From 367c46b11cb19cbe7efcfb24f5c8543fc013fb73 Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Tue, 21 Aug 2018 14:52:13 -0700 Subject: [PATCH] Enable hardware based FBE on f2fs and adapt ext4 fs Hardware File Based Encryption (FBE) uses inline crypto engine to encrypt the user data. 1. security/pfk: changes to support per file encryption for f2fs using hardware crypto engine. 2. fs/ext4: adapted crypto APIs for generic crypto layer. 3. fs/f2fs: support hardware crypto engine based per file encryption. 4. fs/crypto: export APIs to support hardware crypto engine based per file encryption. 5. security/pfe: added wrapped key support based on upstream changes. Other changes made to provide support framework for per file encryption. Reverting commit e02a4e21f640 ("ext4: Add HW File Based Encryption on ext4 file system") and adding changes to have FBE in sync with upstream implementation of FBE. Change-Id: I17f9909c43ba744eb874f6d237745fbf88a2b848 Signed-off-by: Shivaprasad Hongal --- block/bio.c | 9 ++ block/blk-merge.c | 5 +- block/elevator.c | 8 +- drivers/crypto/Kconfig | 1 + drivers/scsi/scsi_lib.c | 2 + drivers/scsi/ufs/ufs-qcom.c | 19 ++- fs/crypto/Makefile | 7 +- fs/crypto/bio.c | 6 +- fs/crypto/ext4_ice.c | 108 --------------- fs/crypto/fscrypt_ice.c | 146 ++++++++++++++++++++ fs/crypto/fscrypt_ice.h | 106 ++++++++++++++ fs/crypto/fscrypt_private.h | 14 +- fs/crypto/keyinfo.c | 164 +++++++++++----------- fs/direct-io.c | 3 +- fs/ext4/Makefile | 1 - fs/ext4/ext4.h | 3 - fs/ext4/ext4_ice.h | 104 -------------- fs/ext4/inode.c | 26 ++-- fs/ext4/ioctl.c | 10 +- fs/ext4/page-io.c | 7 +- fs/ext4/super.c | 6 + fs/f2fs/data.c | 37 ++++- fs/f2fs/f2fs.h | 13 +- fs/f2fs/super.c | 6 + fs/namei.c | 2 - include/linux/bio.h | 8 ++ include/linux/blk_types.h | 10 +- include/linux/blkdev.h | 3 + include/linux/bvec.h | 1 + include/linux/fscrypt.h | 12 +- include/linux/fscrypt_notsupp.h | 15 ++ include/linux/fscrypt_supp.h | 8 ++ include/linux/pfk.h | 16 ++- include/linux/security.h | 4 +- include/scsi/scsi_host.h | 3 + include/uapi/linux/fs.h | 1 + security/Kconfig | 1 - security/Makefile | 4 +- security/pfe/Kconfig | 11 ++ security/pfe/Makefile | 4 +- security/pfe/pfk.c | 176 ++++++++++++++++-------- security/pfe/pfk_ext4.c | 44 ++++-- security/pfe/pfk_f2fs.c | 200 +++++++++++++++++++++++++++ security/pfe/pfk_f2fs.h | 37 +++++ security/pfe/pfk_ice.c | 206 ++++++++++++++++++++++------ security/pfe/pfk_ice.h | 26 ++++ security/pfe/pfk_kc.c | 2 + security/security.c | 2 +- security/selinux/include/objsec.h | 2 +- security/selinux/include/security.h | 1 + 50 files changed, 1136 insertions(+), 474 deletions(-) delete mode 100644 fs/crypto/ext4_ice.c create mode 100644 fs/crypto/fscrypt_ice.c create mode 100644 fs/crypto/fscrypt_ice.h delete mode 100644 fs/ext4/ext4_ice.h create mode 100644 security/pfe/pfk_f2fs.c create mode 100644 security/pfe/pfk_f2fs.h diff --git a/block/bio.c b/block/bio.c index 61975a2bd9e0..6328c6e71b27 100644 --- a/block/bio.c +++ b/block/bio.c @@ -577,6 +577,14 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio) } EXPORT_SYMBOL(bio_phys_segments); +static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src) +{ +#ifdef CONFIG_PFK + dst->bi_crypt_key = src->bi_crypt_key; + dst->bi_iter.bi_dun = src->bi_iter.bi_dun; +#endif +} + /** * __bio_clone_fast - clone a bio that shares the original bio's biovec * @bio: destination bio @@ -606,6 +614,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; bio->bi_dio_inode = bio_src->bi_dio_inode; + bio_clone_crypt_key(bio, bio_src); bio_clone_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); diff --git a/block/blk-merge.c b/block/blk-merge.c index 4f7e70419ba2..e8c45fd4a972 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -7,9 +7,9 @@ #include #include #include -#include -#include +#include +#include #include "blk.h" static struct bio *blk_bio_discard_split(struct request_queue *q, @@ -705,6 +705,7 @@ static struct request *attempt_merge(struct request_queue *q, if (crypto_not_mergeable(req->bio, next->bio)) return 0; + /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn diff --git a/block/elevator.c b/block/elevator.c index 153926a90901..154dc38a03a3 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -436,7 +436,7 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, { struct elevator_queue *e = q->elevator; struct request *__rq; - + enum elv_merge ret; /* * Levels of merges: * nomerges: No merges at all attempted @@ -449,9 +449,11 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req, /* * First try one-hit cache. */ - if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) { - enum elv_merge ret = blk_try_merge(q->last_merge, bio); + if (q->last_merge) { + if (!elv_bio_merge_ok(q->last_merge, bio)) + return ELEVATOR_NO_MERGE; + ret = blk_try_merge(q->last_merge, bio); if (ret != ELEVATOR_NO_MERGE) { *req = q->last_merge; return ret; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 0359f0c484fc..fe89328d3d99 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -773,4 +773,5 @@ config CRYPTO_DEV_ARTPEC6 if ARCH_QCOM source drivers/crypto/msm/Kconfig endif + endif # CRYPTO_HW diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 60345cb4e414..11ff33c1e5c4 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2159,6 +2159,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) if (!shost->use_clustering) q->limits.cluster = 0; + if (shost->inlinecrypt_support) + queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q); /* * Set a reasonable default alignment: The larger of 32-byte (dword), * which is a common minimum for HBAs, and the minimum DMA alignment, diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index fb42b567a1b7..a7430a46da45 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -937,11 +937,18 @@ static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba, req = lrbp->cmd->request; else return 0; - - /* Use request LBA as the DUN value */ - if (req->bio) - *dun = (req->bio->bi_iter.bi_sector) >> - UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + /* + * Right now ICE do not support variable dun but can be + * taken as future enhancement + * if (bio_dun(req->bio)) { + * dun @bio can be split, so we have to adjust offset + * *dun = bio_dun(req->bio); + * } else + */ + if (req->bio) { + *dun = req->bio->bi_iter.bi_sector; + *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; + } ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable); @@ -2180,6 +2187,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) dev_err(dev, "%s: ufs_qcom_ice_get_dev failed %d\n", __func__, err); goto out_variant_clear; + } else { + hba->host->inlinecrypt_support = 1; } host->generic_phy = devm_phy_get(dev, "ufsphy"); diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index e7bee887b605..cc42e5e29472 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o -fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o -fscrypto-$(CONFIG_BLOCK) += bio.o ccflags-y += -Ifs/ext4 -fscrypto-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o +ccflags-y += -Ifs/f2fs + +fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o fscrypt_ice.o +fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index d32a5c69ca38..93cd5e567d07 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -25,7 +25,6 @@ #include #include #include "fscrypt_private.h" -#include "ext4_ice.h" static void __fscrypt_decrypt_bio(struct bio *bio, bool done) { @@ -34,12 +33,11 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - if (ext4_should_be_processed_by_ice(page->mapping->host)) { + if (fscrypt_using_hardware_encryption(page->mapping->host)) { SetPageUptodate(page); } else { int ret = fscrypt_decrypt_page(page->mapping->host, - page, PAGE_SIZE, 0, page->index); - + page, PAGE_SIZE, 0, page->index); if (ret) { WARN_ON_ONCE(1); SetPageError(page); diff --git a/fs/crypto/ext4_ice.c b/fs/crypto/ext4_ice.c deleted file mode 100644 index a8098e338f29..000000000000 --- a/fs/crypto/ext4_ice.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "ext4_ice.h" -#include "fscrypt_private.h" - -/* - * Retrieves encryption key from the inode - */ -char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[0]); -} - -/* - * Retrieves encryption salt from the inode - */ -char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - if (!inode) - return NULL; - - ci = inode->i_crypt_info; - if (!ci) - return NULL; - - return &(ci->ci_raw_key[ext4_get_ice_encryption_key_size(inode)]); -} - -/* - * returns true if the cipher mode in inode is AES XTS - */ -int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - struct fscrypt_info *ci = NULL; - - ci = inode->i_crypt_info; - if (!ci) - return 0; - - return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); -} - -/* - * returns true if encryption info in both inodes is equal - */ -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2) -{ - char *key1 = NULL; - char *key2 = NULL; - char *salt1 = NULL; - char *salt2 = NULL; - - if (!inode1 || !inode2) - return 0; - - if (inode1 == inode2) - return 1; - - /* both do not belong to ice, so we don't care, they are equal for us */ - if (!ext4_should_be_processed_by_ice(inode1) && - !ext4_should_be_processed_by_ice(inode2)) - return 1; - - /* one belongs to ice, the other does not -> not equal */ - if (ext4_should_be_processed_by_ice(inode1) ^ - ext4_should_be_processed_by_ice(inode2)) - return 0; - - key1 = ext4_get_ice_encryption_key(inode1); - key2 = ext4_get_ice_encryption_key(inode2); - salt1 = ext4_get_ice_encryption_salt(inode1); - salt2 = ext4_get_ice_encryption_salt(inode2); - - /* key and salt should not be null by this point */ - if (!key1 || !key2 || !salt1 || !salt2 || - (ext4_get_ice_encryption_key_size(inode1) != - ext4_get_ice_encryption_key_size(inode2)) || - (ext4_get_ice_encryption_salt_size(inode1) != - ext4_get_ice_encryption_salt_size(inode2))) - return 0; - - return ((memcmp(key1, key2, - ext4_get_ice_encryption_key_size(inode1)) == 0) && - (memcmp(salt1, salt2, - ext4_get_ice_encryption_salt_size(inode1)) == 0)); -} diff --git a/fs/crypto/fscrypt_ice.c b/fs/crypto/fscrypt_ice.c new file mode 100644 index 000000000000..62dae83cf732 --- /dev/null +++ b/fs/crypto/fscrypt_ice.c @@ -0,0 +1,146 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fscrypt_ice.h" + +int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + return S_ISREG(inode->i_mode) && ci && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; +} +EXPORT_SYMBOL(fscrypt_using_hardware_encryption); + +/* + * Retrieves encryption key from the inode + */ +char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[0]); +} + +/* + * Retrieves encryption salt from the inode + */ +char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + struct fscrypt_info *ci = NULL; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[fscrypt_get_ice_encryption_key_size(inode)]); +} + +/* + * returns true if the cipher mode in inode is AES XTS + */ +int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + struct fscrypt_info *ci = inode->i_crypt_info; + + if (!ci) + return 0; + + return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); +} + +/* + * returns true if encryption info in both inodes is equal + */ +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2) +{ + char *key1 = NULL; + char *key2 = NULL; + char *salt1 = NULL; + char *salt2 = NULL; + + if (!inode1 || !inode2) + return false; + + if (inode1 == inode2) + return true; + + /* both do not belong to ice, so we don't care, they are equal + *for us + */ + if (!fscrypt_should_be_processed_by_ice(inode1) && + !fscrypt_should_be_processed_by_ice(inode2)) + return true; + + /* one belongs to ice, the other does not -> not equal */ + if (fscrypt_should_be_processed_by_ice(inode1) ^ + fscrypt_should_be_processed_by_ice(inode2)) + return false; + + key1 = fscrypt_get_ice_encryption_key(inode1); + key2 = fscrypt_get_ice_encryption_key(inode2); + salt1 = fscrypt_get_ice_encryption_salt(inode1); + salt2 = fscrypt_get_ice_encryption_salt(inode2); + + /* key and salt should not be null by this point */ + if (!key1 || !key2 || !salt1 || !salt2 || + (fscrypt_get_ice_encryption_key_size(inode1) != + fscrypt_get_ice_encryption_key_size(inode2)) || + (fscrypt_get_ice_encryption_salt_size(inode1) != + fscrypt_get_ice_encryption_salt_size(inode2))) + return false; + + if ((memcmp(key1, key2, + fscrypt_get_ice_encryption_key_size(inode1)) == 0) && + (memcmp(salt1, salt2, + fscrypt_get_ice_encryption_salt_size(inode1)) == 0)) + return true; + + return false; +} + +void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun) +{ + if (fscrypt_should_be_processed_by_ice(inode)) + bio->bi_iter.bi_dun = dun; +} +EXPORT_SYMBOL(fscrypt_set_ice_dun); + +/* + * This function will be used for filesystem when deciding to merge bios. + * Basic assumption is, if inline_encryption is set, single bio has to + * guarantee consecutive LBAs as well as ino|pg->index. + */ +bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted) +{ + if (!bio) + return true; + + /* if both of them are not encrypted, no further check is needed */ + if (!bio_dun(bio) && !bio_encrypted) + return true; + + /* ICE allows only consecutive iv_key stream. */ + return bio_end_dun(bio) == dun; +} +EXPORT_SYMBOL(fscrypt_mergeable_bio); diff --git a/fs/crypto/fscrypt_ice.h b/fs/crypto/fscrypt_ice.h new file mode 100644 index 000000000000..38e8ba69f3c2 --- /dev/null +++ b/fs/crypto/fscrypt_ice.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _FSCRYPT_ICE_H +#define _FSCRYPT_ICE_H + +#include +#include "fscrypt_private.h" + +#if IS_ENABLED(CONFIG_FS_ENCRYPTION) +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + if (!inode->i_sb->s_cop) + return 0; + if (!inode->i_sb->s_cop->is_encrypted((struct inode *)inode)) + return 0; + + return fscrypt_using_hardware_encryption(inode); +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return blk_queue_inlinecrypt(bdev_get_queue(sb->s_bdev)); +} + +int fscrypt_is_aes_xts_cipher(const struct inode *inode); + +char *fscrypt_get_ice_encryption_key(const struct inode *inode); +char *fscrypt_get_ice_encryption_salt(const struct inode *inode); + +bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1, + const struct inode *inode2); + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return FS_AES_256_XTS_KEY_SIZE / 2; +} +#else +static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_ice_capable(const struct super_block *sb) +{ + return 0; +} + +static inline char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + return NULL; +} + +static inline char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + return NULL; +} + +static inline size_t fscrypt_get_ice_encryption_key_size( + const struct inode *inode) +{ + return 0; +} + +static inline size_t fscrypt_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return 0; +} + +static inline int fscrypt_is_xts_cipher(const struct inode *inode) +{ + return 0; +} + +static inline bool fscrypt_is_ice_encryption_info_equal( + const struct inode *inode1, + const struct inode *inode2) +{ + return 0; +} + +static inline int fscrypt_is_aes_xts_cipher(const struct inode *inode) +{ + return 0; +} + +#endif + +#endif /* _FSCRYPT_ICE_H */ diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index c9ca9e79411d..ca6e75a5cb37 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -17,6 +17,7 @@ #endif #include #include +#include /* Encryption parameters */ #define FS_IV_SIZE 16 @@ -61,11 +62,18 @@ struct fscrypt_symlink_data { char encrypted_path[1]; } __packed; +enum ci_mode_info { + CI_NONE_MODE = 0, + CI_DATA_MODE, + CI_FNAME_MODE, +}; + /* * A pointer to this structure is stored in the file system's in-core * representation of an inode. */ struct fscrypt_info { + u8 ci_mode; u8 ci_data_mode; u8 ci_filename_mode; u8 ci_flags; @@ -105,12 +113,12 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, return false; } -static inline bool is_private_mode(struct fscrypt_info *ci) +static inline bool is_private_data_mode(struct fscrypt_info *ci) { - return ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; + return ci->ci_mode == CI_DATA_MODE && + ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; } - /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 27edc5b9eb66..737af4b41f71 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -16,7 +16,7 @@ #include #include #include "fscrypt_private.h" -#include "ext4_ice.h" +#include "fscrypt_ice.h" static struct crypto_shash *essiv_hash_tfm; @@ -69,7 +69,7 @@ out: } static int validate_user_key(struct fscrypt_info *crypt_info, - struct fscrypt_context *ctx, u8 *raw_key, + struct fscrypt_context *ctx, const char *prefix, int min_keysize) { char *description; @@ -117,21 +117,20 @@ static int validate_user_key(struct fscrypt_info *crypt_info, res = -ENOKEY; goto out; } - /* - * If we don't need to derive, we still want to do everything + res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key); + /* If we don't need to derive, we still want to do everything * up until now to validate the key. It's cleaner to fail now * than to fail in block I/O. */ - if (!is_private_mode(crypt_info)) { + if (!is_private_data_mode(crypt_info)) { res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key); } else { - /* - * Inline encryption: no key derivation required because IVs are + /* Inline encryption: no key derivation required because IVs are * assigned based on iv_sector. */ - if (sizeof(crypt_info->ci_raw_key) != sizeof(master_key->raw)) - goto out; + BUILD_BUG_ON(sizeof(crypt_info->ci_raw_key) != + sizeof(master_key->raw)); memcpy(crypt_info->ci_raw_key, master_key->raw, sizeof(crypt_info->ci_raw_key)); res = 0; @@ -156,42 +155,37 @@ static const struct { FS_AES_128_CTS_KEY_SIZE }, [FS_ENCRYPTION_MODE_SPECK128_256_XTS] = { "xts(speck128)", 64 }, [FS_ENCRYPTION_MODE_SPECK128_256_CTS] = { "cts(cbc(speck128))", 32 }, - [FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", FS_AES_256_XTS_KEY_SIZE }, + [FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", + FS_AES_256_XTS_KEY_SIZE }, }; static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, - const char **cipher_str_ret, int *keysize_ret, int *fname) + const char **cipher_str_ret, int *keysize_ret) { + u32 mode; + + if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) { + pr_warn_ratelimited("fscrypt: inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)\n", + inode->i_ino, + ci->ci_data_mode, ci->ci_filename_mode); + return -EINVAL; + } + if (S_ISREG(inode->i_mode)) { - if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) { - *cipher_str_ret = "xts(aes)"; - *keysize_ret = FS_AES_256_XTS_KEY_SIZE; - return 0; - } else if (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE) { - *cipher_str_ret = "bugon"; - *keysize_ret = FS_AES_256_XTS_KEY_SIZE; - return 0; - } - pr_warn_once("fscrypto: unsupported contents encryption mode %d for inode %lu\n", - ci->ci_data_mode, inode->i_ino); - return -ENOKEY; + ci->ci_mode = CI_DATA_MODE; + mode = ci->ci_data_mode; + } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { + ci->ci_mode = CI_FNAME_MODE; + mode = ci->ci_filename_mode; + } else { + WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n", + inode->i_ino, (inode->i_mode & S_IFMT)); + return -EINVAL; } - if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { - if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) { - *cipher_str_ret = "cts(cbc(aes))"; - *keysize_ret = FS_AES_256_CTS_KEY_SIZE; - *fname = 1; - return 0; - } - pr_warn_once("fscrypto: unsupported filenames encryption mode %d for inode %lu\n", - ci->ci_filename_mode, inode->i_ino); - return -ENOKEY; - } - - pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n", - (inode->i_mode & S_IFMT), inode->i_ino); - return -ENOKEY; + *cipher_str_ret = available_modes[mode].cipher_str; + *keysize_ret = available_modes[mode].keysize; + return 0; } static void put_crypt_info(struct fscrypt_info *ci) @@ -201,6 +195,7 @@ static void put_crypt_info(struct fscrypt_info *ci) crypto_free_skcipher(ci->ci_ctfm); crypto_free_cipher(ci->ci_essiv_tfm); + memset(ci, 0, sizeof(*ci)); /* sanitizes ->ci_raw_key */ kmem_cache_free(fscrypt_info_cachep, ci); } @@ -271,21 +266,12 @@ void __exit fscrypt_essiv_cleanup(void) crypto_free_shash(essiv_hash_tfm); } -static int fs_data_encryption_mode(void) +static int fscrypt_data_encryption_mode(struct inode *inode) { - return ext4_is_ice_enabled() ? FS_ENCRYPTION_MODE_PRIVATE : - FS_ENCRYPTION_MODE_AES_256_XTS; + return fscrypt_should_be_processed_by_ice(inode) ? + FS_ENCRYPTION_MODE_PRIVATE : FS_ENCRYPTION_MODE_AES_256_XTS; } -int fs_using_hardware_encryption(struct inode *inode) -{ - struct fscrypt_info *ci = inode->i_crypt_info; - - return S_ISREG(inode->i_mode) && ci && - ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE; -} -EXPORT_SYMBOL(fs_using_hardware_encryption); - int fscrypt_get_encryption_info(struct inode *inode) { struct fscrypt_info *crypt_info; @@ -293,8 +279,8 @@ int fscrypt_get_encryption_info(struct inode *inode) struct crypto_skcipher *ctfm; const char *cipher_str; int keysize; + u8 *raw_key = NULL; int res; - int fname = 0; if (inode->i_crypt_info) return 0; @@ -311,7 +297,8 @@ int fscrypt_get_encryption_info(struct inode *inode) /* Fake up a context for an unencrypted directory */ memset(&ctx, 0, sizeof(ctx)); ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1; - ctx.contents_encryption_mode = fs_data_encryption_mode(); + ctx.contents_encryption_mode = + fscrypt_data_encryption_mode(inode); ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS; memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE); } else if (res != sizeof(ctx)) { @@ -336,8 +323,7 @@ int fscrypt_get_encryption_info(struct inode *inode) memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor, sizeof(crypt_info->ci_master_key)); - res = determine_cipher_type(crypt_info, inode, &cipher_str, - &keysize, &fname); + res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize); if (res) goto out; @@ -346,17 +332,16 @@ int fscrypt_get_encryption_info(struct inode *inode) * crypto API as part of key derivation. */ res = -ENOMEM; + raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS); + if (!raw_key) + goto out; - if (fscrypt_dummy_context_enabled(inode)) { - memset(crypt_info->ci_raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE); - goto got_key; - } - res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key, - FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE); + res = validate_user_key(crypt_info, &ctx, FS_KEY_DESC_PREFIX, + keysize); if (res && inode->i_sb->s_cop->key_prefix) { int res2 = validate_user_key(crypt_info, &ctx, - crypt_info->ci_raw_key, - inode->i_sb->s_cop->key_prefix, keysize); + inode->i_sb->s_cop->key_prefix, + keysize); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; @@ -366,42 +351,57 @@ int fscrypt_get_encryption_info(struct inode *inode) } else if (res) { goto out; } -got_key: - if (crypt_info->ci_data_mode != FS_ENCRYPTION_MODE_PRIVATE || fname) { - ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); - if (!ctfm || IS_ERR(ctfm)) { - res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; - pr_err("%s: error %d inode %u allocating crypto tfm\n", - __func__, res, (unsigned int) inode->i_ino); + + if (is_private_data_mode(crypt_info)) { + if (!fscrypt_is_ice_capable(inode->i_sb)) { + pr_warn("%s: ICE support not available\n", + __func__); + res = -EINVAL; goto out; } - crypt_info->ci_ctfm = ctfm; - crypto_skcipher_clear_flags(ctfm, ~0); - crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); - /* - * if the provided key is longer than keysize, we use the first - * keysize bytes of the derived key only - */ - res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, - keysize); - if (res) - goto out; - } else if (S_ISREG(inode->i_mode) && + /* Let's encrypt/decrypt by ICE */ + goto do_ice; + } + + + ctfm = crypto_alloc_skcipher(cipher_str, 0, 0); + if (!ctfm || IS_ERR(ctfm)) { + res = ctfm ? PTR_ERR(ctfm) : -ENOMEM; + pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n", + __func__, res, inode->i_ino); + goto out; + } + crypt_info->ci_ctfm = ctfm; + crypto_skcipher_clear_flags(ctfm, ~0); + crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY); + /* + * if the provided key is longer than keysize, we use the first + * keysize bytes of the derived key only + */ + res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, keysize); + if (res) + goto out; + + if (S_ISREG(inode->i_mode) && crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) { res = init_essiv_generator(crypt_info, crypt_info->ci_raw_key, - keysize); + keysize); if (res) { pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", __func__, res, inode->i_ino); goto out; } } + memzero_explicit(crypt_info->ci_raw_key, + sizeof(crypt_info->ci_raw_key)); +do_ice: if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) crypt_info = NULL; out: if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); + kzfree(raw_key); return res; } EXPORT_SYMBOL(fscrypt_get_encryption_info); diff --git a/fs/direct-io.c b/fs/direct-io.c index 96a103249a0b..c03813a80a34 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -473,10 +473,9 @@ struct inode *dio_bio_get_inode(struct bio *bio) return NULL; inode = bio->bi_dio_inode; - return inode; } -EXPORT_SYMBOL(dio_bio_get_inode); + /* * Release any resources in case of a failure */ diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 7cf69c14f796..8fdfcd3c3e04 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -2,7 +2,6 @@ # # Makefile for the linux ext4-filesystem routines. # -ccflags-y += -Ifs/crypto obj-$(CONFIG_EXT4_FS) += ext4.o diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 2dd8c7e0f298..69e83cf4c699 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -40,9 +40,7 @@ #include #endif -#ifndef __FS_HAS_ENCRYPTION #define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION) -#endif #include /* @@ -2352,7 +2350,6 @@ static inline int ext4_fname_setup_filename(struct inode *dir, } static inline void ext4_fname_free_filename(struct ext4_filename *fname) { } -#define fscrypt_set_d_op(i) #endif /* dir.c */ diff --git a/fs/ext4/ext4_ice.h b/fs/ext4/ext4_ice.h deleted file mode 100644 index b0149dd7bad4..000000000000 --- a/fs/ext4/ext4_ice.h +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _EXT4_ICE_H -#define _EXT4_ICE_H - -#include "ext4.h" -#include - -#ifdef CONFIG_EXT4_FS_ICE_ENCRYPTION -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - if (!ext4_encrypted_inode((struct inode *)inode)) - return 0; - - return fs_using_hardware_encryption((struct inode *)inode); -} - -static inline int ext4_is_ice_enabled(void) -{ - return 1; -} - -int ext4_is_aes_xts_cipher(const struct inode *inode); - -char *ext4_get_ice_encryption_key(const struct inode *inode); -char *ext4_get_ice_encryption_salt(const struct inode *inode); - -int ext4_is_ice_encryption_info_equal(const struct inode *inode1, - const struct inode *inode2); - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return FS_AES_256_XTS_KEY_SIZE / 2; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return FS_AES_256_XTS_KEY_SIZE / 2; -} - -#else -static inline int ext4_should_be_processed_by_ice(const struct inode *inode) -{ - return 0; -} -static inline int ext4_is_ice_enabled(void) -{ - return 0; -} - -static inline char *ext4_get_ice_encryption_key(const struct inode *inode) -{ - return NULL; -} - -static inline char *ext4_get_ice_encryption_salt(const struct inode *inode) -{ - return NULL; -} - -static inline size_t ext4_get_ice_encryption_key_size( - const struct inode *inode) -{ - return 0; -} - -static inline size_t ext4_get_ice_encryption_salt_size( - const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_xts_cipher(const struct inode *inode) -{ - return 0; -} - -static inline int ext4_is_ice_encryption_info_equal( - const struct inode *inode1, - const struct inode *inode2) -{ - return 0; -} - -static inline int ext4_is_aes_xts_cipher(const struct inode *inode) -{ - return 0; -} - -#endif - -#endif /* _EXT4_ICE_H */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2764b4d1ce32..7e777ea24614 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -44,7 +44,6 @@ #include "xattr.h" #include "acl.h" #include "truncate.h" -#include "ext4_ice.h" #include #include @@ -1220,7 +1219,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) && - !ext4_should_be_processed_by_ice(inode); + !fscrypt_using_hardware_encryption(inode); } } /* @@ -3716,15 +3715,14 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) get_block_func = ext4_dio_get_block_unwritten_async; dio_flags = DIO_LOCKING; } - -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) - return 0; +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + WARN_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)); #endif - ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, - get_block_func, ext4_end_io_dio, NULL, - dio_flags); + ret = __blockdev_direct_IO(iocb, inode, + inode->i_sb->s_bdev, iter, + get_block_func, + ext4_end_io_dio, NULL, dio_flags); if (ret > 0 && !overwrite && ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN)) { @@ -3830,9 +3828,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ -!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) +#if defined(CONFIG_EXT4_FS_ENCRYPTION) + if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) + && !fscrypt_using_hardware_encryption(inode)) return 0; #endif @@ -4042,7 +4040,7 @@ static int __ext4_block_zero_page_range(handle_t *handle, goto unlock; if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode) && - !ext4_should_be_processed_by_ice(inode)) { + !fscrypt_using_hardware_encryption(inode)) { /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(blocksize != PAGE_SIZE); diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 53bd5d893a58..1eb68e626931 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -939,13 +939,11 @@ resizefs_out: case EXT4_IOC_PRECACHE_EXTENTS: return ext4_ext_precache(inode); - case EXT4_IOC_SET_ENCRYPTION_POLICY: { -#ifdef CONFIG_EXT4_FS_ENCRYPTION + case EXT4_IOC_SET_ENCRYPTION_POLICY: + if (!ext4_has_feature_encrypt(sb)) + return -EOPNOTSUPP; return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); -#else - return -EOPNOTSUPP; -#endif - } + case EXT4_IOC_GET_ENCRYPTION_PWSALT: { #ifdef CONFIG_EXT4_FS_ENCRYPTION int err, err2; diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index bc475426f0c3..11566757db26 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -29,7 +29,6 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" -#include "ext4_ice.h" static struct kmem_cache *io_end_cachep; @@ -483,9 +482,9 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: - if (!ext4_should_be_processed_by_ice(inode)) - data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, - 0, page->index, gfp_flags); + if (!fscrypt_using_hardware_encryption(inode)) + data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, + page->index, gfp_flags); if (IS_ERR(data_page)) { ret = PTR_ERR(data_page); if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) { diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 84a038a6f604..491d09a1f7bf 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1235,6 +1235,11 @@ static unsigned ext4_max_namelen(struct inode *inode) EXT4_NAME_LEN; } +static inline bool ext4_is_encrypted(struct inode *inode) +{ + return ext4_encrypted_inode(inode); +} + static const struct fscrypt_operations ext4_cryptops = { .key_prefix = "ext4:", .get_context = ext4_get_context, @@ -1242,6 +1247,7 @@ static const struct fscrypt_operations ext4_cryptops = { .dummy_context = ext4_dummy_context, .empty_dir = ext4_empty_dir, .max_namelen = ext4_max_namelen, + .is_encrypted = ext4_is_encrypted, }; #endif diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c9db73e498a6..39dc4810ea5f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -439,6 +439,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) struct bio *bio; struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; + struct inode *inode = fio->page->mapping->host; verify_block_addr(fio, fio->new_blkaddr); trace_f2fs_submit_page_bio(page, fio); @@ -448,6 +449,9 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc, 1, is_read_io(fio->op), fio->type, fio->temp); + if (f2fs_may_encrypt_bio(inode, fio)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, fio->page)); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -467,6 +471,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; struct page *bio_page; + struct inode *inode; + bool bio_encrypted; + u64 dun; int err = 0; f2fs_bug_on(sbi, is_read_io(fio->op)); @@ -490,6 +497,9 @@ next: verify_block_addr(fio, fio->new_blkaddr); bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; + inode = fio->page->mapping->host; + dun = PG_DUN(inode, fio->page); + bio_encrypted = f2fs_may_encrypt_bio(inode, fio); /* set submitted = true as a return value */ fio->submitted = true; @@ -500,6 +510,11 @@ next: (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) || !__same_bdev(sbi, fio->new_blkaddr, io->bio))) __submit_merged_bio(io); + + /* ICE support */ + if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted)) + __submit_merged_bio(io); + alloc_new: if (io->bio == NULL) { if ((fio->type == DATA || fio->type == NODE) && @@ -511,6 +526,9 @@ alloc_new: io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc, BIO_MAX_PAGES, false, fio->type, fio->temp); + if (bio_encrypted) + fscrypt_set_ice_dun(inode, io->bio, dun); + io->fio = *fio; } @@ -577,6 +595,9 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, if (IS_ERR(bio)) return PTR_ERR(bio); + if (f2fs_may_encrypt_bio(inode, NULL)) + fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, page)); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); return -EFAULT; @@ -1436,6 +1457,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping, sector_t last_block_in_file; sector_t block_nr; struct f2fs_map_blocks map; + bool bio_encrypted; + u64 dun; map.m_pblk = 0; map.m_lblk = 0; @@ -1513,6 +1536,14 @@ submit_and_realloc: __submit_bio(F2FS_I_SB(inode), bio, DATA); bio = NULL; } + + dun = PG_DUN(inode, page); + bio_encrypted = f2fs_may_encrypt_bio(inode, NULL); + if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted)) { + __submit_bio(F2FS_I_SB(inode), bio, DATA); + bio = NULL; + } + if (bio == NULL) { bio = f2fs_grab_read_bio(inode, block_nr, nr_pages); if (IS_ERR(bio)) { @@ -1520,7 +1551,8 @@ submit_and_realloc: goto set_error_page; } } - + if (bio_encrypted) + fscrypt_set_ice_dun(inode, bio, dun); if (bio_add_page(bio, page, blocksize, 0) < blocksize) goto submit_and_realloc; @@ -1590,6 +1622,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio) f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr); retry_encrypt: + if (fscrypt_using_hardware_encryption(inode)) + return 0; + fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, PAGE_SIZE, 0, fio->page->index, gfp_flags); if (!IS_ERR(fio->encrypted_page)) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index bc633925d7b7..5895204c39d1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3279,9 +3279,20 @@ static inline bool f2fs_may_encrypt(struct inode *inode) static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) { - return (f2fs_post_read_required(inode) || + return ((f2fs_post_read_required(inode) && + !fscrypt_using_hardware_encryption(inode)) || (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || F2FS_I_SB(inode)->s_ndevs); } +static inline bool f2fs_may_encrypt_bio(struct inode *inode, + struct f2fs_io_info *fio) +{ + if (fio && (fio->type != DATA || fio->encrypted_page)) + return false; + + return (f2fs_encrypted_file(inode) && + fscrypt_using_hardware_encryption(inode)); +} + #endif diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2b79c1a7a2f2..a26bd6dda9b4 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1940,6 +1940,11 @@ static unsigned f2fs_max_namelen(struct inode *inode) inode->i_sb->s_blocksize : F2FS_NAME_LEN; } +static inline bool f2fs_is_encrypted(struct inode *inode) +{ + return f2fs_encrypted_file(inode); +} + static const struct fscrypt_operations f2fs_cryptops = { .key_prefix = "f2fs:", .get_context = f2fs_get_context, @@ -1947,6 +1952,7 @@ static const struct fscrypt_operations f2fs_cryptops = { .dummy_context = f2fs_dummy_context, .empty_dir = f2fs_empty_dir, .max_namelen = f2fs_max_namelen, + .is_encrypted = f2fs_is_encrypted, }; #endif diff --git a/fs/namei.c b/fs/namei.c index 055c6c40901b..d3650e50a6ed 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3742,11 +3742,9 @@ int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, u error = dir->i_op->mknod(dir, dentry, mode, dev); if (error) return error; - error = security_inode_post_create(dir, dentry, mode); if (error) return error; - if (!error) fsnotify_create(dir, dentry); return error; diff --git a/include/linux/bio.h b/include/linux/bio.h index 5aa40f4712ff..8988ccdb10c8 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -69,6 +69,9 @@ ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) +#define bio_dun(bio) ((bio)->bi_iter.bi_dun) +#define bio_duns(bio) (bio_sectors(bio) >> 3) /* 4KB unit */ +#define bio_end_dun(bio) (bio_dun(bio) + bio_duns(bio)) /* * Return the data direction, READ or WRITE. @@ -173,6 +176,11 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, { iter->bi_sector += bytes >> 9; +#ifdef CONFIG_PFK + if (iter->bi_dun) + iter->bi_dun += bytes >> 12; +#endif + if (bio_no_advance_iter(bio)) { iter->bi_size -= bytes; iter->bi_done += bytes; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index be2bee81c748..ba4b484c0008 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -100,6 +100,10 @@ struct bio { struct bio_integrity_payload *bi_integrity; /* data integrity */ #endif }; +#ifdef CONFIG_PFK + /* Encryption key to use (NULL if none) */ + const struct blk_encryption_key *bi_crypt_key; +#endif unsigned short bi_vcnt; /* how many bio_vec's */ @@ -115,12 +119,8 @@ struct bio { struct bio_set *bi_pool; - /* - * When using dircet-io (O_DIRECT), we can't get the inode from a bio - * by walking bio->bi_io_vec->bv_page->mapping->host - * since the page is anon. - */ struct inode *bi_dio_inode; + /* * We can inline a number of vecs at the end of the bio, to avoid * double allocations for a small number of bio_vecs. This member diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 64ac8e3c5a40..c3a488f8b2e1 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -652,6 +652,7 @@ struct request_queue { #define QUEUE_FLAG_REGISTERED 26 /* queue has been registered to a disk */ #define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */ #define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */ +#define QUEUE_FLAG_INLINECRYPT 29 /* inline encryption support */ #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ @@ -751,6 +752,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) #define blk_queue_scsi_passthrough(q) \ test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(q)->queue_flags) +#define blk_queue_inlinecrypt(q) \ + test_bit(QUEUE_FLAG_INLINECRYPT, &(q)->queue_flags) #define blk_noretry_request(rq) \ ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ diff --git a/include/linux/bvec.h b/include/linux/bvec.h index ec8a4d7af6bd..41d309fda777 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -44,6 +44,7 @@ struct bvec_iter { unsigned int bi_bvec_done; /* number of bytes completed in current bvec */ + u64 bi_dun; /* DUN setting for bio */ }; /* diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 2a3957bc2221..129b948bee5a 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -17,10 +17,16 @@ #include #define FS_CRYPTO_BLOCK_SIZE 16 -#define FS_ENCRYPTION_MODE_PRIVATE 127 -#define FS_AES_256_XTS_KEY_SIZE 64 struct fscrypt_ctx; + +/* iv sector for security/pfe/pfk_fscrypt.c and f2fs. sizeof is required + * to accommodate 32 bit targets. + */ +#define PG_DUN(i, p) \ + ((((i)->i_ino & 0xffffffff) << (sizeof((i)->i_ino)/2)) | \ + ((p)->index & 0xffffffff)) + struct fscrypt_info; struct fscrypt_str { @@ -44,8 +50,6 @@ struct fscrypt_name { /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 28 -extern int fs_using_hardware_encryption(struct inode *inode); - #if __FS_HAS_ENCRYPTION #include #else diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 9770be37c9d4..07f6b63f4240 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -184,6 +184,21 @@ static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, return -EOPNOTSUPP; } +/* fscrypt_ice.c */ +static inline int fscrypt_using_hardware_encryption(const struct inode *inode) +{ + return 0; +} + +static inline void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun){} + +static inline bool fscrypt_mergeable_bio(struct bio *bio, + sector_t iv_block, bool bio_encrypted) +{ + return true; +} + /* hooks.c */ static inline int fscrypt_file_open(struct inode *inode, struct file *filp) diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 2c9a86ac5e83..483de436fbb6 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -30,6 +30,7 @@ struct fscrypt_operations { bool (*dummy_context)(struct inode *); bool (*empty_dir)(struct inode *); unsigned (*max_namelen)(struct inode *); + bool (*is_encrypted)(struct inode *); }; struct fscrypt_ctx { @@ -196,6 +197,13 @@ extern void fscrypt_pullback_bio_page(struct page **, bool); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); +/* fscrypt_ice.c */ +extern int fscrypt_using_hardware_encryption(const struct inode *inode); +extern void fscrypt_set_ice_dun(const struct inode *inode, + struct bio *bio, u64 dun); +extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted); + + /* hooks.c */ extern int fscrypt_file_open(struct inode *inode, struct file *filp); extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir); diff --git a/include/linux/pfk.h b/include/linux/pfk.h index 3c7a389fd4d4..8cc20edb6802 100644 --- a/include/linux/pfk.h +++ b/include/linux/pfk.h @@ -19,8 +19,22 @@ struct ice_crypto_setting; #ifdef CONFIG_PFK +/* + * Default key for inline encryption. + * + * For now only AES-256-XTS is supported, so this is a fixed length. But if + * ever needed, this should be made variable-length with a 'mode' and 'size'. + * (Remember to update pfk_allow_merge_bio() when doing so!) + */ +#define BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS 64 + +struct blk_encryption_key { + u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS]; +}; + int pfk_load_key_start(const struct bio *bio, - struct ice_crypto_setting *ice_setting, bool *is_pfe, bool); + struct ice_crypto_setting *ice_setting, + bool *is_pfe, bool async); int pfk_load_key_end(const struct bio *bio, bool *is_pfe); int pfk_remove_key(const unsigned char *key, size_t key_size); bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2); diff --git a/include/linux/security.h b/include/linux/security.h index 30fb23a4ca81..0cd947e5fb00 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -668,8 +668,8 @@ static inline int security_inode_create(struct inode *dir, } static inline int security_inode_post_create(struct inode *dir, - struct dentry *dentry, - umode_t mode) + struct dentry *dentry, + umode_t mode) { return 0; } diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 00f18dd00372..8fd4cda282c3 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -663,6 +663,9 @@ struct Scsi_Host { /* The controller does not support WRITE SAME */ unsigned no_write_same:1; + /* Inline encryption support? */ + unsigned inlinecrypt_support:1; + unsigned use_blk_mq:1; unsigned use_cmd_list:1; diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 971e82aec6d0..5bf4dcb38013 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -277,6 +277,7 @@ struct fsxattr { #define FS_ENCRYPTION_MODE_AES_128_CTS 6 #define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 #define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 +#define FS_ENCRYPTION_MODE_PRIVATE 127 struct fscrypt_policy { __u8 version; diff --git a/security/Kconfig b/security/Kconfig index 87d8bb2df7c8..1996a6bace8a 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -10,7 +10,6 @@ if ARCH_QCOM source security/pfe/Kconfig endif - config SECURITY_DMESG_RESTRICT bool "Restrict unprivileged access to the kernel syslog" default n diff --git a/security/Makefile b/security/Makefile index f15945d3800b..47bffaa3f5f8 100644 --- a/security/Makefile +++ b/security/Makefile @@ -10,7 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin -subdir-$(CONFIG_ARCH_QCOM) += pfe +subdir-$(CONFIG_ARCH_QCOM) += pfe # always enable default capabilities obj-y += commoncap.o @@ -26,8 +26,8 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ -obj-$(CONFIG_ARCH_QCOM) += pfe/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o +obj-$(CONFIG_ARCH_QCOM) += pfe/ # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig index 0cd9e81a4952..45640adf8101 100644 --- a/security/pfe/Kconfig +++ b/security/pfe/Kconfig @@ -25,4 +25,15 @@ config PFK Information is used when file is encrypted later using ICE or dm crypto engine +config PFK_WRAPPED_KEY_SUPPORTED + bool "Per-File-Key driver with wrapped key support" + depends on SECURITY + depends on SECURITY_SELINUX + depends on QSEECOM + depends on PFK + default n + help + Adds wrapped key support in PFK driver. Instead of setting + the key directly in ICE, it unwraps the key and sets the key + in ICE. endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile index 242a2165fccb..2507557837db 100644 --- a/security/pfe/Makefile +++ b/security/pfe/Makefile @@ -3,8 +3,8 @@ # ccflags-y += -Isecurity/selinux -Isecurity/selinux/include -ccflags-y += -Ifs/ext4 ccflags-y += -Ifs/crypto +ccflags-y += -Idrivers/misc obj-$(CONFIG_PFT) += pft.o -obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o +obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o pfk_f2fs.o diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c index b38cd5c4b05d..27a2ede61946 100644 --- a/security/pfe/pfk.c +++ b/security/pfe/pfk.c @@ -37,6 +37,9 @@ * */ + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ #define pr_fmt(fmt) "pfk [%s]: " fmt, __func__ #include @@ -45,24 +48,27 @@ #include #include #include -#include +#include #include -#include "ext4.h" -#include "objsec.h" +#include + #include "pfk_kc.h" +#include "objsec.h" #include "pfk_ice.h" #include "pfk_ext4.h" +#include "pfk_f2fs.h" #include "pfk_internal.h" static bool pfk_ready; + /* might be replaced by a table when more than one cipher is supported */ #define PFK_SUPPORTED_KEY_SIZE 32 #define PFK_SUPPORTED_SALT_SIZE 32 /* Various PFE types and function tables to support each one of them */ -enum pfe_type {EXT4_CRYPT_PFE, INVALID_PFE}; +enum pfe_type {EXT4_CRYPT_PFE, F2FS_CRYPT_PFE, INVALID_PFE}; typedef int (*pfk_parse_inode_type)(const struct bio *bio, const struct inode *inode, @@ -76,31 +82,40 @@ typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1, static const pfk_parse_inode_type pfk_parse_inode_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_parse_inode, }; static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = { /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio, + /* F2FS_CRYPT_PFE */ &pfk_f2fs_allow_merge_bio, }; static void __exit pfk_exit(void) { pfk_ready = false; pfk_ext4_deinit(); + pfk_f2fs_deinit(); pfk_kc_deinit(); } static int __init pfk_init(void) { + int ret = 0; ret = pfk_ext4_init(); if (ret != 0) goto fail; + ret = pfk_f2fs_init(); + if (ret != 0) + goto fail; + ret = pfk_kc_init(); if (ret != 0) { pr_err("could init pfk key cache, error %d\n", ret); pfk_ext4_deinit(); + pfk_f2fs_deinit(); goto fail; } @@ -126,6 +141,9 @@ static enum pfe_type pfk_get_pfe_type(const struct inode *inode) if (pfk_is_ext4_type(inode)) return EXT4_CRYPT_PFE; + if (pfk_is_f2fs_type(inode)) + return F2FS_CRYPT_PFE; + return INVALID_PFE; } @@ -142,6 +160,9 @@ char *inode_to_filename(const struct inode *inode) struct dentry *dentry = NULL; char *filename = NULL; + if (!inode) + return "NULL"; + if (hlist_empty(&inode->i_dentry)) return "unknown"; @@ -176,30 +197,30 @@ static inline bool pfk_is_ready(void) */ static struct inode *pfk_bio_get_inode(const struct bio *bio) { - struct address_space *mapping; - if (!bio) return NULL; + if (!bio_has_data((struct bio *)bio)) + return NULL; if (!bio->bi_io_vec) return NULL; if (!bio->bi_io_vec->bv_page) return NULL; - if (!bio_has_data((struct bio *)bio)) - return NULL; if (PageAnon(bio->bi_io_vec->bv_page)) { struct inode *inode; + /* Using direct-io (O_DIRECT) without page cache */ inode = dio_bio_get_inode((struct bio *)bio); pr_debug("inode on direct-io, inode = 0x%pK.\n", inode); + return inode; } - mapping = page_mapping(bio->bi_io_vec->bv_page); - if (!mapping) + if (!page_mapping(bio->bi_io_vec->bv_page)) return NULL; - if (!mapping->host) + if (!bio->bi_io_vec->bv_page->mapping->host) + return NULL; return bio->bi_io_vec->bv_page->mapping->host; @@ -250,6 +271,58 @@ bool pfe_is_inode_filesystem_type(const struct inode *inode, return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); } +/** + * pfk_get_key_for_bio() - get the encryption key to be used for a bio + * + * @bio: pointer to the BIO + * @key_info: pointer to the key information which will be filled in + * @algo_mode: optional pointer to the algorithm identifier which will be set + * @is_pfe: will be set to false if the BIO should be left unencrypted + * + * Return: 0 if a key is being used, otherwise a -errno value + */ +static int pfk_get_key_for_bio(const struct bio *bio, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo_mode, + bool *is_pfe) +{ + const struct inode *inode; + enum pfe_type which_pfe; + const struct blk_encryption_key *key; + + inode = pfk_bio_get_inode(bio); + which_pfe = pfk_get_pfe_type(inode); + + if (which_pfe != INVALID_PFE) { + /* Encrypted file; override ->bi_crypt_key */ + pr_debug("parsing inode %lu with PFE type %d\n", + inode->i_ino, which_pfe); + return (*(pfk_parse_inode_ftable[which_pfe])) + (bio, inode, key_info, algo_mode, is_pfe); + } + + /* + * bio is not for an encrypted file. Use ->bi_crypt_key if it was set. + * Otherwise, don't encrypt/decrypt the bio. + */ + key = bio->bi_crypt_key; + if (!key) { + *is_pfe = false; + return -EINVAL; + } + + /* Note: the "salt" is really just the second half of the XTS key. */ + BUILD_BUG_ON(sizeof(key->raw) != + PFK_SUPPORTED_KEY_SIZE + PFK_SUPPORTED_SALT_SIZE); + key_info->key = &key->raw[0]; + key_info->key_size = PFK_SUPPORTED_KEY_SIZE; + key_info->salt = &key->raw[PFK_SUPPORTED_KEY_SIZE]; + key_info->salt_size = PFK_SUPPORTED_SALT_SIZE; + if (algo_mode) + *algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; + return 0; +} + /** * pfk_load_key_start() - loads PFE encryption key to the ICE @@ -279,8 +352,6 @@ int pfk_load_key_start(const struct bio *bio, enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; enum ice_crpto_key_size key_size_type = 0; u32 key_index = 0; - struct inode *inode = NULL; - enum pfe_type which_pfe = INVALID_PFE; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -301,26 +372,16 @@ int pfk_load_key_start(const struct bio *bio, pr_err("ice setting is NULL\n"); return -EINVAL; } - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - pr_debug("parsing file %s with PFE %d\n", - inode_to_filename(inode), which_pfe); - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, &algo_mode, is_pfe); + ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe); + if (ret != 0) return ret; + ret = pfk_key_size_to_key_type(key_info.key_size, &key_size_type); if (ret != 0) return ret; + ret = pfk_kc_load_key_start(key_info.key, key_info.key_size, key_info.salt, key_info.salt_size, &key_index, async); if (ret) { @@ -338,7 +399,7 @@ int pfk_load_key_start(const struct bio *bio, ice_setting->key_index = key_index; pr_debug("loaded key for file %s key_index %d\n", - inode_to_filename(inode), key_index); + inode_to_filename(pfk_bio_get_inode(bio)), key_index); return 0; } @@ -357,9 +418,7 @@ int pfk_load_key_start(const struct bio *bio, int pfk_load_key_end(const struct bio *bio, bool *is_pfe) { int ret = 0; - struct pfk_key_info key_info = {0}; - enum pfe_type which_pfe = INVALID_PFE; - struct inode *inode = NULL; + struct pfk_key_info key_info = {NULL, NULL, 0, 0}; if (!is_pfe) { pr_err("is_pfe is NULL\n"); @@ -375,20 +434,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) if (!pfk_is_ready()) return -ENODEV; - inode = pfk_bio_get_inode(bio); - if (!inode) { - *is_pfe = false; - return -EINVAL; - } - - which_pfe = pfk_get_pfe_type(inode); - if (which_pfe == INVALID_PFE) { - *is_pfe = false; - return -EPERM; - } - - ret = (*(pfk_parse_inode_ftable[which_pfe])) - (bio, inode, &key_info, NULL, is_pfe); + ret = pfk_get_key_for_bio(bio, &key_info, NULL, is_pfe); if (ret != 0) return ret; @@ -396,7 +442,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) key_info.salt, key_info.salt_size); pr_debug("finished using key for file %s\n", - inode_to_filename(inode)); + inode_to_filename(pfk_bio_get_inode(bio))); return 0; } @@ -418,10 +464,12 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe) */ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) { - struct inode *inode1 = NULL; - struct inode *inode2 = NULL; - enum pfe_type which_pfe1 = INVALID_PFE; - enum pfe_type which_pfe2 = INVALID_PFE; + const struct blk_encryption_key *key1; + const struct blk_encryption_key *key2; + const struct inode *inode1; + const struct inode *inode2; + enum pfe_type which_pfe1; + enum pfe_type which_pfe2; if (!pfk_is_ready()) return false; @@ -432,24 +480,38 @@ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2) if (bio1 == bio2) return true; + key1 = bio1->bi_crypt_key; + key2 = bio2->bi_crypt_key; + inode1 = pfk_bio_get_inode(bio1); inode2 = pfk_bio_get_inode(bio2); - which_pfe1 = pfk_get_pfe_type(inode1); which_pfe2 = pfk_get_pfe_type(inode2); - /* nodes with different encryption, do not merge */ + /* + * If one bio is for an encrypted file and the other is for a different + * type of encrypted file or for blocks that are not part of an + * encrypted file, do not merge. + */ if (which_pfe1 != which_pfe2) return false; - /* both nodes do not have encryption, allow merge */ - if (which_pfe1 == INVALID_PFE) - return true; + if (which_pfe1 != INVALID_PFE) { + /* Both bios are for the same type of encrypted file. */ + return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, + inode1, inode2); + } - return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, - inode1, inode2); + /* + * Neither bio is for an encrypted file. Merge only if the default keys + * are the same (or both are NULL). + */ + return key1 == key2 || + (key1 && key2 && + !crypto_memneq(key1->raw, key2->raw, sizeof(key1->raw))); } + /** * Flush key table on storage core reset. During core reset key configuration * is lost in ICE. We need to flash the cache, so that the keys will be diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c index 05a8628e34b8..0eb122565ecc 100644 --- a/security/pfe/pfk_ext4.c +++ b/security/pfe/pfk_ext4.c @@ -26,6 +26,9 @@ * */ + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ #define pr_fmt(fmt) "pfk_ext4 [%s]: " fmt, __func__ #include @@ -33,8 +36,9 @@ #include #include -#include "ext4_ice.h" +#include "fscrypt_ice.h" #include "pfk_ext4.h" +//#include "ext4_ice.h" static bool pfk_ext4_ready; @@ -67,6 +71,29 @@ static inline bool pfk_ext4_is_ready(void) return pfk_ext4_ready; } +/** + * pfk_ext4_dump_inode() - dumps all interesting info about inode to the screen + * + * + */ +/* + * static void pfk_ext4_dump_inode(const struct inode* inode) + * { + * struct ext4_crypt_info *ci = ext4_encryption_info((struct inode*)inode); + * + * pr_debug("dumping inode with address 0x%p\n", inode); + * pr_debug("S_ISREG is %d\n", S_ISREG(inode->i_mode)); + * pr_debug("EXT4_INODE_ENCRYPT flag is %d\n", + * ext4_test_inode_flag((struct inode*)inode, EXT4_INODE_ENCRYPT)); + * if (ci) { + * pr_debug("crypt_info address 0x%p\n", ci); + * pr_debug("ci->ci_data_mode %d\n", ci->ci_data_mode); + * } else { + * pr_debug("crypt_info is NULL\n"); + * } + * } + */ + /** * pfk_is_ext4_type() - return true if inode belongs to ICE EXT4 PFE * @inode: inode pointer @@ -76,7 +103,7 @@ bool pfk_is_ext4_type(const struct inode *inode) if (!pfe_is_inode_filesystem_type(inode, "ext4")) return false; - return ext4_should_be_processed_by_ice(inode); + return fscrypt_should_be_processed_by_ice(inode); } /** @@ -98,7 +125,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode, if (!inode) return -EINVAL; - if (!ext4_is_aes_xts_cipher(inode)) { + if (!fscrypt_is_aes_xts_cipher(inode)) { pr_err("ext4 alghoritm is not supported by pfk\n"); return -EINVAL; } @@ -109,6 +136,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode, return 0; } + int pfk_ext4_parse_inode(const struct bio *bio, const struct inode *inode, struct pfk_key_info *key_info, @@ -136,25 +164,25 @@ int pfk_ext4_parse_inode(const struct bio *bio, if (!key_info) return -EINVAL; - key_info->key = ext4_get_ice_encryption_key(inode); + key_info->key = fscrypt_get_ice_encryption_key(inode); if (!key_info->key) { pr_err("could not parse key from ext4\n"); return -EINVAL; } - key_info->key_size = ext4_get_ice_encryption_key_size(inode); + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); if (!key_info->key_size) { pr_err("could not parse key size from ext4\n"); return -EINVAL; } - key_info->salt = ext4_get_ice_encryption_salt(inode); + key_info->salt = fscrypt_get_ice_encryption_salt(inode); if (!key_info->salt) { pr_err("could not parse salt from ext4\n"); return -EINVAL; } - key_info->salt_size = ext4_get_ice_encryption_salt_size(inode); + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); if (!key_info->salt_size) { pr_err("could not parse salt size from ext4\n"); return -EINVAL; @@ -180,5 +208,5 @@ bool pfk_ext4_allow_merge_bio(const struct bio *bio1, if (!inode1 || !inode2) return false; - return ext4_is_ice_encryption_info_equal(inode1, inode2); + return fscrypt_is_ice_encryption_info_equal(inode1, inode2); } diff --git a/security/pfe/pfk_f2fs.c b/security/pfe/pfk_f2fs.c new file mode 100644 index 000000000000..8b9d515043e8 --- /dev/null +++ b/security/pfe/pfk_f2fs.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Per-File-Key (PFK) - f2fs + * + * This driver is used for working with EXT4/F2FS crypt extension + * + * The key information is stored in node by EXT4/F2FS when file is first opened + * and will be later accessed by Block Device Driver to actually load the key + * to encryption hw. + * + * PFK exposes API's for loading and removing keys from encryption hw + * and also API to determine whether 2 adjacent blocks can be agregated by + * Block Layer in one request to encryption hw. + * + */ + + +/* Uncomment the line below to enable debug messages */ +#define DEBUG 1 +#define pr_fmt(fmt) "pfk_f2fs [%s]: " fmt, __func__ + +#include +#include +#include +#include + +#include "fscrypt_ice.h" +#include "pfk_f2fs.h" + +static bool pfk_f2fs_ready; + +/* + * pfk_f2fs_deinit() - Deinit function, should be invoked by upper PFK layer + */ +void pfk_f2fs_deinit(void) +{ + pfk_f2fs_ready = false; +} + +/* + * pfk_f2fs_init() - Init function, should be invoked by upper PFK layer + */ +int __init pfk_f2fs_init(void) +{ + pfk_f2fs_ready = true; + pr_info("PFK F2FS inited successfully\n"); + + return 0; +} + +/** + * pfk_f2fs_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +static inline bool pfk_f2fs_is_ready(void) +{ + return pfk_f2fs_ready; +} + +/** + * pfk_is_f2fs_type() - return true if inode belongs to ICE F2FS PFE + * @inode: inode pointer + */ +bool pfk_is_f2fs_type(const struct inode *inode) +{ + if (!pfe_is_inode_filesystem_type(inode, "f2fs")) + return false; + + return fscrypt_should_be_processed_by_ice(inode); +} + +/** + * pfk_f2fs_parse_cipher() - parse cipher from inode to enum + * @inode: inode + * @algo: pointer to store the output enum (can be null) + * + * return 0 in case of success, error otherwise (i.e not supported cipher) + */ +static int pfk_f2fs_parse_cipher(const struct inode *inode, + enum ice_cryto_algo_mode *algo) +{ + /* + * currently only AES XTS algo is supported + * in the future, table with supported ciphers might + * be introduced + */ + if (!inode) + return -EINVAL; + + if (!fscrypt_is_aes_xts_cipher(inode)) { + pr_err("f2fs alghoritm is not supported by pfk\n"); + return -EINVAL; + } + + if (algo) + *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; + + return 0; +} + + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe) +{ + int ret = 0; + + if (!is_pfe) + return -EINVAL; + + /* + * only a few errors below can indicate that + * this function was not invoked within PFE context, + * otherwise we will consider it PFE + */ + *is_pfe = true; + + if (!pfk_f2fs_is_ready()) + return -ENODEV; + + if (!inode) + return -EINVAL; + + if (!key_info) + return -EINVAL; + + key_info->key = fscrypt_get_ice_encryption_key(inode); + if (!key_info->key) { + pr_err("could not parse key from f2fs\n"); + return -EINVAL; + } + + key_info->key_size = fscrypt_get_ice_encryption_key_size(inode); + if (!key_info->key_size) { + pr_err("could not parse key size from f2fs\n"); + return -EINVAL; + } + + key_info->salt = fscrypt_get_ice_encryption_salt(inode); + if (!key_info->salt) { + pr_err("could not parse salt from f2fs\n"); + return -EINVAL; + } + + key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode); + if (!key_info->salt_size) { + pr_err("could not parse salt size from f2fs\n"); + return -EINVAL; + } + + ret = pfk_f2fs_parse_cipher(inode, algo); + if (ret != 0) { + pr_err("not supported cipher\n"); + return ret; + } + + return 0; +} + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2) +{ + bool mergeable; + + /* if there is no f2fs pfk, don't disallow merging blocks */ + if (!pfk_f2fs_is_ready()) + return true; + + if (!inode1 || !inode2) + return false; + + mergeable = fscrypt_is_ice_encryption_info_equal(inode1, inode2); + if (!mergeable) + return false; + + + /* ICE allows only consecutive iv_key stream. */ + if (!bio_dun(bio1) && !bio_dun(bio2)) + return true; + else if (!bio_dun(bio1) || !bio_dun(bio2)) + return false; + + return bio_end_dun(bio1) == bio_dun(bio2); +} diff --git a/security/pfe/pfk_f2fs.h b/security/pfe/pfk_f2fs.h new file mode 100644 index 000000000000..551d529bced6 --- /dev/null +++ b/security/pfe/pfk_f2fs.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PFK_F2FS_H_ +#define _PFK_F2FS_H_ + +#include +#include +#include +#include "pfk_internal.h" + +bool pfk_is_f2fs_type(const struct inode *inode); + +int pfk_f2fs_parse_inode(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe); + +bool pfk_f2fs_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +int __init pfk_f2fs_init(void); + +void pfk_f2fs_deinit(void); + +#endif /* _PFK_F2FS_H_ */ diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index bf60dd18dd76..6452b4220136 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -24,7 +24,7 @@ #include #include #include "pfk_ice.h" - +#include "qseecom_kernel.h" /**********************************/ /** global definitions **/ @@ -55,48 +55,120 @@ TZ_SYSCALL_CREATE_PARAM_ID_1( \ TZ_SYSCALL_PARAM_TYPE_VAL) +#define CONTEXT_SIZE 0x1000 + +#define KEYMASTER_UTILS_CMD_ID 0x200UL +#define KEYMASTER_SET_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 18UL) +#define KEYMASTER_CLEAR_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 19UL) + #define ICE_KEY_SIZE 32 #define ICE_SALT_SIZE 32 static uint8_t ice_key[ICE_KEY_SIZE]; static uint8_t ice_salt[ICE_KEY_SIZE]; -int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, - char *storage_type) +static struct qseecom_handle *qhandle; + +static int set_wrapped_key(uint32_t index, const uint8_t *key, + const uint8_t *salt) +{ + int ret = 0; + u32 set_req_len = 0; + u32 set_rsp_len = 0; + struct pfk_ice_key_req *set_req_buf; + struct pfk_ice_key_rsp *set_rsp_buf; + + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); + + if (!qhandle) { + ret = qseecom_start_app(&qhandle, "keymaster64", + CONTEXT_SIZE); + if (ret) { + pr_err("Qseecom start app failed\n"); + return ret; + } + } + + set_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + set_req_buf->cmd_id = KEYMASTER_SET_ICE_KEY; + set_req_buf->index = index; + set_req_buf->ice_key_offset = sizeof(struct pfk_ice_key_req); + set_req_buf->ice_key_size = ICE_KEY_SIZE; + set_req_buf->ice_salt_offset = set_req_buf->ice_key_offset + + set_req_buf->ice_key_size; + set_req_buf->ice_salt_size = ICE_SALT_SIZE; + + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_key_offset, ice_key, + set_req_buf->ice_key_size); + memcpy((uint8_t *) set_req_buf + set_req_buf->ice_salt_offset, ice_salt, + set_req_buf->ice_salt_size); + + set_req_len = sizeof(struct pfk_ice_key_req) + set_req_buf->ice_key_size + + set_req_buf->ice_salt_size; + + set_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + set_req_len); + set_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, + set_req_buf, set_req_len, + set_rsp_buf, set_rsp_len); + + if (ret) + pr_err("%s: Set wrapped key error: Status %d\n", __func__, + set_rsp_buf->ret); + + return ret; +} + +static int clear_wrapped_key(uint32_t index) +{ + int ret = 0; + + u32 clear_req_len = 0; + u32 clear_rsp_len = 0; + struct pfk_ice_key_req *clear_req_buf; + struct pfk_ice_key_rsp *clear_rsp_buf; + + clear_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf; + memset(clear_req_buf, 0, sizeof(qhandle->sbuf)); + clear_req_buf->cmd_id = KEYMASTER_CLEAR_ICE_KEY; + clear_req_buf->index = index; + clear_req_len = sizeof(struct pfk_ice_key_req); + clear_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf + + QSEECOM_ALIGN(clear_req_len)); + clear_rsp_len = sizeof(struct pfk_ice_key_rsp); + + ret = qseecom_send_command(qhandle, clear_req_buf, clear_req_len, + clear_rsp_buf, clear_rsp_len); + if (ret) + pr_err("%s: Clear wrapped key error: Status %d\n", __func__, + clear_rsp_buf->ret); + + return ret; +} + +static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt) { struct scm_desc desc = {0}; - int ret, ret1; + int ret = 0; + uint32_t smc_id = 0; char *tzbuf_key = (char *)ice_key; char *tzbuf_salt = (char *)ice_salt; - char *s_type = storage_type; - uint32_t smc_id = 0; u32 tzbuflen_key = sizeof(ice_key); u32 tzbuflen_salt = sizeof(ice_salt); - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { - pr_err("%s Invalid index %d\n", __func__, index); - return -EINVAL; - } - if (!key || !salt) { - pr_err("%s Invalid key/salt\n", __func__); - return -EINVAL; - } - if (!tzbuf_key || !tzbuf_salt) { pr_err("%s No Memory\n", __func__); return -ENOMEM; } - if (s_type == NULL) { - pr_err("%s Invalid Storage type\n", __func__); - return -EINVAL; - } - memset(tzbuf_key, 0, tzbuflen_key); memset(tzbuf_salt, 0, tzbuflen_salt); - memcpy(ice_key, key, tzbuflen_key); - memcpy(ice_salt, salt, tzbuflen_salt); + memcpy(ice_key, key, sizeof(ice_key)); + memcpy(ice_salt, salt, sizeof(ice_salt)); dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); @@ -110,33 +182,84 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, desc.args[3] = virt_to_phys(tzbuf_salt); desc.args[4] = tzbuflen_salt; + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + + return ret; +} + +static int clear_key(uint32_t index) +{ + struct scm_desc desc = {0}; + int ret = 0; + uint32_t smc_id = 0; + + smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; + + desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; + desc.args[0] = index; + + ret = scm_call2(smc_id, &desc); + if (ret) + pr_err("%s:SCM call Error: 0x%x\n", __func__, ret); + return ret; +} + +int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, + char *storage_type) +{ + int ret = 0, ret1 = 0; + char *s_type = storage_type; + + if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { + pr_err("%s Invalid index %d\n", __func__, index); + return -EINVAL; + } + if (!key || !salt) { + pr_err("%s Invalid key/salt\n", __func__); + return -EINVAL; + } + + if (s_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + return -EINVAL; + } + ret = qcom_ice_setup_ice_hw((const char *)s_type, true); if (ret) { pr_err("%s: could not enable clocks: %d\n", __func__, ret); goto out; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + pr_debug("%s: Setting wrapped key\n", __func__); + ret = set_wrapped_key(index, key, salt); + } else { + pr_debug("%s: Setting keys with QSEE kernel\n", __func__); + ret = set_key(index, key, salt); + } + if (ret) { pr_err("%s: Set Key Error: %d\n", __func__, ret); if (ret == -EBUSY) { if (qcom_ice_setup_ice_hw((const char *)s_type, false)) pr_err("%s: clock disable failed\n", __func__); - goto out; + goto out; } /* Try to invalidate the key to keep ICE in proper state */ - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret1 = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) + ret1 = clear_wrapped_key(index); + else + ret1 = clear_key(index); + if (ret1) - pr_err("%s: Invalidate Key Error: %d\n", __func__, - ret1); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); } ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); - if (ret1) - pr_err("%s: Error %d disabling clocks\n", __func__, ret1); + if (ret) + pr_err("%s: Error %d disabling clocks\n", __func__, ret); out: return ret; @@ -144,11 +267,8 @@ out: int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) { - struct scm_desc desc = {0}; int ret = 0; - uint32_t smc_id = 0; - if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) { pr_err("%s Invalid index %d\n", __func__, index); return -EINVAL; @@ -159,20 +279,22 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) return -EINVAL; } - smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID; - - desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID; - desc.args[0] = index; - ret = qcom_ice_setup_ice_hw((const char *)storage_type, true); if (ret) { pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret); return ret; } - ret = scm_call2(smc_id, &desc); + if (pfk_wrapped_key_supported()) { + ret = clear_wrapped_key(index); + pr_debug("%s: Clearing wrapped key\n", __func__); + } else { + pr_debug("%s: Clearing keys with QSEE kernel\n", __func__); + ret = clear_key(index); + } + if (ret) - pr_err("%s: Error: 0x%x\n", __func__, ret); + pr_err("%s: Invalidate key error: %d\n", __func__, ret); if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) pr_err("%s: could not disable clocks\n", __func__); diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h index a00193919116..5adfcb200b68 100644 --- a/security/pfe/pfk_ice.h +++ b/security/pfe/pfk_ice.h @@ -22,9 +22,35 @@ #include +struct __attribute__ ((__packed__)) pfk_ice_key_req { + uint32_t cmd_id; + uint32_t index; + uint32_t ice_key_offset; + uint32_t ice_key_size; + uint32_t ice_salt_offset; + uint32_t ice_salt_size; +}; + +struct __attribute__ ((__packed__)) pfk_ice_key_rsp { + uint32_t ret; + uint32_t cmd_id; +}; + int pfk_ice_init(void); int pfk_ice_deinit(void); +#ifdef CONFIG_PFK_WRAPPED_KEY_SUPPORTED +static inline bool pfk_wrapped_key_supported(void) +{ + return true; +} +#else +static inline bool pfk_wrapped_key_supported(void) +{ + return false; +} +#endif + int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, char *storage_type); int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type); diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c index 6ccfbd1a5484..041a02f1b3ee 100644 --- a/security/pfe/pfk_kc.c +++ b/security/pfe/pfk_kc.c @@ -435,6 +435,7 @@ int pfk_kc_init(void) } kc_ready = true; kc_spin_unlock(); + return 0; } @@ -448,6 +449,7 @@ int pfk_kc_deinit(void) int res = pfk_kc_clear(); kc_ready = false; + return res; } diff --git a/security/security.c b/security/security.c index d0d99921b751..2ba27d75f052 100644 --- a/security/security.c +++ b/security/security.c @@ -613,7 +613,7 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode EXPORT_SYMBOL_GPL(security_inode_create); int security_inode_post_create(struct inode *dir, struct dentry *dentry, - umode_t mode) + umode_t mode) { if (unlikely(IS_PRIVATE(dir))) return 0; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index af8582501f93..9cec304b6937 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -66,7 +66,7 @@ struct inode_security_struct { u16 sclass; /* security class of this object */ unsigned char initialized; /* initialization flag */ u32 tag; /* Per-File-Encryption tag */ - void *pfk_data; /* Per-File-Key data from ecryptfs */ + void *pfk_data; /* Per-File-Key data from ecryptfs */ spinlock_t lock; }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index de4c7d32b955..99203f1b32ff 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -13,6 +13,7 @@ #include #include #include +//#include "flask.h" #define SECSID_NULL 0x00000000 /* unspecified SID */ #define SECSID_WILD 0xffffffff /* wildcard SID */