diff --git a/block/bio.c b/block/bio.c index 4f93345c6a82..4d938110a518 100644 --- a/block/bio.c +++ b/block/bio.c @@ -589,7 +589,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_opf = bio_src->bi_opf; 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_blkcg_association(bio, bio_src); } EXPORT_SYMBOL(__bio_clone_fast); diff --git a/block/blk-merge.c b/block/blk-merge.c index abde3707438d..0272face5199 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -6,7 +6,7 @@ #include #include #include - +#include #include #include "blk.h" @@ -725,6 +725,11 @@ static void blk_account_io_merge(struct request *req) } } +static bool crypto_not_mergeable(const struct bio *bio, const struct bio *nxt) +{ + return (!pfk_allow_merge_bio(bio, nxt)); +} + /* * Has to be called with the request spinlock acquired */ @@ -752,6 +757,8 @@ static int attempt_merge(struct request_queue *q, struct request *req, !blk_write_same_mergeable(req->bio, next->bio)) return 0; + 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 @@ -862,6 +869,8 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) !blk_write_same_mergeable(rq->bio, bio)) return false; + if (crypto_not_mergeable(rq->bio, bio)) + return false; return true; } diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 3aa75aa03044..f15267eb69b8 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -152,6 +152,9 @@ static int qti_ice_setting_config(struct request *req, return -EPERM; } + if (!setting) + return -EINVAL; + if ((short)(crypto_data->key_index) >= 0) { memcpy(&setting->crypto_data, crypto_data, @@ -1488,7 +1491,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, bool is_pfe = false; sector_t data_size; - if (!pdev || !req || !setting) { + if (!pdev || !req) { pr_err("%s: Invalid params passed\n", __func__); return -EINVAL; } @@ -1507,6 +1510,7 @@ static int qcom_ice_config_start(struct platform_device *pdev, /* It is not an error to have a request with no bio */ return 0; } + //pr_err("%s bio is %pK\n", __func__, req->bio); ret = pfk_load_key_start(req->bio, &pfk_crypto_data, &is_pfe, async); if (is_pfe) { @@ -1664,7 +1668,7 @@ static struct ice_device *get_ice_device_from_storage_type list_for_each_entry(ice_dev, &ice_devices, list) { if (!strcmp(ice_dev->ice_instance_type, storage_type)) { - pr_info("%s: found ice device %p\n", __func__, ice_dev); + pr_debug("%s: ice device %pK\n", __func__, ice_dev); return ice_dev; } } diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index b1c86d42148a..d4fe6eede3b4 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-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 @@ -172,17 +172,15 @@ out: static void ufs_qcom_ice_cfg_work(struct work_struct *work) { unsigned long flags; - struct ice_data_setting ice_set; struct ufs_qcom_host *qcom_host = container_of(work, struct ufs_qcom_host, ice_cfg_work); - struct request *req_pending = NULL; if (!qcom_host->ice.vops->config_start) return; spin_lock_irqsave(&qcom_host->ice_work_lock, flags); - req_pending = qcom_host->req_pending; - if (!req_pending) { + if (!qcom_host->req_pending) { + qcom_host->work_pending = false; spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); return; } @@ -191,24 +189,15 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work) /* * config_start is called again as previous attempt returned -EAGAIN, * this call shall now take care of the necessary key setup. - * 'ice_set' will not actually be used, instead the next call to - * config_start() for this request, in the normal call flow, will - * succeed as the key has now been setup. */ qcom_host->ice.vops->config_start(qcom_host->ice.pdev, - qcom_host->req_pending, &ice_set, false); + qcom_host->req_pending, NULL, false); spin_lock_irqsave(&qcom_host->ice_work_lock, flags); qcom_host->req_pending = NULL; + qcom_host->work_pending = false; spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags); - /* - * Resume with requests processing. We assume config_start has been - * successful, but even if it wasn't we still must resume in order to - * allow for the request to be retried. - */ - ufshcd_scsi_unblock_requests(qcom_host->hba); - } /** @@ -294,18 +283,14 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, * requires a non-atomic context, this means we should * call the function again from the worker thread to do * the configuration. For this request the error will - * propagate so it will be re-queued and until the - * configuration is is completed we block further - * request processing. + * propagate so it will be re-queued. */ if (err == -EAGAIN) { dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", __func__); - if (!qcom_host->req_pending) { - ufshcd_scsi_block_requests( - qcom_host->hba); + if (!qcom_host->work_pending) { qcom_host->req_pending = cmd->request; if (!queue_work(ice_workqueue, @@ -316,10 +301,9 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, &qcom_host->ice_work_lock, flags); - ufshcd_scsi_unblock_requests( - qcom_host->hba); return err; } + qcom_host->work_pending = true; } } else { @@ -418,9 +402,7 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, * requires a non-atomic context, this means we should * call the function again from the worker thread to do * the configuration. For this request the error will - * propagate so it will be re-queued and until the - * configuration is is completed we block further - * request processing. + * propagate so it will be re-queued. */ if (err == -EAGAIN) { @@ -428,9 +410,8 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, "%s: scheduling task for ice setup\n", __func__); - if (!qcom_host->req_pending) { - ufshcd_scsi_block_requests( - qcom_host->hba); + if (!qcom_host->work_pending) { + qcom_host->req_pending = cmd->request; if (!queue_work(ice_workqueue, &qcom_host->ice_cfg_work)) { @@ -440,10 +421,9 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, &qcom_host->ice_work_lock, flags); - ufshcd_scsi_unblock_requests( - qcom_host->hba); return err; } + qcom_host->work_pending = true; } } else { diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index a03ecb0dc1f7..27f6a05af547 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -375,6 +375,7 @@ struct ufs_qcom_host { struct work_struct ice_cfg_work; struct request *req_pending; struct ufs_vreg *vddp_ref_clk; + bool work_pending; }; static inline u32 diff --git a/fs/crypto/Makefile b/fs/crypto/Makefile index cb496989a6b6..a35f058cd6f5 100644 --- a/fs/crypto/Makefile +++ b/fs/crypto/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o +ccflags-y += -Ifs/ext4 fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o fscrypto-$(CONFIG_BLOCK) += bio.o diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index d7b4c480e39e..205e92806876 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -32,14 +32,18 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - int ret = fscrypt_decrypt_page(page->mapping->host, page, - PAGE_SIZE, 0, page->index); - if (ret) { - WARN_ON_ONCE(1); - SetPageError(page); - } else if (done) { + if (fs_is_ice_enabled()) { SetPageUptodate(page); + } else { + int ret = fscrypt_decrypt_page(page->mapping->host, + page, PAGE_SIZE, 0, page->index); + if (ret) { + WARN_ON_ONCE(1); + SetPageError(page); + } else if (done) { + SetPageUptodate(page); + } } if (done) unlock_page(page); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index d36a648cb2bb..3e72d65e8a80 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -69,6 +69,7 @@ struct fscrypt_info { struct crypto_skcipher *ci_ctfm; struct crypto_cipher *ci_essiv_tfm; u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE]; + u8 ci_raw_key[FS_MAX_KEY_SIZE]; }; typedef enum { @@ -90,6 +91,9 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) return true; + if (contents_mode == FS_ENCRYPTION_MODE_PRIVATE) + return true; + return false; } @@ -112,6 +116,10 @@ extern bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, u32 max_len, u32 *encrypted_len_ret); +static inline int fs_is_ice_enabled(void) +{ + return 1; +} /* keyinfo.c */ extern void __exit fscrypt_essiv_cleanup(void); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index aae68c0924f1..dcd00d5fe62c 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -134,10 +134,12 @@ static const struct { FS_AES_128_CBC_KEY_SIZE }, [FS_ENCRYPTION_MODE_AES_128_CTS] = { "cts(cbc(aes))", FS_AES_128_CTS_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) + const char **cipher_str_ret, int *keysize_ret, int *fname) { u32 mode; @@ -152,6 +154,7 @@ static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode, mode = ci->ci_data_mode; } else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) { mode = ci->ci_filename_mode; + *fname = 1; } 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)); @@ -170,6 +173,7 @@ static void put_crypt_info(struct fscrypt_info *ci) crypto_free_skcipher(ci->ci_ctfm); crypto_free_cipher(ci->ci_essiv_tfm); + memzero_explicit(ci->ci_raw_key, sizeof(ci->ci_raw_key)); kmem_cache_free(fscrypt_info_cachep, ci); } @@ -239,6 +243,21 @@ void __exit fscrypt_essiv_cleanup(void) crypto_free_shash(essiv_hash_tfm); } +static int fs_data_encryption_mode(void) +{ + return fs_is_ice_enabled() ? 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; @@ -246,8 +265,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; @@ -264,7 +283,7 @@ 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_ENCRYPTION_MODE_AES_256_XTS; + ctx.contents_encryption_mode = fs_data_encryption_mode(); 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)) { @@ -289,7 +308,8 @@ 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); + res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize, + &fname); if (res) goto out; @@ -298,16 +318,13 @@ 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; - res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX, - keysize); + res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key, + FS_KEY_DESC_PREFIX, keysize); if (res && inode->i_sb->s_cop->key_prefix) { - int res2 = validate_user_key(crypt_info, &ctx, raw_key, - inode->i_sb->s_cop->key_prefix, - keysize); + int res2 = validate_user_key(crypt_info, &ctx, + crypt_info->ci_raw_key, + inode->i_sb->s_cop->key_prefix, keysize); if (res2) { if (res2 == -ENOKEY) res = -ENOKEY; @@ -316,32 +333,40 @@ int fscrypt_get_encryption_info(struct inode *inode) } else if (res) { goto out; } - 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, 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, raw_key, keysize); - if (res) { - pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", + 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_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); + if (res) { + pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n", + __func__, res, inode->i_ino); + goto out; + } + } + } else if (!fs_is_ice_enabled()) { + pr_warn("%s: ICE support not available\n", __func__); + res = -EINVAL; + goto out; } if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL) crypt_info = NULL; @@ -349,7 +374,6 @@ out: if (res == -ENOKEY) res = 0; put_crypt_info(crypt_info); - kzfree(raw_key); return res; } EXPORT_SYMBOL(fscrypt_get_encryption_info); @@ -360,3 +384,51 @@ void fscrypt_put_encryption_info(struct inode *inode) inode->i_crypt_info = NULL; } EXPORT_SYMBOL(fscrypt_put_encryption_info); + +char *fscrypt_get_ice_encryption_key(const struct inode *inode) +{ + struct fscrypt_info *ci; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[0]); +} +EXPORT_SYMBOL(fscrypt_get_ice_encryption_key); + +/* + * Retrieves encryption salt from the inode + */ +char *fscrypt_get_ice_encryption_salt(const struct inode *inode) +{ + struct fscrypt_info *ci; + + if (!inode) + return NULL; + + ci = inode->i_crypt_info; + if (!ci) + return NULL; + + return &(ci->ci_raw_key[FS_AES_256_XTS_KEY_SIZE / 2]); +} +EXPORT_SYMBOL(fscrypt_get_ice_encryption_salt); + +/* + * 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; + + ci = inode->i_crypt_info; + if (!ci) + return 0; + + return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); +} +EXPORT_SYMBOL(fscrypt_is_aes_xts_cipher); diff --git a/fs/direct-io.c b/fs/direct-io.c index c6220a2daefd..bf03a92d109a 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -411,6 +411,7 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty) bio_set_pages_dirty(bio); + bio->bi_dio_inode = dio->inode; dio->bio_bdev = bio->bi_bdev; if (sdio->submit_io) { @@ -424,6 +425,18 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) sdio->logical_offset_in_bio = 0; } +struct inode *dio_bio_get_inode(struct bio *bio) +{ + struct inode *inode = NULL; + + if (bio == NULL) + 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/Kconfig b/fs/ext4/Kconfig index e38039fd96ff..e9232a09af5d 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -109,10 +109,16 @@ config EXT4_ENCRYPTION decrypted pages in the page cache. config EXT4_FS_ENCRYPTION - bool - default y + bool "Ext4 FS Encryption" + default n depends on EXT4_ENCRYPTION +config EXT4_FS_ICE_ENCRYPTION + bool "Ext4 Encryption with ICE support" + default n + depends on EXT4_FS_ENCRYPTION + depends on PFK + config EXT4_DEBUG bool "EXT4 debugging support" depends on EXT4_FS diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 354103f3490c..d9e563a914ad 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -1,6 +1,7 @@ # # Makefile for the linux ext4-filesystem routines. # +ccflags-y += -Ifs/crypto obj-$(CONFIG_EXT4_FS) += ext4.o @@ -12,3 +13,4 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o +ext4-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o diff --git a/fs/ext4/ext4_ice.c b/fs/ext4/ext4_ice.c new file mode 100644 index 000000000000..802df3699810 --- /dev/null +++ b/fs/ext4/ext4_ice.c @@ -0,0 +1,109 @@ +/* Copyright (c) 2017-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 + +/* + * Retrieves encryption key from the inode + */ +char *ext4_get_ice_encryption_key(const struct inode *inode) +{ + /* + * struct fscrypt_info *ci; + * if (!inode) + * return NULL; + * ci = inode->i_crypt_info; + * if (!ci) + * return NULL; + * return &(ci->ci_raw_key[0]); + */ + return fscrypt_get_ice_encryption_key(inode); +} + +/* + * Retrieves encryption salt from the inode + */ +char *ext4_get_ice_encryption_salt(const struct inode *inode) +{ + /* + * struct fscrypt_info *ci; + * 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)]); + */ + return fscrypt_get_ice_encryption_salt(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; + * ci = inode->i_crypt_info; + * if (!ci) + * return 0; + * return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE); + */ + return fscrypt_is_aes_xts_cipher(inode); +} + +/* + * 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/ext4/ext4_ice.h b/fs/ext4/ext4_ice.h new file mode 100644 index 000000000000..8cf4d2e607c9 --- /dev/null +++ b/fs/ext4/ext4_ice.h @@ -0,0 +1,108 @@ +/* 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" +#define EXT4_256_XTS_KEY_SIZE 64 + +#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 EXT4_256_XTS_KEY_SIZE / 2; +} + +static inline size_t ext4_get_ice_encryption_salt_size( + const struct inode *inode) +{ + return EXT4_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; +} + +static int fs_using_hardware_encryption(struct inode *inode) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* _EXT4_ICE_H */ diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 2bf83d0cb363..3d89b98c8b37 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -42,6 +42,7 @@ #include "xattr.h" #include "acl.h" #include "truncate.h" +#include "ext4_ice.h" #include #include @@ -1152,7 +1153,8 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, ll_rw_block(REQ_OP_READ, 0, 1, &bh); *wait_bh++ = bh; decrypt = ext4_encrypted_inode(inode) && - S_ISREG(inode->i_mode); + S_ISREG(inode->i_mode) && + !ext4_is_ice_enabled(); } } /* @@ -3509,7 +3511,8 @@ 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; } -#ifdef CONFIG_EXT4_FS_ENCRYPTION +#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ +!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)); #endif if (IS_DAX(inode)) { @@ -3631,7 +3634,8 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ssize_t ret; int rw = iov_iter_rw(iter); -#ifdef CONFIG_EXT4_FS_ENCRYPTION +#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \ +!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION) if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) return 0; #endif @@ -3828,7 +3832,8 @@ static int __ext4_block_zero_page_range(handle_t *handle, if (!buffer_uptodate(bh)) goto unlock; if (S_ISREG(inode->i_mode) && - ext4_encrypted_inode(inode)) { + ext4_encrypted_inode(inode) && + !fs_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 15ca15cb9f28..3585e26c0964 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -774,8 +774,8 @@ resizefs_out: return ext4_ext_precache(inode); case EXT4_IOC_SET_ENCRYPTION_POLICY: - if (!ext4_has_feature_encrypt(sb)) - return -EOPNOTSUPP; +// if (!ext4_has_feature_encrypt(sb)) +// return -EOPNOTSUPP; return fscrypt_ioctl_set_policy(filp, (const void __user *)arg); case EXT4_IOC_GET_ENCRYPTION_PWSALT: { diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 0718a8667f0c..a9dc6723b9db 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -28,6 +28,7 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" +#include "ext4_ice.h" static struct kmem_cache *io_end_cachep; @@ -469,6 +470,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, gfp_t gfp_flags = GFP_NOFS; retry_encrypt: + if (!fs_using_hardware_encryption(inode)) data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, page->index, gfp_flags); if (IS_ERR(data_page)) { diff --git a/fs/namei.c b/fs/namei.c index a5a05d3faa63..c138ab184a2e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2905,6 +2905,11 @@ int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, if (error) return error; error = dir->i_op->create(dir, dentry, mode, want_excl); + if (error) + return error; + error = security_inode_post_create(dir, dentry, mode); + if (error) + return error; if (!error) fsnotify_create(dir, dentry); return error; @@ -3720,6 +3725,13 @@ int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, u return error; 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/blk_types.h b/include/linux/blk_types.h index e4d84d327a4b..4115fa430be3 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -81,6 +81,12 @@ 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/fs.h b/include/linux/fs.h index 8a3bdadd0ca7..1c4da438fdc5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2948,6 +2948,8 @@ static inline void inode_dio_end(struct inode *inode) wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); } +struct inode *dio_bio_get_inode(struct bio *bio); + extern void inode_set_flags(struct inode *inode, unsigned int flags, unsigned int mask); diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 1ed79eeb2438..401584753746 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -97,6 +97,10 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, /* keyinfo.c */ extern int fscrypt_get_encryption_info(struct inode *); extern void fscrypt_put_encryption_info(struct inode *); +extern int fs_using_hardware_encryption(struct inode *inode); +extern char *fscrypt_get_ice_encryption_key(const struct inode *inode); +extern char *fscrypt_get_ice_encryption_salt(const struct inode *inode); +extern int fscrypt_is_aes_xts_cipher(const struct inode *inode); /* fname.c */ extern int fscrypt_setup_filename(struct inode *, const struct qstr *, diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index be65c03cfcdc..f510c681378c 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1452,6 +1452,8 @@ union security_list_options { size_t *len); int (*inode_create)(struct inode *dir, struct dentry *dentry, umode_t mode); + int (*inode_post_create)(struct inode *dir, struct dentry *dentry, + umode_t mode); int (*inode_link)(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); int (*inode_unlink)(struct inode *dir, struct dentry *dentry); @@ -1750,6 +1752,7 @@ struct security_hook_heads { struct list_head inode_free_security; struct list_head inode_init_security; struct list_head inode_create; + struct list_head inode_post_create; struct list_head inode_link; struct list_head inode_unlink; struct list_head inode_symlink; diff --git a/include/linux/pfk.h b/include/linux/pfk.h new file mode 100644 index 000000000000..3c7a389fd4d4 --- /dev/null +++ b/include/linux/pfk.h @@ -0,0 +1,57 @@ +/* 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_H_ +#define PFK_H_ + +#include + +struct ice_crypto_setting; + +#ifdef CONFIG_PFK + +int pfk_load_key_start(const struct bio *bio, + struct ice_crypto_setting *ice_setting, bool *is_pfe, bool); +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); +void pfk_clear_on_reset(void); + +#else +static inline int pfk_load_key_start(const struct bio *bio, + struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async) +{ + return -ENODEV; +} + +static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe) +{ + return -ENODEV; +} + +static inline int pfk_remove_key(const unsigned char *key, size_t key_size) +{ + return -ENODEV; +} + +static inline bool pfk_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2) +{ + return true; +} + +static inline void pfk_clear_on_reset(void) +{} + +#endif /* CONFIG_PFK */ + +#endif /* PFK_H */ diff --git a/include/linux/security.h b/include/linux/security.h index 363242871b66..bfb1b749da64 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -30,6 +30,7 @@ #include #include #include +#include struct linux_binprm; struct cred; @@ -256,6 +257,8 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const char **name, void **value, size_t *len); int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode); +int security_inode_post_create(struct inode *dir, struct dentry *dentry, + umode_t mode); int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); int security_inode_unlink(struct inode *dir, struct dentry *dentry); @@ -304,6 +307,7 @@ int security_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int sig); int security_file_receive(struct file *file); int security_file_open(struct file *file, const struct cred *cred); + int security_task_create(unsigned long clone_flags); void security_task_free(struct task_struct *task); int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); @@ -637,6 +641,13 @@ static inline int security_inode_create(struct inode *dir, return 0; } +static inline int security_inode_post_create(struct inode *dir, + struct dentry *dentry, + umode_t mode) +{ + return 0; +} + static inline int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index 12263e4b8b08..dfcf37128ecb 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h @@ -273,6 +273,7 @@ struct fsxattr { #define FS_ENCRYPTION_MODE_AES_256_CTS 4 #define FS_ENCRYPTION_MODE_AES_128_CBC 5 #define FS_ENCRYPTION_MODE_AES_128_CTS 6 +#define FS_ENCRYPTION_MODE_PRIVATE 127 struct fscrypt_policy { __u8 version; diff --git a/security/Kconfig b/security/Kconfig index 2e68fa436974..638afc868ba2 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -6,6 +6,11 @@ menu "Security options" source security/keys/Kconfig +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 f2d71cdb8e19..79166bad11d0 100644 --- a/security/Makefile +++ b/security/Makefile @@ -9,6 +9,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 # always enable default capabilities obj-y += commoncap.o @@ -24,6 +25,7 @@ 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 # Object integrity file lists diff --git a/security/pfe/Kconfig b/security/pfe/Kconfig new file mode 100644 index 000000000000..0cd9e81a4952 --- /dev/null +++ b/security/pfe/Kconfig @@ -0,0 +1,28 @@ +menu "Qualcomm Technologies, Inc Per File Encryption security device drivers" + depends on ARCH_QCOM + +config PFT + bool "Per-File-Tagger driver" + depends on SECURITY + default n + help + This driver is used for tagging enterprise files. + It is part of the Per-File-Encryption (PFE) feature. + The driver is tagging files when created by + registered application. + Tagged files are encrypted using the dm-req-crypt driver. + +config PFK + bool "Per-File-Key driver" + depends on SECURITY + depends on SECURITY_SELINUX + default n + help + This driver is used for storing eCryptfs information + in file node. + This is part of eCryptfs hardware enhanced solution + provided by Qualcomm Technologies, Inc. + Information is used when file is encrypted later using + ICE or dm crypto engine + +endmenu diff --git a/security/pfe/Makefile b/security/pfe/Makefile new file mode 100644 index 000000000000..242a2165fccb --- /dev/null +++ b/security/pfe/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the MSM specific security device drivers. +# + +ccflags-y += -Isecurity/selinux -Isecurity/selinux/include +ccflags-y += -Ifs/ext4 +ccflags-y += -Ifs/crypto + +obj-$(CONFIG_PFT) += pft.o +obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c new file mode 100644 index 000000000000..cd282a09c7d5 --- /dev/null +++ b/security/pfe/pfk.c @@ -0,0 +1,483 @@ +/* + * 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). + * + * This driver is responsible for overall management of various + * Per File Encryption variants that work on top of or as part of different + * file systems. + * + * The driver has the following purpose : + * 1) Define priorities between PFE's if more than one is enabled + * 2) Extract key information from inode + * 3) Load and manage various keys in ICE HW engine + * 4) It should be invoked from various layers in FS/BLOCK/STORAGE DRIVER + * that need to take decision on HW encryption management of the data + * Some examples: + * BLOCK LAYER: when it takes decision on whether 2 chunks can be united + * to one encryption / decryption request sent to the HW + * + * UFS DRIVER: when it need to configure ICE HW with a particular key slot + * to be used for encryption / decryption + * + * PFE variants can differ on particular way of storing the cryptographic info + * inside inode, actions to be taken upon file operations, etc., but the common + * properties are described above + * + */ + + +/* Uncomment the line below to enable debug messages */ +/* #define DEBUG 1 */ +#define pr_fmt(fmt) "pfk [%s]: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pfk_kc.h" +#include "objsec.h" +#include "pfk_ice.h" +#include "pfk_ext4.h" +#include "pfk_internal.h" +#include "ext4.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}; + +typedef int (*pfk_parse_inode_type)(const struct bio *bio, + const struct inode *inode, + struct pfk_key_info *key_info, + enum ice_cryto_algo_mode *algo, + bool *is_pfe); + +typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +static const pfk_parse_inode_type pfk_parse_inode_ftable[] = { + /* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode, +}; + +static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = { + /* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio, +}; + +static void __exit pfk_exit(void) +{ + pfk_ready = false; + pfk_ext4_deinit(); + pfk_kc_deinit(); +} + +static int __init pfk_init(void) +{ + + int ret = 0; + + ret = pfk_ext4_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(); + goto fail; + } + + pfk_ready = true; + pr_info("Driver initialized successfully\n"); + + return 0; + +fail: + pr_err("Failed to init driver\n"); + return -ENODEV; +} + +/* + * If more than one type is supported simultaneously, this function will also + * set the priority between them + */ +static enum pfe_type pfk_get_pfe_type(const struct inode *inode) +{ + if (!inode) + return INVALID_PFE; + + if (pfk_is_ext4_type(inode)) + return EXT4_CRYPT_PFE; + + return INVALID_PFE; +} + +/** + * inode_to_filename() - get the filename from inode pointer. + * @inode: inode pointer + * + * it is used for debug prints. + * + * Return: filename string or "unknown". + */ +char *inode_to_filename(const struct inode *inode) +{ + struct dentry *dentry = NULL; + char *filename = NULL; + + if (hlist_empty(&inode->i_dentry)) + return "unknown"; + + dentry = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); + filename = dentry->d_iname; + + return filename; +} + +/** + * pfk_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +static inline bool pfk_is_ready(void) +{ + return pfk_ready; +} + +/** + * pfk_bio_get_inode() - get the inode from a bio. + * @bio: Pointer to BIO structure. + * + * Walk the bio struct links to get the inode. + * Please note, that in general bio may consist of several pages from + * several files, but in our case we always assume that all pages come + * from the same file, since our logic ensures it. That is why we only + * walk through the first page to look for inode. + * + * Return: pointer to the inode struct if successful, or NULL otherwise. + * + */ +static struct inode *pfk_bio_get_inode(const struct bio *bio) +{ + struct address_space *mapping; + + if (!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) + return NULL; + + if (!mapping->host) + return NULL; + + return bio->bi_io_vec->bv_page->mapping->host; +} + +/** + * pfk_key_size_to_key_type() - translate key size to key size enum + * @key_size: key size in bytes + * @key_size_type: pointer to store the output enum (can be null) + * + * return 0 in case of success, error otherwise (i.e not supported key size) + */ +int pfk_key_size_to_key_type(size_t key_size, + enum ice_crpto_key_size *key_size_type) +{ + /* + * currently only 32 bit key size is supported + * in the future, table with supported key sizes might + * be introduced + */ + + if (key_size != PFK_SUPPORTED_KEY_SIZE) { + pr_err("not supported key size %zu\n", key_size); + return -EINVAL; + } + + if (key_size_type) + *key_size_type = ICE_CRYPTO_KEY_SIZE_256; + + return 0; +} + +/* + * Retrieves filesystem type from inode's superblock + */ +bool pfe_is_inode_filesystem_type(const struct inode *inode, + const char *fs_type) +{ + if (!inode || !fs_type) + return false; + + if (!inode->i_sb) + return false; + + if (!inode->i_sb->s_type) + return false; + + return (strcmp(inode->i_sb->s_type->name, fs_type) == 0); +} + + +/** + * pfk_load_key_start() - loads PFE encryption key to the ICE + * Can also be invoked from non + * PFE context, in this case it + * is not relevant and is_pfe + * flag is set to false + * + * @bio: Pointer to the BIO structure + * @ice_setting: Pointer to ice setting structure that will be filled with + * ice configuration values, including the index to which the key was loaded + * @is_pfe: will be false if inode is not relevant to PFE, in such a case + * it should be treated as non PFE by the block layer + * + * Returns the index where the key is stored in encryption hw and additional + * information that will be used later for configuration of the encryption hw. + * + * Must be followed by pfk_load_key_end when key is no longer used by ice + * + */ +int pfk_load_key_start(const struct bio *bio, + struct ice_crypto_setting *ice_setting, bool *is_pfe, + bool async) +{ + int ret = 0; + struct pfk_key_info key_info = {NULL, NULL, 0, 0}; + 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"); + 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_is_ready()) + return -ENODEV; + + if (!ice_setting) { + 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); + 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) { + if (ret != -EBUSY && ret != -EAGAIN) + pr_err("start: could not load key into pfk key cache, error %d\n", + ret); + + return ret; + } + + ice_setting->key_size = key_size_type; + ice_setting->algo_mode = algo_mode; + /* hardcoded for now */ + ice_setting->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY; + ice_setting->key_index = key_index; + + pr_debug("loaded key for file %s key_index %d\n", + inode_to_filename(inode), key_index); + + return 0; +} + +/** + * pfk_load_key_end() - marks the PFE key as no longer used by ICE + * Can also be invoked from non + * PFE context, in this case it is not + * relevant and is_pfe flag is + * set to false + * + * @bio: Pointer to the BIO structure + * @is_pfe: Pointer to is_pfe flag, which will be true if function was invoked + * from PFE context + */ +int pfk_load_key_end(const struct bio *bio, bool *is_pfe) +{ + int ret = 0; + struct pfk_key_info key_info = {NULL, NULL, 0, 0}; + enum pfe_type which_pfe = INVALID_PFE; + struct inode *inode = NULL; + + if (!is_pfe) { + pr_err("is_pfe is NULL\n"); + 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_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); + if (ret != 0) + return ret; + + pfk_kc_load_key_end(key_info.key, key_info.key_size, + key_info.salt, key_info.salt_size); + + pr_debug("finished using key for file %s\n", + inode_to_filename(inode)); + + return 0; +} + +/** + * pfk_allow_merge_bio() - Check if 2 BIOs can be merged. + * @bio1: Pointer to first BIO structure. + * @bio2: Pointer to second BIO structure. + * + * Prevent merging of BIOs from encrypted and non-encrypted + * files, or files encrypted with different key. + * Also prevent non encrypted and encrypted data from the same file + * to be merged (ecryptfs header if stored inside file should be non + * encrypted) + * This API is called by the file system block layer. + * + * Return: true if the BIOs allowed to be merged, false + * otherwise. + */ +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; + + if (!pfk_is_ready()) + return false; + + if (!bio1 || !bio2) + return false; + + if (bio1 == bio2) + return true; + + 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 (which_pfe1 != which_pfe2) + return false; + + /* both nodes do not have encryption, allow merge */ + if (which_pfe1 == INVALID_PFE) + return true; + + return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2, + inode1, inode2); +} +/** + * 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 + * reconfigured again for every subsequent transaction + */ +void pfk_clear_on_reset(void) +{ + if (!pfk_is_ready()) + return; + + pfk_kc_clear_on_reset(); +} + +module_init(pfk_init); +module_exit(pfk_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Per-File-Key driver"); diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c new file mode 100644 index 000000000000..c8a527e4a671 --- /dev/null +++ b/security/pfe/pfk_ext4.c @@ -0,0 +1,211 @@ +/* + * 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) - EXT4 + * + * This driver is used for working with EXT4 crypt extension + * + * The key information is stored in node by EXT4 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_ext4 [%s]: " fmt, __func__ + +#include +#include +#include +#include + +#include "ext4_ice.h" +#include "pfk_ext4.h" + +static bool pfk_ext4_ready; + +/* + * pfk_ext4_deinit() - Deinit function, should be invoked by upper PFK layer + */ +void pfk_ext4_deinit(void) +{ + pfk_ext4_ready = false; +} + +/* + * pfk_ecryptfs_init() - Init function, should be invoked by upper PFK layer + */ +int __init pfk_ext4_init(void) +{ + pfk_ext4_ready = true; + pr_info("PFK EXT4 inited successfully\n"); + + return 0; +} + +/** + * pfk_ecryptfs_is_ready() - driver is initialized and ready. + * + * Return: true if the driver is ready. + */ +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 + */ +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); +} + +/** + * pfk_ext4_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_ext4_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 (!ext4_is_aes_xts_cipher(inode)) { + pr_err("ext4 alghoritm is not supported by pfk\n"); + return -EINVAL; + } + + if (algo) + *algo = ICE_CRYPTO_ALGO_MODE_AES_XTS; + + return 0; +} + + +int pfk_ext4_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_ext4_is_ready()) + return -ENODEV; + + if (!inode) + return -EINVAL; + + if (!key_info) + return -EINVAL; + + key_info->key = ext4_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); + 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); + 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); + if (!key_info->salt_size) { + pr_err("could not parse salt size from ext4\n"); + return -EINVAL; + } + + ret = pfk_ext4_parse_cipher(inode, algo); + if (ret != 0) { + pr_err("not supported cipher\n"); + return ret; + } + + return 0; +} + +bool pfk_ext4_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2) +{ + /* if there is no ext4 pfk, don't disallow merging blocks */ + if (!pfk_ext4_is_ready()) + return true; + + if (!inode1 || !inode2) + return false; + + return ext4_is_ice_encryption_info_equal(inode1, inode2); +} diff --git a/security/pfe/pfk_ext4.h b/security/pfe/pfk_ext4.h new file mode 100644 index 000000000000..c33232f35a14 --- /dev/null +++ b/security/pfe/pfk_ext4.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_EXT4_H_ +#define _PFK_EXT4_H_ + +#include +#include +#include +#include "pfk_internal.h" + +bool pfk_is_ext4_type(const struct inode *inode); + +int pfk_ext4_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_ext4_allow_merge_bio(const struct bio *bio1, + const struct bio *bio2, const struct inode *inode1, + const struct inode *inode2); + +int __init pfk_ext4_init(void); + +void pfk_ext4_deinit(void); + +#endif /* _PFK_EXT4_H_ */ diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c new file mode 100644 index 000000000000..16ed5162665d --- /dev/null +++ b/security/pfe/pfk_ice.c @@ -0,0 +1,189 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pfk_ice.h" + + +/**********************************/ +/** global definitions **/ +/**********************************/ + +#define TZ_ES_SET_ICE_KEY 0x2 +#define TZ_ES_INVALIDATE_ICE_KEY 0x3 + +/* index 0 and 1 is reserved for FDE */ +#define MIN_ICE_KEY_INDEX 2 + +#define MAX_ICE_KEY_INDEX 31 + + +#define TZ_ES_SET_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_ES, TZ_ES_SET_ICE_KEY) + + +#define TZ_ES_INVALIDATE_ICE_KEY_ID \ + TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, \ + TZ_SVC_ES, TZ_ES_INVALIDATE_ICE_KEY) + + +#define TZ_ES_SET_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_5( \ + TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \ + TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL) + +#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \ + TZ_SYSCALL_CREATE_PARAM_ID_1( \ + TZ_SYSCALL_PARAM_TYPE_VAL) + +#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) +{ + struct scm_desc desc = {0}; + int ret, ret1; + 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); + + dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key); + dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt); + + smc_id = TZ_ES_SET_ICE_KEY_ID; + + desc.arginfo = TZ_ES_SET_ICE_KEY_PARAM_ID; + desc.args[0] = index; + desc.args[1] = virt_to_phys(tzbuf_key); + desc.args[2] = tzbuflen_key; + desc.args[3] = virt_to_phys(tzbuf_salt); + desc.args[4] = tzbuflen_salt; + + 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 (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; + } + /*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 (ret1) + pr_err("%s: Invalidate Key Error: %d\n", __func__, + ret1); + goto out; + } + ret = qcom_ice_setup_ice_hw((const char *)s_type, false); + +out: + return ret; +} + +int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type) +{ + struct scm_desc desc = {0}; + int ret; + + 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; + } + + if (storage_type == NULL) { + pr_err("%s Invalid Storage type\n", __func__); + 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 (ret) { + pr_err("%s: Error: 0x%x\n", __func__, ret); + if (qcom_ice_setup_ice_hw((const char *)storage_type, false)) + pr_err("%s: could not disable clocks\n", __func__); + } else { + ret = qcom_ice_setup_ice_hw((const char *)storage_type, false); + } + + return ret; +} diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h new file mode 100644 index 000000000000..31772e798636 --- /dev/null +++ b/security/pfe/pfk_ice.h @@ -0,0 +1,33 @@ +/* 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 PFK_ICE_H_ +#define PFK_ICE_H_ + +/* + * PFK ICE + * + * ICE keys configuration through scm calls. + * + */ + +#include + +int pfk_ice_init(void); +int pfk_ice_deinit(void); + +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); + + +#endif /* PFK_ICE_H_ */ diff --git a/security/pfe/pfk_internal.h b/security/pfe/pfk_internal.h new file mode 100644 index 000000000000..3214327b8bcd --- /dev/null +++ b/security/pfe/pfk_internal.h @@ -0,0 +1,34 @@ +/* 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_INTERNAL_H_ +#define _PFK_INTERNAL_H_ + +#include +#include + +struct pfk_key_info { + const unsigned char *key; + const unsigned char *salt; + size_t key_size; + size_t salt_size; +}; + +int pfk_key_size_to_key_type(size_t key_size, + enum ice_crpto_key_size *key_size_type); + +bool pfe_is_inode_filesystem_type(const struct inode *inode, + const char *fs_type); + +char *inode_to_filename(const struct inode *inode); + +#endif /* _PFK_INTERNAL_H_ */ diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c new file mode 100644 index 000000000000..a405d05ccbfb --- /dev/null +++ b/security/pfe/pfk_kc.c @@ -0,0 +1,905 @@ +/* + * 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. + */ + +/* + * PFK Key Cache + * + * Key Cache used internally in PFK. + * The purpose of the cache is to save access time to QSEE when loading keys. + * Currently the cache is the same size as the total number of keys that can + * be loaded to ICE. Since this number is relatively small, the algorithms for + * cache eviction are simple, linear and based on last usage timestamp, i.e + * the node that will be evicted is the one with the oldest timestamp. + * Empty entries always have the oldest timestamp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pfk_kc.h" +#include "pfk_ice.h" + + +/** the first available index in ice engine */ +#define PFK_KC_STARTING_INDEX 2 + +/** currently the only supported key and salt sizes */ +#define PFK_KC_KEY_SIZE 32 +#define PFK_KC_SALT_SIZE 32 + +/** Table size */ +/* TODO replace by some constant from ice.h */ +#define PFK_KC_TABLE_SIZE ((32) - (PFK_KC_STARTING_INDEX)) + +/** The maximum key and salt size */ +#define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE +#define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE +#define PFK_UFS "ufs" + +static DEFINE_SPINLOCK(kc_lock); +static unsigned long flags; +static bool kc_ready; +static char *s_type = "sdcc"; + +/** + * enum pfk_kc_entry_state - state of the entry inside kc table + * + * @FREE: entry is free + * @ACTIVE_ICE_PRELOAD: entry is actively used by ICE engine + and cannot be used by others. SCM call + to load key to ICE is pending to be performed + * @ACTIVE_ICE_LOADED: entry is actively used by ICE engine and + cannot be used by others. SCM call to load the + key to ICE was successfully executed and key is + now loaded + * @INACTIVE_INVALIDATING: entry is being invalidated during file close + and cannot be used by others until invalidation + is complete + * @INACTIVE: entry's key is already loaded, but is not + currently being used. It can be re-used for + optimization and to avoid SCM call cost or + it can be taken by another key if there are + no FREE entries + * @SCM_ERROR: error occurred while scm call was performed to + load the key to ICE + */ +enum pfk_kc_entry_state { + FREE, + ACTIVE_ICE_PRELOAD, + ACTIVE_ICE_LOADED, + INACTIVE_INVALIDATING, + INACTIVE, + SCM_ERROR +}; + +struct kc_entry { + unsigned char key[PFK_MAX_KEY_SIZE]; + size_t key_size; + + unsigned char salt[PFK_MAX_SALT_SIZE]; + size_t salt_size; + + u64 time_stamp; + u32 key_index; + + struct task_struct *thread_pending; + + enum pfk_kc_entry_state state; + + /* ref count for the number of requests in the HW queue for this key */ + int loaded_ref_cnt; + int scm_error; +}; + +static struct kc_entry kc_table[PFK_KC_TABLE_SIZE]; + +/** + * kc_is_ready() - driver is initialized and ready. + * + * Return: true if the key cache is ready. + */ +static inline bool kc_is_ready(void) +{ + return kc_ready; +} + +static inline void kc_spin_lock(void) +{ + spin_lock_irqsave(&kc_lock, flags); +} + +static inline void kc_spin_unlock(void) +{ + spin_unlock_irqrestore(&kc_lock, flags); +} + +/** + * kc_entry_is_available() - checks whether the entry is available + * + * Return true if it is , false otherwise or if invalid + * Should be invoked under spinlock + */ +static bool kc_entry_is_available(const struct kc_entry *entry) +{ + if (!entry) + return false; + + return (entry->state == FREE || entry->state == INACTIVE); +} + +/** + * kc_entry_wait_till_available() - waits till entry is available + * + * Returns 0 in case of success or -ERESTARTSYS if the wait was interrupted + * by signal + * + * Should be invoked under spinlock + */ +static int kc_entry_wait_till_available(struct kc_entry *entry) +{ + int res = 0; + + while (!kc_entry_is_available(entry)) { + set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + res = -ERESTARTSYS; + break; + } + /* assuming only one thread can try to invalidate + * the same entry + */ + entry->thread_pending = current; + kc_spin_unlock(); + schedule(); + kc_spin_lock(); + } + set_current_state(TASK_RUNNING); + + return res; +} + +/** + * kc_entry_start_invalidating() - moves entry to state + * INACTIVE_INVALIDATING + * If entry is in use, waits till + * it gets available + * @entry: pointer to entry + * + * Return 0 in case of success, otherwise error + * Should be invoked under spinlock + */ +static int kc_entry_start_invalidating(struct kc_entry *entry) +{ + int res; + + res = kc_entry_wait_till_available(entry); + if (res) + return res; + + entry->state = INACTIVE_INVALIDATING; + + return 0; +} + +/** + * kc_entry_finish_invalidating() - moves entry to state FREE + * wakes up all the tasks waiting + * on it + * + * @entry: pointer to entry + * + * Return 0 in case of success, otherwise error + * Should be invoked under spinlock + */ +static void kc_entry_finish_invalidating(struct kc_entry *entry) +{ + if (!entry) + return; + + if (entry->state != INACTIVE_INVALIDATING) + return; + + entry->state = FREE; +} + +/** + * kc_min_entry() - compare two entries to find one with minimal time + * @a: ptr to the first entry. If NULL the other entry will be returned + * @b: pointer to the second entry + * + * Return the entry which timestamp is the minimal, or b if a is NULL + */ +static inline struct kc_entry *kc_min_entry(struct kc_entry *a, + struct kc_entry *b) +{ + if (!a) + return b; + + if (time_before64(b->time_stamp, a->time_stamp)) + return b; + + return a; +} + +/** + * kc_entry_at_index() - return entry at specific index + * @index: index of entry to be accessed + * + * Return entry + * Should be invoked under spinlock + */ +static struct kc_entry *kc_entry_at_index(int index) +{ + return &(kc_table[index]); +} + +/** + * kc_find_key_at_index() - find kc entry starting at specific index + * @key: key to look for + * @key_size: the key size + * @salt: salt to look for + * @salt_size: the salt size + * @sarting_index: index to start search with, if entry found, updated with + * index of that entry + * + * Return entry or NULL in case of error + * Should be invoked under spinlock + */ +static struct kc_entry *kc_find_key_at_index(const unsigned char *key, + size_t key_size, const unsigned char *salt, size_t salt_size, + int *starting_index) +{ + struct kc_entry *entry = NULL; + int i = 0; + + for (i = *starting_index; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + + if (salt != NULL) { + if (entry->salt_size != salt_size) + continue; + + if (memcmp(entry->salt, salt, salt_size) != 0) + continue; + } + + if (entry->key_size != key_size) + continue; + + if (memcmp(entry->key, key, key_size) == 0) { + *starting_index = i; + return entry; + } + } + + return NULL; +} + +/** + * kc_find_key() - find kc entry + * @key: key to look for + * @key_size: the key size + * @salt: salt to look for + * @salt_size: the salt size + * + * Return entry or NULL in case of error + * Should be invoked under spinlock + */ +static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + int index = 0; + + return kc_find_key_at_index(key, key_size, salt, salt_size, &index); +} + +/** + * kc_find_oldest_entry_non_locked() - finds the entry with minimal timestamp + * that is not locked + * + * Returns entry with minimal timestamp. Empty entries have timestamp + * of 0, therefore they are returned first. + * If all the entries are locked, will return NULL + * Should be invoked under spin lock + */ +static struct kc_entry *kc_find_oldest_entry_non_locked(void) +{ + struct kc_entry *curr_min_entry = NULL; + struct kc_entry *entry = NULL; + int i = 0; + + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + + if (entry->state == FREE) + return entry; + + if (entry->state == INACTIVE) + curr_min_entry = kc_min_entry(curr_min_entry, entry); + } + + return curr_min_entry; +} + +/** + * kc_update_timestamp() - updates timestamp of entry to current + * + * @entry: entry to update + * + */ +static void kc_update_timestamp(struct kc_entry *entry) +{ + if (!entry) + return; + + entry->time_stamp = get_jiffies_64(); +} + +/** + * kc_clear_entry() - clear the key from entry and mark entry not in use + * + * @entry: pointer to entry + * + * Should be invoked under spinlock + */ +static void kc_clear_entry(struct kc_entry *entry) +{ + if (!entry) + return; + + memset(entry->key, 0, entry->key_size); + memset(entry->salt, 0, entry->salt_size); + + entry->key_size = 0; + entry->salt_size = 0; + + entry->time_stamp = 0; + entry->scm_error = 0; + + entry->state = FREE; + + entry->loaded_ref_cnt = 0; + entry->thread_pending = NULL; +} + +/** + * kc_update_entry() - replaces the key in given entry and + * loads the new key to ICE + * + * @entry: entry to replace key in + * @key: key + * @key_size: key_size + * @salt: salt + * @salt_size: salt_size + * + * The previous key is securely released and wiped, the new one is loaded + * to ICE. + * Should be invoked under spinlock + */ +static int kc_update_entry(struct kc_entry *entry, const unsigned char *key, + size_t key_size, const unsigned char *salt, size_t salt_size) +{ + int ret; + + kc_clear_entry(entry); + + memcpy(entry->key, key, key_size); + entry->key_size = key_size; + + memcpy(entry->salt, salt, salt_size); + entry->salt_size = salt_size; + + /* Mark entry as no longer free before releasing the lock */ + entry->state = ACTIVE_ICE_PRELOAD; + kc_spin_unlock(); + + ret = qti_pfk_ice_set_key(entry->key_index, entry->key, + entry->salt, s_type); + + kc_spin_lock(); + return ret; +} + +/** + * pfk_kc_init() - init function + * + * Return 0 in case of success, error otherwise + */ +int pfk_kc_init(void) +{ + int i = 0; + struct kc_entry *entry = NULL; + + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + entry->key_index = PFK_KC_STARTING_INDEX + i; + } + kc_ready = true; + kc_spin_unlock(); + return 0; +} + +/** + * pfk_kc_denit() - deinit function + * + * Return 0 in case of success, error otherwise + */ +int pfk_kc_deinit(void) +{ + int res = pfk_kc_clear(); + + kc_ready = false; + return res; +} + +/** + * pfk_kc_load_key_start() - retrieve the key from cache or add it if + * it's not there and return the ICE hw key index in @key_index. + * @key: pointer to the key + * @key_size: the size of the key + * @salt: pointer to the salt + * @salt_size: the size of the salt + * @key_index: the pointer to key_index where the output will be stored + * @async: whether scm calls are allowed in the caller context + * + * If key is present in cache, than the key_index will be retrieved from cache. + * If it is not present, the oldest entry from kc table will be evicted, + * the key will be loaded to ICE via QSEE to the index that is the evicted + * entry number and stored in cache. + * Entry that is going to be used is marked as being used, it will mark + * as not being used when ICE finishes using it and pfk_kc_load_key_end + * will be invoked. + * As QSEE calls can only be done from a non-atomic context, when @async flag + * is set to 'false', it specifies that it is ok to make the calls in the + * current context. Otherwise, when @async is set, the caller should retry the + * call again from a different context, and -EAGAIN error will be returned. + * + * Return 0 in case of success, error otherwise + */ +int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size, u32 *key_index, + bool async) +{ + int ret = 0; + struct kc_entry *entry = NULL; + bool entry_exists = false; + + if (!kc_is_ready()) + return -ENODEV; + + if (!key || !salt || !key_index) { + pr_err("%s key/salt/key_index NULL\n", __func__); + return -EINVAL; + } + + if (key_size != PFK_KC_KEY_SIZE) { + pr_err("unsupported key size %zu\n", key_size); + return -EINVAL; + } + + if (salt_size != PFK_KC_SALT_SIZE) { + pr_err("unsupported salt size %zu\n", salt_size); + return -EINVAL; + } + + kc_spin_lock(); + + entry = kc_find_key(key, key_size, salt, salt_size); + if (!entry) { + if (async) { + pr_debug("%s task will populate entry\n", __func__); + kc_spin_unlock(); + return -EAGAIN; + } + + entry = kc_find_oldest_entry_non_locked(); + if (!entry) { + /* could not find a single non locked entry, + * return EBUSY to upper layers so that the + * request will be rescheduled + */ + kc_spin_unlock(); + return -EBUSY; + } + } else { + entry_exists = true; + } + + pr_debug("entry with index %d is in state %d\n", + entry->key_index, entry->state); + + switch (entry->state) { + case (INACTIVE): + if (entry_exists) { + kc_update_timestamp(entry); + entry->state = ACTIVE_ICE_LOADED; + + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { + entry->loaded_ref_cnt++; + } + break; + } + case (FREE): + ret = kc_update_entry(entry, key, key_size, salt, salt_size); + if (ret) { + entry->state = SCM_ERROR; + entry->scm_error = ret; + pr_err("%s: key load error (%d)\n", __func__, ret); + } else { + kc_update_timestamp(entry); + entry->state = ACTIVE_ICE_LOADED; + + /* + * In case of UFS only increase ref cnt for async calls, + * sync calls from within work thread do not pass + * requests further to HW + */ + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { + entry->loaded_ref_cnt++; + } + } + break; + case (ACTIVE_ICE_PRELOAD): + case (INACTIVE_INVALIDATING): + ret = -EAGAIN; + break; + case (ACTIVE_ICE_LOADED): + kc_update_timestamp(entry); + + if (!strcmp(s_type, (char *)PFK_UFS)) { + if (async) + entry->loaded_ref_cnt++; + } else { + entry->loaded_ref_cnt++; + } + break; + case(SCM_ERROR): + ret = entry->scm_error; + kc_clear_entry(entry); + entry->state = FREE; + break; + default: + pr_err("invalid state %d for entry with key index %d\n", + entry->state, entry->key_index); + ret = -EINVAL; + } + + *key_index = entry->key_index; + kc_spin_unlock(); + + return ret; +} + +/** + * pfk_kc_load_key_end() - finish the process of key loading that was started + * by pfk_kc_load_key_start + * by marking the entry as not + * being in use + * @key: pointer to the key + * @key_size: the size of the key + * @salt: pointer to the salt + * @salt_size: the size of the salt + * + */ +void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + struct kc_entry *entry = NULL; + struct task_struct *tmp_pending = NULL; + int ref_cnt = 0; + + if (!kc_is_ready()) + return; + + if (!key || !salt) + return; + + if (key_size != PFK_KC_KEY_SIZE) + return; + + if (salt_size != PFK_KC_SALT_SIZE) + return; + + kc_spin_lock(); + + entry = kc_find_key(key, key_size, salt, salt_size); + if (!entry) { + kc_spin_unlock(); + pr_err("internal error, there should an entry to unlock\n"); + + return; + } + ref_cnt = --entry->loaded_ref_cnt; + + if (ref_cnt < 0) + pr_err("internal error, ref count should never be negative\n"); + + if (!ref_cnt) { + entry->state = INACTIVE; + /* + * wake-up invalidation if it's waiting + * for the entry to be released + */ + if (entry->thread_pending) { + tmp_pending = entry->thread_pending; + entry->thread_pending = NULL; + + kc_spin_unlock(); + wake_up_process(tmp_pending); + return; + } + } + + kc_spin_unlock(); +} + +/** + * pfk_kc_remove_key() - remove the key from cache and from ICE engine + * @key: pointer to the key + * @key_size: the size of the key + * @salt: pointer to the key + * @salt_size: the size of the key + * + * Return 0 in case of success, error otherwise (also in case of non + * (existing key) + */ +int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size) +{ + struct kc_entry *entry = NULL; + int res = 0; + + if (!kc_is_ready()) + return -ENODEV; + + if (!key) + return -EINVAL; + + if (!salt) + return -EINVAL; + + if (key_size != PFK_KC_KEY_SIZE) + return -EINVAL; + + if (salt_size != PFK_KC_SALT_SIZE) + return -EINVAL; + + kc_spin_lock(); + + entry = kc_find_key(key, key_size, salt, salt_size); + if (!entry) { + pr_debug("%s: key does not exist\n", __func__); + kc_spin_unlock(); + return -EINVAL; + } + + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + return res; + } + kc_clear_entry(entry); + + kc_spin_unlock(); + + qti_pfk_ice_invalidate_key(entry->key_index, s_type); + + kc_spin_lock(); + kc_entry_finish_invalidating(entry); + kc_spin_unlock(); + + return 0; +} + +/** + * pfk_kc_remove_key() - remove the key from cache and from ICE engine + * when no salt is available. Will only search key part, if there are several, + * all will be removed + * + * @key: pointer to the key + * @key_size: the size of the key + * + * Return 0 in case of success, error otherwise (also for non-existing key) + */ +int pfk_kc_remove_key(const unsigned char *key, size_t key_size) +{ + struct kc_entry *entry = NULL; + int index = 0; + int temp_indexes[PFK_KC_TABLE_SIZE] = {0}; + int temp_indexes_size = 0; + int i = 0; + int res = 0; + + if (!kc_is_ready()) + return -ENODEV; + + if (!key) + return -EINVAL; + + if (key_size != PFK_KC_KEY_SIZE) + return -EINVAL; + + memset(temp_indexes, -1, sizeof(temp_indexes)); + + kc_spin_lock(); + + entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); + if (!entry) { + pr_err("%s: key does not exist\n", __func__); + kc_spin_unlock(); + return -EINVAL; + } + + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + return res; + } + + temp_indexes[temp_indexes_size++] = index; + kc_clear_entry(entry); + + /* let's clean additional entries with the same key if there are any */ + do { + index++; + entry = kc_find_key_at_index(key, key_size, NULL, 0, &index); + if (!entry) + break; + + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + goto out; + } + + temp_indexes[temp_indexes_size++] = index; + + kc_clear_entry(entry); + + + } while (true); + + kc_spin_unlock(); + + temp_indexes_size--; + for (i = temp_indexes_size; i >= 0 ; i--) + qti_pfk_ice_invalidate_key( + kc_entry_at_index(temp_indexes[i])->key_index, + s_type); + + /* fall through */ + res = 0; + +out: + kc_spin_lock(); + for (i = temp_indexes_size; i >= 0 ; i--) + kc_entry_finish_invalidating( + kc_entry_at_index(temp_indexes[i])); + kc_spin_unlock(); + + return res; +} + +/** + * pfk_kc_clear() - clear the table and remove all keys from ICE + * + * Return 0 on success, error otherwise + * + */ +int pfk_kc_clear(void) +{ + struct kc_entry *entry = NULL; + int i = 0; + int res = 0; + + if (!kc_is_ready()) + return -ENODEV; + + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + res = kc_entry_start_invalidating(entry); + if (res != 0) { + kc_spin_unlock(); + goto out; + } + kc_clear_entry(entry); + } + kc_spin_unlock(); + + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) + qti_pfk_ice_invalidate_key(kc_entry_at_index(i)->key_index, + s_type); + + /* fall through */ + res = 0; +out: + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) + kc_entry_finish_invalidating(kc_entry_at_index(i)); + kc_spin_unlock(); + + return res; +} + +/** + * pfk_kc_clear_on_reset() - clear the table and remove all keys from ICE + * The assumption is that at this point we don't have any pending transactions + * Also, there is no need to clear keys from ICE + * + * Return 0 on success, error otherwise + * + */ +void pfk_kc_clear_on_reset(void) +{ + struct kc_entry *entry = NULL; + int i = 0; + + if (!kc_is_ready()) + return; + + kc_spin_lock(); + for (i = 0; i < PFK_KC_TABLE_SIZE; i++) { + entry = kc_entry_at_index(i); + kc_clear_entry(entry); + } + kc_spin_unlock(); +} + +static int pfk_kc_find_storage_type(char **device) +{ + char boot[20] = {'\0'}; + char *match = (char *)strnstr(saved_command_line, + "androidboot.bootdevice=", + strlen(saved_command_line)); + if (match) { + memcpy(boot, (match + strlen("androidboot.bootdevice=")), + sizeof(boot) - 1); + if (strnstr(boot, PFK_UFS, strlen(boot))) + *device = PFK_UFS; + + return 0; + } + return -EINVAL; +} + +static int __init pfk_kc_pre_init(void) +{ + return pfk_kc_find_storage_type(&s_type); +} + +static void __exit pfk_kc_exit(void) +{ + s_type = NULL; +} + +module_init(pfk_kc_pre_init); +module_exit(pfk_kc_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Per-File-Key-KC driver"); diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h new file mode 100644 index 000000000000..6adeee2259cd --- /dev/null +++ b/security/pfe/pfk_kc.h @@ -0,0 +1,33 @@ +/* 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_KC_H_ +#define PFK_KC_H_ + +#include + +int pfk_kc_init(void); +int pfk_kc_deinit(void); +int pfk_kc_load_key_start(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size, u32 *key_index, + bool async); +void pfk_kc_load_key_end(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size); +int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size, + const unsigned char *salt, size_t salt_size); +int pfk_kc_remove_key(const unsigned char *key, size_t key_size); +int pfk_kc_clear(void); +void pfk_kc_clear_on_reset(void); +extern char *saved_command_line; + + +#endif /* PFK_KC_H_ */ diff --git a/security/security.c b/security/security.c index e43c50cbdcbf..35c8dcec61f3 100644 --- a/security/security.c +++ b/security/security.c @@ -525,6 +525,14 @@ 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) +{ + if (unlikely(IS_PRIVATE(dir))) + return 0; + return call_int_hook(inode_post_create, 0, dir, dentry, mode); +} + int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { @@ -1700,6 +1708,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init = { .inode_init_security = LIST_HEAD_INIT(security_hook_heads.inode_init_security), .inode_create = LIST_HEAD_INIT(security_hook_heads.inode_create), + .inode_post_create = + LIST_HEAD_INIT(security_hook_heads.inode_post_create), .inode_link = LIST_HEAD_INIT(security_hook_heads.inode_link), .inode_unlink = LIST_HEAD_INIT(security_hook_heads.inode_unlink), .inode_symlink = diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 43535cdd4c37..60cdcf44da18 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -25,8 +25,9 @@ #include #include #include -#include "flask.h" -#include "avc.h" +//#include "flask.h" +//#include "avc.h" +#include "security.h" struct task_security_struct { u32 osid; /* SID prior to last execve */ @@ -52,6 +53,8 @@ struct inode_security_struct { u32 sid; /* SID of this object */ 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 */ struct mutex lock; }; diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 308a286c6cbe..b8e98c111b2f 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -12,7 +12,6 @@ #include #include #include -#include "flask.h" #define SECSID_NULL 0x00000000 /* unspecified SID */ #define SECSID_WILD 0xffffffff /* wildcard SID */