From patchwork Sun Jan 1 05:06:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086329 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BE811C54EBC for ; Sun, 1 Jan 2023 05:13:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229999AbjAAFN7 (ORCPT ); Sun, 1 Jan 2023 00:13:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232556AbjAAFNt (ORCPT ); Sun, 1 Jan 2023 00:13:49 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E95346410 for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 6B999825FF; Sun, 1 Jan 2023 00:06:31 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549591; bh=Qv1TeX542er9NMo8QNyHPEGrBDJKAGVwPmLI7IoKOyw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=llIgTTnA0i3tW7VDJLT8XZpGMe1rMCaL2aSShVrM5+kC+jYdwPjWKSKzVD42966bL Hzt3pOdSYmifFcj+gy68C93LpPusSgV2rao1XeNKKJRD8O1MlnSgy1VYjlN44mtD02 EIBEckkAJolevWzYSYoRnmIKscQQQgHXDWCCKfK28vynOeULahMSsoPhXR+QST51LO TxLhU4An4B6F3KR4Nteu4kf6oEV8MmlXQa/Wsw6xMAcGNmb2+w2xGXW9Myq18Vxo0V B2dm9UreXEgT88DeQu1h7r/iTGhDqsXXUdkXe5O8al1twT3teMAfRyn1h5YKYHa/XF d/DVsFfOzXWJg== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 01/17] fscrypt: factor accessing inode->i_crypt_info Date: Sun, 1 Jan 2023 00:06:05 -0500 Message-Id: <1d69320524e31f4f0ece20ba3c0d2b8244228f4f.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org Currently, inode->i_crypt_info is accessed directly in many places; the initial setting occurs in one place, via cmpxchg_release, and the initial access is abstracted into fscrypt_get_info() which uses smp_load_acquire(), but there are many direct accesses. While many of them follow calls to fscrypt_get_info() on the same thread, verifying this is not always trivial. For instance, fscrypt_crypt_block() does not obviously follow a call to fscrypt_get_info() on the same cpu; if some other mechanism does not ensure a memory barrier, it is conceivable that a filesystem could call fscrypt_crypt_block() on a cpu which had an old (NULL) i_crypt_info cached. Even if the cpu does READ_ONCE(i_crypt_info), I believe it's theoretically possible for it to see the old NULL value, since this could be happening on a cpu which did not do the smp_load_acquire(). (I may be misunderstanding, but memory-barriers.txt says that only the cpus involved in an acquire/release chain are guaranteed to see the correct order of operations, which seems to imply that a cpu which does not do an acquire may be able to see a memory value from before the release.) For safety, then, and so each site doesn't need to be individually evaluated, this change factors all accesses of i_crypt_info to go through fscrypt_get_info(), ensuring every access uses acquire and is thus paired against an appropriate release. (The same treatment is not necessary for setting i_crypt_info; the only unprotected setting is during inode cleanup, which is inevitably followed by freeing the inode; there are no uses past the unprotected setting possible.) Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 2 +- fs/crypto/fname.c | 9 +++++---- fs/crypto/hooks.c | 2 +- fs/crypto/inline_crypt.c | 10 +++++----- fs/crypto/keysetup.c | 2 +- fs/crypto/policy.c | 6 +++--- 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index e78be66bbf01..2efd1da9df8d 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -107,7 +107,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist dst, src; - struct fscrypt_info *ci = inode->i_crypt_info; + struct fscrypt_info *ci = fscrypt_get_info(inode); struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; int res = 0; diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 12bd61d20f69..6efb53cba523 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -100,7 +100,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); - const struct fscrypt_info *ci = inode->i_crypt_info; + const struct fscrypt_info *ci = fscrypt_get_info(inode); struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; union fscrypt_iv iv; struct scatterlist sg; @@ -157,7 +157,7 @@ static int fname_decrypt(const struct inode *inode, struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist src_sg, dst_sg; - const struct fscrypt_info *ci = inode->i_crypt_info; + const struct fscrypt_info *ci = fscrypt_get_info(inode); struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; union fscrypt_iv iv; int res; @@ -299,7 +299,8 @@ bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, u32 max_len, u32 *encrypted_len_ret) { - return __fscrypt_fname_encrypted_size(&inode->i_crypt_info->ci_policy, + struct fscrypt_info *ci = fscrypt_get_info(inode); + return __fscrypt_fname_encrypted_size(&ci->ci_policy, orig_len, max_len, encrypted_len_ret); } @@ -568,7 +569,7 @@ EXPORT_SYMBOL_GPL(fscrypt_match_name); */ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name) { - const struct fscrypt_info *ci = dir->i_crypt_info; + const struct fscrypt_info *ci = fscrypt_get_info(dir); WARN_ON(!ci->ci_dirhash_key_initialized); diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 7b8c5a1104b5..b605660fb3f1 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -152,7 +152,7 @@ int fscrypt_prepare_setflags(struct inode *inode, err = fscrypt_require_key(inode); if (err) return err; - ci = inode->i_crypt_info; + ci = fscrypt_get_info(inode); if (ci->ci_policy.version != FSCRYPT_POLICY_V2) return -EINVAL; mk = ci->ci_master_key; diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index cea8b14007e6..4b1373715018 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -232,7 +232,7 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb, bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode) { - return inode->i_crypt_info->ci_inlinecrypt; + return fscrypt_get_info(inode)->ci_inlinecrypt; } EXPORT_SYMBOL_GPL(__fscrypt_inode_uses_inline_crypto); @@ -274,7 +274,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, if (!fscrypt_inode_uses_inline_crypto(inode)) return; - ci = inode->i_crypt_info; + ci = fscrypt_get_info(inode); fscrypt_generate_dun(ci, first_lblk, dun); bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask); @@ -364,10 +364,10 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, * uses the same pointer. I.e., there's currently no need to support * merging requests where the keys are the same but the pointers differ. */ - if (bc->bc_key != inode->i_crypt_info->ci_enc_key.blk_key) + if (bc->bc_key != fscrypt_get_info(inode)->ci_enc_key.blk_key) return false; - fscrypt_generate_dun(inode->i_crypt_info, next_lblk, next_dun); + fscrypt_generate_dun(fscrypt_get_info(inode), next_lblk, next_dun); return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun); } EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio); @@ -469,7 +469,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) if (nr_blocks <= 1) return nr_blocks; - ci = inode->i_crypt_info; + ci = fscrypt_get_info(inode); if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_blocks; diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index f7407071a952..ad56192305b3 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -706,7 +706,7 @@ EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); */ void fscrypt_put_encryption_info(struct inode *inode) { - put_crypt_info(inode->i_crypt_info); + put_crypt_info(fscrypt_get_info(inode)); inode->i_crypt_info = NULL; } EXPORT_SYMBOL(fscrypt_put_encryption_info); diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 46757c3052ef..ccab27afd3cc 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -687,7 +687,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir) err = fscrypt_require_key(dir); if (err) return ERR_PTR(err); - return &dir->i_crypt_info->ci_policy; + return &fscrypt_get_info(dir)->ci_policy; } return fscrypt_get_dummy_policy(dir->i_sb); @@ -706,7 +706,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir) */ int fscrypt_context_for_new_inode(void *ctx, struct inode *inode) { - struct fscrypt_info *ci = inode->i_crypt_info; + struct fscrypt_info *ci = fscrypt_get_info(inode); BUILD_BUG_ON(sizeof(union fscrypt_context) != FSCRYPT_SET_CONTEXT_MAX_SIZE); @@ -731,7 +731,7 @@ EXPORT_SYMBOL_GPL(fscrypt_context_for_new_inode); */ int fscrypt_set_context(struct inode *inode, void *fs_data) { - struct fscrypt_info *ci = inode->i_crypt_info; + struct fscrypt_info *ci = fscrypt_get_info(inode); union fscrypt_context ctx; int ctxsize; From patchwork Sun Jan 1 05:06:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086318 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0B91FC3DA79 for ; Sun, 1 Jan 2023 05:13:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230152AbjAAFNu (ORCPT ); Sun, 1 Jan 2023 00:13:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50806 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229703AbjAAFNr (ORCPT ); Sun, 1 Jan 2023 00:13:47 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D8CF863FF for ; Sat, 31 Dec 2022 21:13:46 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id A07DE82612; Sun, 1 Jan 2023 00:06:33 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549594; bh=/0KsiKITv755odE4hV+51/rBkhkC+Aktg2KUCYeJUeg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pn2IP1cHuuhaTvCbZ7JQUPqQRmYW8oQVPIlygdpoyhRJIRSRNBDV4Y8MEoDrNgNZI lQikXEHs7BkFLGTzELhnJRp7kx60pXN7YQG8ih4TZGuYrVqQ/G8Wjp9szIItVo3ZUg pWSBXyaCjG+Jr1hYsvW3LK9xSFveHyr17+GKfcsyw6wIFec64z4ZVhJMW/6z/JzwOL Oc/trRqo+2VUeeiQelB56/tGvmxg6SEJNbvgGeM3LV5ObA39H3VPucSqCnM223SwFH i6L67gkRoExQy1Si4IcSUn6pdTW4xUSy3NjbBPru2O4wEnGf81aWMCuO2yzrJVA/k+ jt806YvZ7I3Og== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 02/17] fscrypt: separate getting info for a specific block Date: Sun, 1 Jan 2023 00:06:06 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org For filesystems using extent-based encryption, the content of each extent will be encrypted with a different fscrypt_info for each extent. Meanwhile, directories and symlinks will continue to use the fscrypt_info for the inode. Therefore, merely calling fscrypt_get_info() will be insufficient; the caller must specifically request the inode info or the info for a specific block. Add that distinction, adding both fscrypt_get_inode_info() and fscrypt_get_lblk_info(), and updating all callsites to call the appropriate one. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 3 ++- fs/crypto/fname.c | 8 +++---- fs/crypto/fscrypt_private.h | 46 +++++++++++++++++++++++++++++++++++++ fs/crypto/hooks.c | 2 +- fs/crypto/inline_crypt.c | 12 ++++++---- fs/crypto/keysetup.c | 4 ++-- fs/crypto/policy.c | 8 +++---- 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 2efd1da9df8d..41c60c60b74c 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -107,7 +107,8 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist dst, src; - struct fscrypt_info *ci = fscrypt_get_info(inode); + struct fscrypt_info *ci = fscrypt_get_lblk_info(inode, lblk_num, NULL, + NULL); struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; int res = 0; diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 6efb53cba523..e1474f24d014 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -100,7 +100,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); - const struct fscrypt_info *ci = fscrypt_get_info(inode); + const struct fscrypt_info *ci = fscrypt_get_inode_info(inode); struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; union fscrypt_iv iv; struct scatterlist sg; @@ -157,7 +157,7 @@ static int fname_decrypt(const struct inode *inode, struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist src_sg, dst_sg; - const struct fscrypt_info *ci = fscrypt_get_info(inode); + const struct fscrypt_info *ci = fscrypt_get_inode_info(inode); struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; union fscrypt_iv iv; int res; @@ -299,7 +299,7 @@ bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, u32 max_len, u32 *encrypted_len_ret) { - struct fscrypt_info *ci = fscrypt_get_info(inode); + struct fscrypt_info *ci = fscrypt_get_inode_info(inode); return __fscrypt_fname_encrypted_size(&ci->ci_policy, orig_len, max_len, encrypted_len_ret); @@ -569,7 +569,7 @@ EXPORT_SYMBOL_GPL(fscrypt_match_name); */ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name) { - const struct fscrypt_info *ci = fscrypt_get_info(dir); + const struct fscrypt_info *ci = fscrypt_get_inode_info(dir); WARN_ON(!ci->ci_dirhash_key_initialized); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index d5f68a0c5d15..2df28c6fe558 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -262,6 +262,52 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; +/** + * fscrypt_get_inode_info() - get the fscrypt_info for a particular inode + * + * @inode: the inode in question + * + * For inode-based encryption, this will return the same info as + * fscrypt_get_lblk_info(). For extent-based encryption, for extentless + * files this will return the inode's info, otherwise it will return the info + * that new extents should inherit. + * + * Return: the appropriate fscrypt_info if there is one, else NULL. + */ +static inline struct fscrypt_info * +fscrypt_get_inode_info(const struct inode *inode) +{ + return fscrypt_get_info(inode); +} + +/** + * fscrypt_get_lblk_info() - get the fscrypt_info to crypt a particular block + * + * @inode: the inode to which the block belongs + * @lblk: the offset of the block within the file which the inode + * references + * @offset: a pointer to return the offset of the block from the first block + * that the info covers. For inode-based encryption, this will + * always be @lblk; for extent-based encryption, this will be in + * the range [0, lblk]. Can be NULL + * @extent_len: a pointer to return the minimum number of lblks starting at + * this offset which also belong to the same fscrypt_info. Can be + * NULL + * + * Return: the appropriate fscrypt_info if there is one, else NULL. + */ +static inline struct fscrypt_info * +fscrypt_get_lblk_info(const struct inode *inode, u64 lblk, u64 *offset, + u64 *extent_len) +{ + if (offset) + *offset = lblk; + if (extent_len) + *extent_len = U64_MAX; + + return fscrypt_get_info(inode); +} + /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; int fscrypt_initialize(unsigned int cop_flags); diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index b605660fb3f1..929749c77440 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -152,7 +152,7 @@ int fscrypt_prepare_setflags(struct inode *inode, err = fscrypt_require_key(inode); if (err) return err; - ci = fscrypt_get_info(inode); + ci = fscrypt_get_inode_info(inode); if (ci->ci_policy.version != FSCRYPT_POLICY_V2) return -EINVAL; mk = ci->ci_master_key; diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 4b1373715018..56d69b231875 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -232,7 +232,7 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb, bool __fscrypt_inode_uses_inline_crypto(const struct inode *inode) { - return fscrypt_get_info(inode)->ci_inlinecrypt; + return fscrypt_get_inode_info(inode)->ci_inlinecrypt; } EXPORT_SYMBOL_GPL(__fscrypt_inode_uses_inline_crypto); @@ -274,7 +274,7 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, if (!fscrypt_inode_uses_inline_crypto(inode)) return; - ci = fscrypt_get_info(inode); + ci = fscrypt_get_lblk_info(inode, first_lblk, NULL, NULL); fscrypt_generate_dun(ci, first_lblk, dun); bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask); @@ -353,21 +353,23 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, { const struct bio_crypt_ctx *bc = bio->bi_crypt_context; u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + struct fscrypt_info *ci; if (!!bc != fscrypt_inode_uses_inline_crypto(inode)) return false; if (!bc) return true; + ci = fscrypt_get_lblk_info(inode, next_lblk, NULL, NULL); /* * Comparing the key pointers is good enough, as all I/O for each key * uses the same pointer. I.e., there's currently no need to support * merging requests where the keys are the same but the pointers differ. */ - if (bc->bc_key != fscrypt_get_info(inode)->ci_enc_key.blk_key) + if (bc->bc_key != ci->ci_enc_key.blk_key) return false; - fscrypt_generate_dun(fscrypt_get_info(inode), next_lblk, next_dun); + fscrypt_generate_dun(ci, next_lblk, next_dun); return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun); } EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio); @@ -469,7 +471,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) if (nr_blocks <= 1) return nr_blocks; - ci = fscrypt_get_info(inode); + ci = fscrypt_get_lblk_info(inode, lblk, NULL, NULL); if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_blocks; diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index ad56192305b3..87f28d666602 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -706,7 +706,7 @@ EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); */ void fscrypt_put_encryption_info(struct inode *inode) { - put_crypt_info(fscrypt_get_info(inode)); + put_crypt_info(fscrypt_get_inode_info(inode)); inode->i_crypt_info = NULL; } EXPORT_SYMBOL(fscrypt_put_encryption_info); @@ -739,7 +739,7 @@ EXPORT_SYMBOL(fscrypt_free_inode); */ int fscrypt_drop_inode(struct inode *inode) { - const struct fscrypt_info *ci = fscrypt_get_info(inode); + const struct fscrypt_info *ci = fscrypt_get_inode_info(inode); /* * If ci is NULL, then the inode doesn't have an encryption key set up diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index ccab27afd3cc..e7de4872d375 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -398,7 +398,7 @@ static int fscrypt_get_policy(struct inode *inode, union fscrypt_policy *policy) union fscrypt_context ctx; int ret; - ci = fscrypt_get_info(inode); + ci = fscrypt_get_inode_info(inode); if (ci) { /* key available, use the cached policy */ *policy = ci->ci_policy; @@ -687,7 +687,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir) err = fscrypt_require_key(dir); if (err) return ERR_PTR(err); - return &fscrypt_get_info(dir)->ci_policy; + return &fscrypt_get_inode_info(dir)->ci_policy; } return fscrypt_get_dummy_policy(dir->i_sb); @@ -706,7 +706,7 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir) */ int fscrypt_context_for_new_inode(void *ctx, struct inode *inode) { - struct fscrypt_info *ci = fscrypt_get_info(inode); + struct fscrypt_info *ci = fscrypt_get_inode_info(inode); BUILD_BUG_ON(sizeof(union fscrypt_context) != FSCRYPT_SET_CONTEXT_MAX_SIZE); @@ -731,7 +731,7 @@ EXPORT_SYMBOL_GPL(fscrypt_context_for_new_inode); */ int fscrypt_set_context(struct inode *inode, void *fs_data) { - struct fscrypt_info *ci = fscrypt_get_info(inode); + struct fscrypt_info *ci = fscrypt_get_inode_info(inode); union fscrypt_context ctx; int ctxsize; From patchwork Sun Jan 1 05:06:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086323 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B7CE0C54E76 for ; Sun, 1 Jan 2023 05:13:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229947AbjAAFN5 (ORCPT ); Sun, 1 Jan 2023 00:13:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50784 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232359AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D7B6663FB for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 6994682619; Sun, 1 Jan 2023 00:06:35 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549595; bh=L8Z9jfs1qqxz9SQqCfkx1PISHOTf+3H/IZb2IdVh3RE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=No+Mw/CX+0ZyaAc+EYiIDWaJ6KsyXgQvOHaR2EccacW3RMBbZQdqgGzwkAddaa+xI QHq3peWOI0ANYkN3ZJVcnsdHpNM2En6owtcpXMZApMeyH/XYRbwtFATXEVq0M224ls qE89Cb1VTvoqspGl7qRbTHY3AvgoSldFiKlwNmhOoZoXrVa/TjB1KCEwmgVVn7nLni 3LCLmvSDB7CNhx99KAiQRomYlpA7JmDkphCGASw/dr4M8BUTDLP5F2B53IYqITC+Nx 0m/sp1tf2P40f+JG8xvFuHWCNz9nyx2O5OImuJFmd/QUBrQEWxanAMhDMBN2qeqgO5 lQICohWqliIoA== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 03/17] fscrypt: adjust effective lblks based on extents Date: Sun, 1 Jan 2023 00:06:07 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org If a filesystem uses extent-based encryption, then the offset within a file is not a constant which can be used for calculating an IV. For instance, the same extent could be blocks 0-8 in one file, and blocks 100-108 in another file. Instead, the block offset within the extent must be used instead. Update all uses of logical block offset within the file to use logical block offset within the extent, if applicable. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 7 ++++--- fs/crypto/inline_crypt.c | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 41c60c60b74c..93b83dbe82ee 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -107,8 +107,9 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist dst, src; - struct fscrypt_info *ci = fscrypt_get_lblk_info(inode, lblk_num, NULL, - NULL); + u64 ci_offset = 0; + struct fscrypt_info *ci = fscrypt_get_lblk_info(inode, lblk_num, + &ci_offset, NULL); struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; int res = 0; @@ -117,7 +118,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, if (WARN_ON_ONCE(len % FSCRYPT_CONTENTS_ALIGNMENT != 0)) return -EINVAL; - fscrypt_generate_iv(&iv, lblk_num, ci); + fscrypt_generate_iv(&iv, ci_offset, ci); req = skcipher_request_alloc(tfm, gfp_flags); if (!req) diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 56d69b231875..0ae220c8afa3 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -271,12 +271,13 @@ void fscrypt_set_bio_crypt_ctx(struct bio *bio, const struct inode *inode, { const struct fscrypt_info *ci; u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; + u64 ci_offset = 0; if (!fscrypt_inode_uses_inline_crypto(inode)) return; - ci = fscrypt_get_lblk_info(inode, first_lblk, NULL, NULL); + ci = fscrypt_get_lblk_info(inode, first_lblk, &ci_offset, NULL); - fscrypt_generate_dun(ci, first_lblk, dun); + fscrypt_generate_dun(ci, ci_offset, dun); bio_crypt_set_ctx(bio, ci->ci_enc_key.blk_key, dun, gfp_mask); } EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx); @@ -354,13 +355,14 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, const struct bio_crypt_ctx *bc = bio->bi_crypt_context; u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]; struct fscrypt_info *ci; + u64 ci_offset = 0; if (!!bc != fscrypt_inode_uses_inline_crypto(inode)) return false; if (!bc) return true; - ci = fscrypt_get_lblk_info(inode, next_lblk, NULL, NULL); + ci = fscrypt_get_lblk_info(inode, next_lblk, &ci_offset, NULL); /* * Comparing the key pointers is good enough, as all I/O for each key * uses the same pointer. I.e., there's currently no need to support @@ -369,7 +371,7 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode, if (bc->bc_key != ci->ci_enc_key.blk_key) return false; - fscrypt_generate_dun(ci, next_lblk, next_dun); + fscrypt_generate_dun(ci, ci_offset, next_dun); return bio_crypt_dun_is_contiguous(bc, bio->bi_iter.bi_size, next_dun); } EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio); @@ -464,6 +466,8 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) { const struct fscrypt_info *ci; u32 dun; + u64 ci_offset; + u64 extent_len; if (!fscrypt_inode_uses_inline_crypto(inode)) return nr_blocks; @@ -471,14 +475,17 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks) if (nr_blocks <= 1) return nr_blocks; - ci = fscrypt_get_lblk_info(inode, lblk, NULL, NULL); + ci = fscrypt_get_lblk_info(inode, lblk, &ci_offset, &extent_len); + + /* Spanning an extent boundary will change the DUN */ + nr_blocks = min_t(u64, nr_blocks, extent_len); if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_blocks; /* With IV_INO_LBLK_32, the DUN can wrap around from U32_MAX to 0. */ - dun = ci->ci_hashed_ino + lblk; + dun = ci->ci_hashed_ino + ci_offset; return min_t(u64, nr_blocks, (u64)U32_MAX + 1 - dun); } From patchwork Sun Jan 1 05:06:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086322 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A1660C3DA79 for ; Sun, 1 Jan 2023 05:13:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229703AbjAAFNz (ORCPT ); Sun, 1 Jan 2023 00:13:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50862 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232274AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C745663E3 for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 286A082634; Sun, 1 Jan 2023 00:06:37 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549597; bh=Cjs7qIoema7Ub8xzcx1e2WzqdwoTIiR4o58nP15fEEE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MHShNtu7TCZXL4t0PajRcdozfNL56jqTolrDeHM06KiaNyvGOa1eI7pzQOe3Vumv1 ocTSygXmLbPAK9E6Fsqq1wtaT5tG+mMdb6GHjeMyKytooz4Xvo/9HONkqGTVzIp3bw Yud/Y+3whiyYAG55iHtK9CuhZ5l6P7Fm6KnqR7BoYFZLR4zaqpyIPK0S2cBR4uuIu1 rPlmwPbWo0xJ3QpCKC30I5imz1U5xWFb9AEz/MQTgiaWvN7JqBQ/Vwc7jpbkVFplOx L6tSTz9D/WsUgHGC3AOssGbAHN/r8/BUlONw3WCGw0d5TmjvuotG78B1Lp2akMg9hi vE3oOFMcLrgng== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 04/17] fscrypt: factor out fscrypt_set_inode_info() Date: Sun, 1 Jan 2023 00:06:08 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org As this function needs to be called in several different places to short-circuit creating a new fscrypt_info for extent-based encryption, it makes sense to pull it into its own function for easy calling. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 60 +++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 87f28d666602..4d7ff8244c55 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -515,6 +515,38 @@ static void put_crypt_info(struct fscrypt_info *ci) kmem_cache_free(fscrypt_info_cachep, ci); } +static bool fscrypt_set_inode_info(struct inode *inode, + struct fscrypt_info *ci, + struct fscrypt_master_key *mk) +{ + if (ci == NULL) { + inode->i_crypt_info = NULL; + return true; + } + + /* + * For existing inodes, multiple tasks may race to set ->i_crypt_info. + * So use cmpxchg_release(). This pairs with the smp_load_acquire() in + * fscrypt_get_info(). I.e., here we publish ->i_crypt_info with a + * RELEASE barrier so that other tasks can ACQUIRE it. + */ + if (cmpxchg_release(&inode->i_crypt_info, NULL, ci) != NULL) + return false; + + /* + * We won the race and set ->i_crypt_info to our crypt_info. + * Now link it into the master key's inode list. + */ + if (mk) { + ci->ci_master_key = mk; + refcount_inc(&mk->mk_active_refs); + spin_lock(&mk->mk_decrypted_inodes_lock); + list_add(&ci->ci_master_key_link, &mk->mk_decrypted_inodes); + spin_unlock(&mk->mk_decrypted_inodes_lock); + } + return true; +} + static int fscrypt_setup_encryption_info(struct inode *inode, const union fscrypt_policy *policy, @@ -525,6 +557,7 @@ fscrypt_setup_encryption_info(struct inode *inode, struct fscrypt_mode *mode; struct fscrypt_master_key *mk = NULL; int res; + bool set_succeeded; res = fscrypt_initialize(inode->i_sb->s_cop->flags); if (res) @@ -550,34 +583,15 @@ fscrypt_setup_encryption_info(struct inode *inode, if (res) goto out; - /* - * For existing inodes, multiple tasks may race to set ->i_crypt_info. - * So use cmpxchg_release(). This pairs with the smp_load_acquire() in - * fscrypt_get_info(). I.e., here we publish ->i_crypt_info with a - * RELEASE barrier so that other tasks can ACQUIRE it. - */ - if (cmpxchg_release(&inode->i_crypt_info, NULL, crypt_info) == NULL) { - /* - * We won the race and set ->i_crypt_info to our crypt_info. - * Now link it into the master key's inode list. - */ - if (mk) { - crypt_info->ci_master_key = mk; - refcount_inc(&mk->mk_active_refs); - spin_lock(&mk->mk_decrypted_inodes_lock); - list_add(&crypt_info->ci_master_key_link, - &mk->mk_decrypted_inodes); - spin_unlock(&mk->mk_decrypted_inodes_lock); - } - crypt_info = NULL; - } + set_succeeded = fscrypt_set_inode_info(inode, crypt_info, mk); res = 0; out: if (mk) { up_read(&mk->mk_sem); fscrypt_put_master_key(mk); } - put_crypt_info(crypt_info); + if (!set_succeeded) + put_crypt_info(crypt_info); return res; } @@ -707,7 +721,7 @@ EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); void fscrypt_put_encryption_info(struct inode *inode) { put_crypt_info(fscrypt_get_inode_info(inode)); - inode->i_crypt_info = NULL; + fscrypt_set_inode_info(inode, NULL, NULL); } EXPORT_SYMBOL(fscrypt_put_encryption_info); From patchwork Sun Jan 1 05:06:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086327 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0D89DC46467 for ; Sun, 1 Jan 2023 05:13:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232200AbjAAFN6 (ORCPT ); Sun, 1 Jan 2023 00:13:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50786 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232452AbjAAFNt (ORCPT ); Sun, 1 Jan 2023 00:13:49 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 063976411 for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id F3D288261F; Sun, 1 Jan 2023 00:06:38 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549599; bh=BK2x5JjPz2d/0HlcZ+8yzxCScpwOk36OlzpYONoG0DI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vS87mZIMAShTDrjR2xqGIL0SCNrvS1G6oE/nQp+vFRr7u0ENVI/SEqAWbrGnl2RQp cJNiaZGvrUT/d8bFiWCGyiXx2mc6yu1kUgPyw3EdkDAdUuBP+BkEmY/lV1raoWWG8u f4rOFyHiDC331id+1Y3/wDI0M6W0HM9SRrX9fDh0JmyyI280ou0EqcgmpyXObCRNaF cC12yWFVYRRnNap6WjW7fX/9ybaqqF9tRkuohZm2d4jE9ysIRPjKNiuKyS7xz4j+yS vPnASvibitHAP86lEZ8EvaSLrVPIwqnryaWRBmg7KyZDV2SYALZCaeSJ6YBeRNabkC dngzRVDSbMluQ== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 05/17] fscrypt: use parent dir's info for extent-based encryption. Date: Sun, 1 Jan 2023 00:06:09 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org For regular files in filesystems using extent-based encryption, the corresponding inode does not need a fscrypt_info structure of its own as for inode-based fscrypt, as they will not be encrypting anything using it. Any new extents written to the inode will use a per-extent info structure derived from the inode's parent directory's info structure. However, it is convenient to cache that parent directory's info structure in the inode; it makes it easy to check whether the parents' info exists, so that we don't have to get and put a reference to the parent inode every time we want to get the inode info. So do that. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 18 ++++++++++++++++++ fs/crypto/keysetup.c | 27 ++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 2df28c6fe558..e4c9c483114f 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -262,6 +262,24 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; +/** + * fscrypt_uses_extent_encryption() -- whether an inode uses per-extent + * encryption + * + * @param inode the inode in question + * + * Return: true if the inode uses per-extent encryption infos, false otherwise + */ +static inline bool fscrypt_uses_extent_encryption(const struct inode *inode) +{ + // Non-regular files don't have extents + if (!S_ISREG(inode->i_mode)) + return false; + + // No filesystem currently uses per-extent infos + return false; +} + /** * fscrypt_get_inode_info() - get the fscrypt_info for a particular inode * diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 4d7ff8244c55..52244e0dd1e4 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -622,6 +622,22 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) if (fscrypt_has_encryption_key(inode)) return 0; + if (fscrypt_uses_extent_encryption(inode)) { + struct dentry *dentry = d_find_any_alias(inode); + struct dentry *parent_dentry = dget_parent(dentry); + struct inode *dir = parent_dentry->d_inode; + struct fscrypt_info *dir_info = fscrypt_get_inode_info(dir); + struct fscrypt_master_key *mk = NULL; + + if (dir_info) + mk = dir_info->ci_master_key; + + fscrypt_set_inode_info(inode, dir_info, mk); + dput(parent_dentry); + dput(dentry); + return 0; + } + res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); if (res < 0) { if (res == -ERANGE && allow_unsupported) @@ -704,6 +720,14 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode, *encrypt_ret = true; + if (fscrypt_uses_extent_encryption(inode)) { + struct fscrypt_info *dir_info = fscrypt_get_inode_info(dir); + + fscrypt_set_inode_info(inode, dir_info, + dir_info->ci_master_key); + return 0; + } + get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE); return fscrypt_setup_encryption_info(inode, policy, nonce, IS_CASEFOLDED(dir) && @@ -720,7 +744,8 @@ EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); */ void fscrypt_put_encryption_info(struct inode *inode) { - put_crypt_info(fscrypt_get_inode_info(inode)); + if (!fscrypt_uses_extent_encryption(inode)) + put_crypt_info(fscrypt_get_inode_info(inode)); fscrypt_set_inode_info(inode, NULL, NULL); } EXPORT_SYMBOL(fscrypt_put_encryption_info); From patchwork Sun Jan 1 05:06:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086317 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03405C46467 for ; Sun, 1 Jan 2023 05:13:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229892AbjAAFNu (ORCPT ); Sun, 1 Jan 2023 00:13:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50784 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229437AbjAAFNr (ORCPT ); Sun, 1 Jan 2023 00:13:47 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 22B6763FE for ; Sat, 31 Dec 2022 21:13:45 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 458918263D; Sun, 1 Jan 2023 00:06:41 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549601; bh=g4930koxwcaUYiQSLl2wE+AjGCHIuIimXlcUqzwAigE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fIkX44IO6MorEtvfv+mGLpDBwN8hknZG8e0TxdHdH7VRBIPKcJKPMEBX1IhXYvBY2 xFvVDQ7/DZxzbKmOzRAiMVYU8lcVhA49JWwO10S51V9I5fgEMb8TIW91Zdn3OIvyFp ZoZ2JlTppz+rvzet39QImw1DI5s6PAWuHmwGS7IdhwgyMV240cnhZOE/inXDjsUfte ZRtiuvQeRQ8ZzVnR/fwudaXO5FAcQddgEGGghUwHCE/fCNqG2AUrXkem93gaWrGDtU yg1cZP5dBSx6KRCb+JqXmlu2UXbxyaqw1zY7Cy+KYibAkycqJHPua36kHpDF45DkkB 3A5cLNe22IuPA== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 06/17] fscrypt: add a super_block pointer to fscrypt_info Date: Sun, 1 Jan 2023 00:06:10 -0500 Message-Id: <623191aef09dc226a77d59230b5363f674910915.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org When fscrypt_infos are attached to extents instead of inodes, we can't go through the inode to get at the filesystems's superblock. Therefore, add a dedicated superblock pointer to fscrypt_info to keep track of it. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 3 +++ fs/crypto/inline_crypt.c | 6 +++--- fs/crypto/keysetup.c | 9 ++++----- fs/crypto/keysetup_v1.c | 6 +++--- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index e4c9c483114f..da4df8642456 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -220,6 +220,9 @@ struct fscrypt_info { /* Back-pointer to the inode */ struct inode *ci_inode; + /* The superblock of the filesystem to which this fscrypt_info pertains */ + struct super_block *ci_sb; + /* * The master key with which this inode was unlocked (decrypted). This * will be NULL if the master key was found in a process-subscribed diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 0ae220c8afa3..7e85167d9f37 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -41,7 +41,7 @@ static struct block_device **fscrypt_get_devices(struct super_block *sb, static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci) { - struct super_block *sb = ci->ci_inode->i_sb; + struct super_block *sb = ci->ci_sb; unsigned int flags = fscrypt_policy_flags(&ci->ci_policy); int ino_bits = 64, lblk_bits = 64; @@ -95,7 +95,7 @@ static void fscrypt_log_blk_crypto_impl(struct fscrypt_mode *mode, int fscrypt_select_encryption_impl(struct fscrypt_info *ci) { const struct inode *inode = ci->ci_inode; - struct super_block *sb = inode->i_sb; + struct super_block *sb = ci->ci_sb; struct blk_crypto_config crypto_cfg; struct block_device **devs; unsigned int num_devs; @@ -158,7 +158,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const struct fscrypt_info *ci) { const struct inode *inode = ci->ci_inode; - struct super_block *sb = inode->i_sb; + struct super_block *sb = ci->ci_sb; enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode; struct blk_crypto_key *blk_key; struct block_device **devs; diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 52244e0dd1e4..dacf3c47a24a 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -174,8 +174,7 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci, struct fscrypt_prepared_key *keys, u8 hkdf_context, bool include_fs_uuid) { - const struct inode *inode = ci->ci_inode; - const struct super_block *sb = inode->i_sb; + const struct super_block *sb = ci->ci_sb; struct fscrypt_mode *mode = ci->ci_mode; const u8 mode_num = mode - fscrypt_modes; struct fscrypt_prepared_key *prep_key; @@ -435,7 +434,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, if (err) return err; - mk = fscrypt_find_master_key(ci->ci_inode->i_sb, &mk_spec); + mk = fscrypt_find_master_key(ci->ci_sb, &mk_spec); if (!mk) { if (ci->ci_policy.version != FSCRYPT_POLICY_V1) return -ENOKEY; @@ -495,8 +494,7 @@ static void put_crypt_info(struct fscrypt_info *ci) if (ci->ci_direct_key) fscrypt_put_direct_key(ci->ci_direct_key); else if (ci->ci_owns_key) - fscrypt_destroy_prepared_key(ci->ci_inode->i_sb, - &ci->ci_enc_key); + fscrypt_destroy_prepared_key(ci->ci_sb, &ci->ci_enc_key); mk = ci->ci_master_key; if (mk) { @@ -568,6 +566,7 @@ fscrypt_setup_encryption_info(struct inode *inode, return -ENOMEM; crypt_info->ci_inode = inode; + crypt_info->ci_sb = inode->i_sb; crypt_info->ci_policy = *policy; memcpy(crypt_info->ci_nonce, nonce, FSCRYPT_FILE_NONCE_SIZE); diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 75dabd9b27f9..3cbf1480c457 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -232,7 +232,7 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) dk = kzalloc(sizeof(*dk), GFP_KERNEL); if (!dk) return ERR_PTR(-ENOMEM); - dk->dk_sb = ci->ci_inode->i_sb; + dk->dk_sb = ci->ci_sb; refcount_set(&dk->dk_refcount, 1); dk->dk_mode = ci->ci_mode; err = fscrypt_prepare_key(&dk->dk_key, raw_key, ci); @@ -306,8 +306,8 @@ int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci) key = find_and_lock_process_key(FSCRYPT_KEY_DESC_PREFIX, ci->ci_policy.v1.master_key_descriptor, ci->ci_mode->keysize, &payload); - if (key == ERR_PTR(-ENOKEY) && ci->ci_inode->i_sb->s_cop->key_prefix) { - key = find_and_lock_process_key(ci->ci_inode->i_sb->s_cop->key_prefix, + if (key == ERR_PTR(-ENOKEY) && ci->ci_sb->s_cop->key_prefix) { + key = find_and_lock_process_key(ci->ci_sb->s_cop->key_prefix, ci->ci_policy.v1.master_key_descriptor, ci->ci_mode->keysize, &payload); } From patchwork Sun Jan 1 05:06:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086314 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 611C2C46467 for ; Sun, 1 Jan 2023 05:13:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230364AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230463AbjAAFNr (ORCPT ); Sun, 1 Jan 2023 00:13:47 -0500 X-Greylist: delayed 433 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Sat, 31 Dec 2022 21:13:45 PST Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BFE1063FA for ; Sat, 31 Dec 2022 21:13:45 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 400E482637; Sun, 1 Jan 2023 00:06:43 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549603; bh=ZORFfQlfZYXnSAgBDpsuOJNt0B3Xahqp03FH9Bh5A7M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=G0jEQZY06oZbPBJai/shCDs6YEalHOJcULZ2b9lUx7jz/s4XdMijEll4JiQj2eCQj 8ykmzEYyLPEJbWadfsP7WnfNdb4a6elXmn+7dpLAHciuencMReBlgRwTviaWkE9TKK xsZXSqc51QWb7S7JvODSx8HRS66tLs9JiUm8bJ3OaE35jueyV/T5ptmT79m8ZVKp6t h1TydsF0pVe5yeChaNSFIFax/GHJr9+gbwcd2GKkl3pdCMNHDABklwM/2gCRvwhAia XNI80Uw1piOde/EGIfflp0OZyxcjpqawJMppbHEfN1X+L4PwD9TACXZq1rBgXjV/HJ zB8hZEWiSzyGg== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 07/17] fscrypt: update comments about inodes to include extents Date: Sun, 1 Jan 2023 00:06:11 -0500 Message-Id: <7cb86ab7780f3a5dadc176a2071977cb0e4af0a5.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org There are a bunch of comments that need updating to refer to any sort of owning object, be it inode or extent, and they don't really fit anywhere else. So do it. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 57 +++++++++++++++++++++---------------- fs/crypto/inline_crypt.c | 9 ++++-- fs/crypto/keyring.c | 24 +++++++++------- fs/crypto/keysetup.c | 6 ++-- 4 files changed, 55 insertions(+), 41 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index da4df8642456..71e16d188fe8 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -53,14 +53,15 @@ struct fscrypt_context_v2 { }; /* - * fscrypt_context - the encryption context of an inode + * fscrypt_context - the encryption context of an object * * This is the on-disk equivalent of an fscrypt_policy, stored alongside each - * encrypted file usually in a hidden extended attribute. It contains the - * fields from the fscrypt_policy, in order to identify the encryption algorithm - * and key with which the file is encrypted. It also contains a nonce that was - * randomly generated by fscrypt itself; this is used as KDF input or as a tweak - * to cause different files to be encrypted differently. + * encrypted file usually in a hidden extended attribute, or along with an extent. + * It contains the fields from the fscrypt_policy, in order to identify the + * encryption algorithm and key with which the file or extent is encrypted. It + * also contains a nonce that was randomly generated by fscrypt itself; this is + * used as KDF input or as a tweak to cause different files to be encrypted + * differently. */ union fscrypt_context { u8 version; @@ -189,11 +190,19 @@ struct fscrypt_prepared_key { }; /* - * fscrypt_info - the "encryption key" for an inode + * fscrypt_info - the "encryption key" for an object (inode or extent) * - * When an encrypted file's key is made available, an instance of this struct is - * allocated and stored in ->i_crypt_info. Once created, it remains until the - * inode is evicted. + * For filesystems using inode-based encryption, or non-regular files for + * filesystems with extent-based encryption: when an encrypted file's key is + * made available, an instance of this struct is allocated and stored in + * ->i_crypt_info. Once created, it remains until the inode is evicted. + * + * For filesystems using extent-based encryption, for regular files: when + * a file is opened, a pointer to the parent directory's fscrypt_info is stored + * in the inode's ->i_crypt_info. When an extent's key is made available, an + * instance of this struct is allocated and should be stored with the extent. + * It is freed when the filesystem decides to drop the extent, or when the key + * needs to be removed. */ struct fscrypt_info { @@ -205,33 +214,33 @@ struct fscrypt_info { #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT /* - * True if this inode will use inline encryption (blk-crypto) instead of + * True if this info will use inline encryption (blk-crypto) instead of * the traditional filesystem-layer encryption. */ bool ci_inlinecrypt; #endif /* - * Encryption mode used for this inode. It corresponds to either the + * Encryption mode for this info. It corresponds to either the * contents or filenames encryption mode, depending on the inode type. */ struct fscrypt_mode *ci_mode; - /* Back-pointer to the inode */ + /* Back-pointer to the inode, for infos owned by a specific inode */ struct inode *ci_inode; /* The superblock of the filesystem to which this fscrypt_info pertains */ struct super_block *ci_sb; /* - * The master key with which this inode was unlocked (decrypted). This + * The master key with which this info was unlocked (decrypted). This * will be NULL if the master key was found in a process-subscribed * keyring rather than in the filesystem-level keyring. */ struct fscrypt_master_key *ci_master_key; /* - * Link in list of inodes that were unlocked with the master key. + * Link in list of infos that were unlocked with the master key. * Only used when ->ci_master_key is set. */ struct list_head ci_master_key_link; @@ -243,20 +252,20 @@ struct fscrypt_info { struct fscrypt_direct_key *ci_direct_key; /* - * This inode's hash key for filenames. This is a 128-bit SipHash-2-4 + * This infos' hash key for filenames. This is a 128-bit SipHash-2-4 * key. This is only set for directories that use a keyed dirhash over * the plaintext filenames -- currently just casefolded directories. */ siphash_key_t ci_dirhash_key; bool ci_dirhash_key_initialized; - /* The encryption policy used by this inode */ + /* The encryption policy used by this info */ union fscrypt_policy ci_policy; - /* This inode's nonce, copied from the fscrypt_context */ + /* This info's nonce, copied from the fscrypt_context */ u8 ci_nonce[FSCRYPT_FILE_NONCE_SIZE]; - /* Hashed inode number. Only set for IV_INO_LBLK_32 */ + /* Hashed object number. Only set for IV_INO_LBLK_32 */ u32 ci_hashed_ino; }; @@ -271,7 +280,7 @@ typedef enum { * * @param inode the inode in question * - * Return: true if the inode uses per-extent encryption infos, false otherwise + * Return: true if the inode uses per-extent fscrypt_infos, false otherwise */ static inline bool fscrypt_uses_extent_encryption(const struct inode *inode) { @@ -350,10 +359,10 @@ fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...); union fscrypt_iv { struct { - /* logical block number within the file */ + /* logical block number within the owning object */ __le64 lblk_num; - /* per-file nonce; only set in DIRECT_KEY mode */ + /* per-object nonce; only set in DIRECT_KEY mode */ u8 nonce[FSCRYPT_FILE_NONCE_SIZE]; }; u8 raw[FSCRYPT_MAX_IV_SIZE]; @@ -684,9 +693,9 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported); /** * fscrypt_require_key() - require an inode's encryption key - * @inode: the inode we need the key for * - * If the inode is encrypted, set up its encryption key if not already done. + * @inode: the inode we need the key for + * * If the inode is encrypted, set up its encryption key if not already done. * Then require that the key be present and return -ENOKEY otherwise. * * No locks are needed, and the key will live as long as the struct inode --- so diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 7e85167d9f37..808c8712ebe7 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -344,8 +344,9 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh); * fscrypt_set_bio_crypt_ctx() must have already been called on the bio. * * This function isn't required in cases where crypto-mergeability is ensured in - * another way, such as I/O targeting only a single file (and thus a single key) - * combined with fscrypt_limit_io_blocks() to ensure DUN contiguity. + * another way, such as I/O targeting only a single file combined with + * fscrypt_limit_io_blocks() to ensure DUN contiguity (which also ensures, + * for extent-based encryption, that the I/O doesn't span extents). * * Return: true iff the I/O is mergeable */ @@ -458,7 +459,9 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported); * DUN to wrap around within logically contiguous blocks, and that wraparound * will occur. If this happens, a value less than @nr_blocks will be returned * so that the wraparound doesn't occur in the middle of a bio, which would - * cause encryption/decryption to produce wrong results. + * cause encryption/decryption to produce wrong results. Similarly, the + * filesystem could be using extent-based encryption, which will return a value + * less than @nr_blocks if needed to prevent spanning multiple extents. * * Return: the actual number of blocks that can be submitted */ diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 2a24b1f0ae68..f825d800867c 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -876,7 +876,7 @@ static void shrink_dcache_inode(struct inode *inode) d_prune_aliases(inode); } -static void evict_dentries_for_decrypted_inodes(struct fscrypt_master_key *mk) +static void evict_dentries_for_decrypted_objects(struct fscrypt_master_key *mk) { struct fscrypt_info *ci; struct inode *inode; @@ -970,12 +970,14 @@ static int try_to_lock_encrypted_files(struct super_block *sb, * Inodes are pinned by their dentries, so we have to evict their * dentries. shrink_dcache_sb() would suffice, but would be overkill * and inappropriate for use by unprivileged users. So instead go - * through the inodes' alias lists and try to evict each dentry. + * through the inodes' alias lists and try to evict each dentry. Also, + * for extent-based encryption, notify the filesystem that it must free + * all the infos for extents using this key. */ - evict_dentries_for_decrypted_inodes(mk); + evict_dentries_for_decrypted_objects(mk); /* - * evict_dentries_for_decrypted_inodes() already iput() each inode in + * evict_dentries_for_decrypted_objects() already iput() each inode in * the list; any inodes for which that dropped the last reference will * have been evicted due to fscrypt_drop_inode() detecting the key * removal and telling the VFS to evict the inode. So to finish, we @@ -995,14 +997,14 @@ static int try_to_lock_encrypted_files(struct super_block *sb, * key itself. * * To "remove the key itself", first we wipe the actual master key secret, so - * that no more inodes can be unlocked with it. Then we try to evict all cached - * inodes that had been unlocked with the key. + * that nothing else can be unlocked with it. Then we try to evict all cached + * inodes and extents that had been unlocked with the key. * - * If all inodes were evicted, then we unlink the fscrypt_master_key from the - * keyring. Otherwise it remains in the keyring in the "incompletely removed" - * state (without the actual secret key) where it tracks the list of remaining - * inodes. Userspace can execute the ioctl again later to retry eviction, or - * alternatively can re-add the secret key again. + * If all were evicted, then we unlink the fscrypt_master_key from the keyring. + * Otherwise it remains in the keyring in the "incompletely removed" state + * (without the actual secret key) where it tracks the list of remaining inodes + * and extents. Userspace can execute the ioctl again later to retry eviction, + * or alternatively can re-add the secret key again. * * For more details, see the "Removing keys" section of * Documentation/filesystems/fscrypt.rst. diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index dacf3c47a24a..22e3ce5d61dc 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -334,9 +334,9 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { /* * IV_INO_LBLK_64: encryption keys are derived from (master_key, - * mode_num, filesystem_uuid), and inode number is included in - * the IVs. This format is optimized for use with inline - * encryption hardware compliant with the UFS standard. + * mode_num, filesystem_uuid), and inode/extent number is + * included in the IVs. This format is optimized for use with + * inline encryption hardware compliant with the UFS standard. */ err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys, HKDF_CONTEXT_IV_INO_LBLK_64_KEY, From patchwork Sun Jan 1 05:06:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086324 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3CD1AC3DA7D for ; Sun, 1 Jan 2023 05:13:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229725AbjAAFN4 (ORCPT ); Sun, 1 Jan 2023 00:13:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50860 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229947AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B42CE63CA for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id D9B5982640; Sun, 1 Jan 2023 00:06:45 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549606; bh=ZPrF757A3eeai3f9ewaah8yVadD7gA3m855rzNAOjbg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RVog0Xuu8dmtl5r4A4gDKn8lb4pBMjKMnjzwCpemhBKu0h2J5URobR4TpgyU0iva0 wLsbnXHJPRjSpEL2cuzukKr0CqvwijBfYcnLYGUofDev96M2S+ZMOipTvSqQqO02rt nQ2Og8JrcBlKW1fS8OtbHGhqD6JXooLPu6HOPkAZySH+gRcrUwSWSckOxYDPIDXW15 U0S/pq6eK8uuB541f6+PTttsvkyB7wbAmwJPKyT2sWxaYPo19DK9UmoM1pZirTKtUG VAEkYBlxER8hlKsvA6pnjwPShDmk1MVy8wWFBdapGImMK9gUCxU9f1I4lZ62x1imo4 5BdbP5BKaFNmw== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 08/17] fscrypt: rename mk->mk_decrypted_inodes* Date: Sun, 1 Jan 2023 00:06:12 -0500 Message-Id: <5040a466038d72547f2ecaae489a4eccc0453fc5.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org With the advent of extent-owned infos, we will need to track both inodes and extents in each master key, in order to appropriately notify filesystems that an extent needs to forget its fscrypt_info. Thus, it no longer makes sense for the list of these objects to be called 'decrypted inodes'. This change renames mk_decrypted_inodes{,_lock} to mk_active_infos{,_lock} since the list tracks active fscrypt_info objects of any provenance. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 12 ++++++------ fs/crypto/keyring.c | 30 +++++++++++++++--------------- fs/crypto/keysetup.c | 12 ++++++------ 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 71e16d188fe8..0c7b785f1d8c 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -537,7 +537,7 @@ struct fscrypt_master_key { * A structural ref only guarantees that the struct continues to exist. * * There is one active ref associated with ->mk_secret being present, - * and one active ref for each inode in ->mk_decrypted_inodes. + * and one active ref for each inode in ->mk_active_infos. * * There is one structural ref associated with the active refcount being * nonzero. Finding a key in the keyring also takes a structural ref, @@ -551,7 +551,7 @@ struct fscrypt_master_key { /* * The secret key material. After FS_IOC_REMOVE_ENCRYPTION_KEY is * executed, this is wiped and no new inodes can be unlocked with this - * key; however, there may still be inodes in ->mk_decrypted_inodes + * key; however, there may still be inodes in ->mk_active_infos * which could not be evicted. As long as some inodes still remain, * FS_IOC_REMOVE_ENCRYPTION_KEY can be retried, or * FS_IOC_ADD_ENCRYPTION_KEY can add the secret again. @@ -587,11 +587,11 @@ struct fscrypt_master_key { struct key *mk_users; /* - * List of inodes that were unlocked using this key. This allows the - * inodes to be evicted efficiently if the key is removed. + * List of infos that were unlocked using this key. This allows the + * owning objects to be evicted efficiently if the key is removed. */ - struct list_head mk_decrypted_inodes; - spinlock_t mk_decrypted_inodes_lock; + struct list_head mk_active_infos; + spinlock_t mk_active_infos_lock; /* * Per-mode encryption keys for the various types of encryption policies diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index f825d800867c..846f480da081 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -99,10 +99,10 @@ void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk) /* * ->mk_active_refs == 0 implies that ->mk_secret is not present and - * that ->mk_decrypted_inodes is empty. + * that ->mk_active_infos is empty. */ WARN_ON(is_master_key_secret_present(&mk->mk_secret)); - WARN_ON(!list_empty(&mk->mk_decrypted_inodes)); + WARN_ON(!list_empty(&mk->mk_active_infos)); for (i = 0; i <= FSCRYPT_MODE_MAX; i++) { fscrypt_destroy_prepared_key( @@ -429,8 +429,8 @@ static int add_new_master_key(struct super_block *sb, refcount_set(&mk->mk_struct_refs, 1); mk->mk_spec = *mk_spec; - INIT_LIST_HEAD(&mk->mk_decrypted_inodes); - spin_lock_init(&mk->mk_decrypted_inodes_lock); + INIT_LIST_HEAD(&mk->mk_active_infos); + spin_lock_init(&mk->mk_active_infos_lock); if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) { err = allocate_master_key_users_keyring(mk); @@ -882,9 +882,9 @@ static void evict_dentries_for_decrypted_objects(struct fscrypt_master_key *mk) struct inode *inode; struct inode *toput_inode = NULL; - spin_lock(&mk->mk_decrypted_inodes_lock); + spin_lock(&mk->mk_active_infos_lock); - list_for_each_entry(ci, &mk->mk_decrypted_inodes, ci_master_key_link) { + list_for_each_entry(ci, &mk->mk_active_infos, ci_master_key_link) { inode = ci->ci_inode; spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) { @@ -893,16 +893,16 @@ static void evict_dentries_for_decrypted_objects(struct fscrypt_master_key *mk) } __iget(inode); spin_unlock(&inode->i_lock); - spin_unlock(&mk->mk_decrypted_inodes_lock); + spin_unlock(&mk->mk_active_infos_lock); shrink_dcache_inode(inode); iput(toput_inode); toput_inode = inode; - spin_lock(&mk->mk_decrypted_inodes_lock); + spin_lock(&mk->mk_active_infos_lock); } - spin_unlock(&mk->mk_decrypted_inodes_lock); + spin_unlock(&mk->mk_active_infos_lock); iput(toput_inode); } @@ -914,25 +914,25 @@ static int check_for_busy_inodes(struct super_block *sb, unsigned long ino; char ino_str[50] = ""; - spin_lock(&mk->mk_decrypted_inodes_lock); + spin_lock(&mk->mk_active_infos_lock); - list_for_each(pos, &mk->mk_decrypted_inodes) + list_for_each(pos, &mk->mk_active_infos) busy_count++; if (busy_count == 0) { - spin_unlock(&mk->mk_decrypted_inodes_lock); + spin_unlock(&mk->mk_active_infos_lock); return 0; } { /* select an example file to show for debugging purposes */ struct inode *inode = - list_first_entry(&mk->mk_decrypted_inodes, + list_first_entry(&mk->mk_active_infos, struct fscrypt_info, ci_master_key_link)->ci_inode; ino = inode->i_ino; } - spin_unlock(&mk->mk_decrypted_inodes_lock); + spin_unlock(&mk->mk_active_infos_lock); /* If the inode is currently being created, ino may still be 0. */ if (ino) @@ -954,7 +954,7 @@ static int try_to_lock_encrypted_files(struct super_block *sb, /* * An inode can't be evicted while it is dirty or has dirty pages. - * Thus, we first have to clean the inodes in ->mk_decrypted_inodes. + * Thus, we first have to clean the inodes in ->mk_active_infos. * * Just do it the easy way: call sync_filesystem(). It's overkill, but * it works, and it's more important to minimize the amount of caches we diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 22e3ce5d61dc..cb3ba4e4f816 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -414,7 +414,7 @@ static bool fscrypt_valid_master_key_size(const struct fscrypt_master_key *mk, * * If the master key is found in the filesystem-level keyring, then it is * returned in *mk_ret with its semaphore read-locked. This is needed to ensure - * that only one task links the fscrypt_info into ->mk_decrypted_inodes (as + * that only one task links the fscrypt_info into ->mk_active_infos (as * multiple tasks may race to create an fscrypt_info for the same inode), and to * synchronize the master key being removed with a new inode starting to use it. */ @@ -504,9 +504,9 @@ static void put_crypt_info(struct fscrypt_info *ci) * inode from a master key struct that already had its secret * removed, then complete the full removal of the struct. */ - spin_lock(&mk->mk_decrypted_inodes_lock); + spin_lock(&mk->mk_active_infos_lock); list_del(&ci->ci_master_key_link); - spin_unlock(&mk->mk_decrypted_inodes_lock); + spin_unlock(&mk->mk_active_infos_lock); fscrypt_put_master_key_activeref(mk); } memzero_explicit(ci, sizeof(*ci)); @@ -538,9 +538,9 @@ static bool fscrypt_set_inode_info(struct inode *inode, if (mk) { ci->ci_master_key = mk; refcount_inc(&mk->mk_active_refs); - spin_lock(&mk->mk_decrypted_inodes_lock); - list_add(&ci->ci_master_key_link, &mk->mk_decrypted_inodes); - spin_unlock(&mk->mk_decrypted_inodes_lock); + spin_lock(&mk->mk_active_infos_lock); + list_add(&ci->ci_master_key_link, &mk->mk_active_infos); + spin_unlock(&mk->mk_active_infos_lock); } return true; } From patchwork Sun Jan 1 05:06:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086326 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1894C4167B for ; Sun, 1 Jan 2023 05:13:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231321AbjAAFN5 (ORCPT ); Sun, 1 Jan 2023 00:13:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50856 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232334AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D7A1463E9 for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 6FC8C82642; Sun, 1 Jan 2023 00:06:47 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549607; bh=FGZbrt7PwqtDqmoTtWjKsiwBXR5iOGg5k7lqM36FoVw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gr67VzxMKoTPRy5yEVrzLbqm0wfoa4PWZ6dMP1mgCXNzVMRZkq7EfCBuBGNM5Vd7K odyVtRxxkPuehGwdU0yPNk7equM1RE1oZuymz6y4s6DEZD9VPRxCuXjtgaFreS8V5Z hJwtZIaB+cM6Zgo39CjPraOTqFgF0i+SVsYtENFf6qOaXs2HTZUzad+WwdA1XnB2OE wtGGdpmRm/9FpDGSMMA0LwrfEzLXgRrhGf2rJPzqi5sNnDk263jh8lWdJhnn0Sgd33 4qpXDrjPoyeFJ9NhnWeRIJScKcAI1anXgB1HJb9fRLlCaQCYbWrC+VuBxutv/XF9SV RE47okrmKAnjw== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 09/17] fscrypt: make fscrypt_setup_encryption_info generic for extents Date: Sun, 1 Jan 2023 00:06:13 -0500 Message-Id: <2e4743214d5f40664ebb6227f71449015d16a218.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org fscrypt_setup_encryption_info() will be used for setting up both inode and extent fscrypt_infos, so it can't just assume that it should set inode->i_crypt_info to the new fscrypt_info. Instead, this changes it to take a pointer to the location to store the new fscrypt_info, which currently is always &inode->i_crypt_info. Correspondingly, fscrypt_setup_encryption_info() currently calls fscrypt_set_inode_info() to set the inode's info; this renames it to fscrypt_set_info() and plumbs through the pointer to the location to store the new fscrypt_info. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index cb3ba4e4f816..04f01da900ca 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -513,22 +513,23 @@ static void put_crypt_info(struct fscrypt_info *ci) kmem_cache_free(fscrypt_info_cachep, ci); } -static bool fscrypt_set_inode_info(struct inode *inode, - struct fscrypt_info *ci, - struct fscrypt_master_key *mk) +static bool fscrypt_set_info(struct fscrypt_info **info_ptr, + struct fscrypt_info *ci, + struct fscrypt_master_key *mk) { if (ci == NULL) { - inode->i_crypt_info = NULL; + *info_ptr = NULL; return true; } /* - * For existing inodes, multiple tasks may race to set ->i_crypt_info. - * So use cmpxchg_release(). This pairs with the smp_load_acquire() in - * fscrypt_get_info(). I.e., here we publish ->i_crypt_info with a - * RELEASE barrier so that other tasks can ACQUIRE it. + * For existing objects, multiple tasks may race to set ->i_crypt_info + * or the equivalent. So use cmpxchg_release(). This pairs with the + * smp_load_acquire() in fscrypt_get_info(). I.e., here we publish + * ->i_crypt_info with a RELEASE barrier so that other tasks can + * ACQUIRE it. */ - if (cmpxchg_release(&inode->i_crypt_info, NULL, ci) != NULL) + if (cmpxchg_release(info_ptr, NULL, ci) != NULL) return false; /* @@ -549,7 +550,8 @@ static int fscrypt_setup_encryption_info(struct inode *inode, const union fscrypt_policy *policy, const u8 nonce[FSCRYPT_FILE_NONCE_SIZE], - bool need_dirhash_key) + bool need_dirhash_key, + struct fscrypt_info **info_ptr) { struct fscrypt_info *crypt_info; struct fscrypt_mode *mode; @@ -582,7 +584,7 @@ fscrypt_setup_encryption_info(struct inode *inode, if (res) goto out; - set_succeeded = fscrypt_set_inode_info(inode, crypt_info, mk); + set_succeeded = fscrypt_set_info(info_ptr, crypt_info, mk); res = 0; out: if (mk) { @@ -631,7 +633,7 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) if (dir_info) mk = dir_info->ci_master_key; - fscrypt_set_inode_info(inode, dir_info, mk); + fscrypt_set_info(&inode->i_crypt_info, dir_info, mk); dput(parent_dentry); dput(dentry); return 0; @@ -663,7 +665,8 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) res = fscrypt_setup_encryption_info(inode, &policy, fscrypt_context_nonce(&ctx), IS_CASEFOLDED(inode) && - S_ISDIR(inode->i_mode)); + S_ISDIR(inode->i_mode), + &inode->i_crypt_info); if (res == -ENOPKG && allow_unsupported) /* Algorithm unavailable? */ res = 0; @@ -722,15 +725,16 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode, if (fscrypt_uses_extent_encryption(inode)) { struct fscrypt_info *dir_info = fscrypt_get_inode_info(dir); - fscrypt_set_inode_info(inode, dir_info, - dir_info->ci_master_key); + fscrypt_set_info(&inode->i_crypt_info, dir_info, + dir_info->ci_master_key); return 0; } get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE); return fscrypt_setup_encryption_info(inode, policy, nonce, IS_CASEFOLDED(dir) && - S_ISDIR(inode->i_mode)); + S_ISDIR(inode->i_mode), + &inode->i_crypt_info); } EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); @@ -745,7 +749,7 @@ void fscrypt_put_encryption_info(struct inode *inode) { if (!fscrypt_uses_extent_encryption(inode)) put_crypt_info(fscrypt_get_inode_info(inode)); - fscrypt_set_inode_info(inode, NULL, NULL); + fscrypt_set_info(&inode->i_crypt_info, NULL, NULL); } EXPORT_SYMBOL(fscrypt_put_encryption_info); From patchwork Sun Jan 1 05:06:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086316 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28238C3DA79 for ; Sun, 1 Jan 2023 05:13:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230463AbjAAFNt (ORCPT ); Sun, 1 Jan 2023 00:13:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50860 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230510AbjAAFNr (ORCPT ); Sun, 1 Jan 2023 00:13:47 -0500 X-Greylist: delayed 435 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Sat, 31 Dec 2022 21:13:46 PST Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 229E963CC for ; Sat, 31 Dec 2022 21:13:45 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 4CB8B82647; Sun, 1 Jan 2023 00:06:49 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549609; bh=kIBJVYH2JqSKtwNK1QBti5TNYAdm7cp7w0tqOZfFeZo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Fxgx0hEHqqVEcnK6BIa/+pYem6g0O8j9J23+hUXjO/eDzvi6M7hh+/ECz7Up9fASz y6o7wXRgGLWa08X9mr5kMePPIOGN4+t0ITtx3iRSiEllAyjuzg1cHGgBu2+wXJDcZi nNu6Xu3RYWve/ghkpaSPn/yvzl9zv9uBoIewWw0ud89Xuv0ZUyIB8P06vAI0jMNJlU 62eXZHV1ZHhQ5mP2arJuidwPWOrZqYpxiJNK3mtRbJmte9A9KO+DricGHIOpy28yGr fFiZh2VXytIB+N+whS36XbyWGK/A6LAYgBjdGOSc07wRN25oPMctAxdlrZs8SqboBI YfgdAZ2vtb7gQ== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 10/17] fscrypt: let fscrypt_infos be owned by an extent Date: Sun, 1 Jan 2023 00:06:14 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org In order to notify extents when their info is part of a master key which is going away, the fscrypt_info must have a backpointer to the extent somehow. Similarly, if a fscrypt_info is owned by an extent, the info must not have a pointer to an inode -- multiple inodes may reference a extent, and the first inode to cause an extent's creation may have a lifetime much shorter than the extent, so there is no inode pointer safe to track in an extent-owned info. Therefore, this adds a new pointer for extent-owned infos to track their extent and updates fscrypt_setup_encryption_info() accordingly. Since it's simple to track the piece of extent memory pointing to the info, and for the extent to then go from such a pointer to the whole extent via container_of(), we store that. Although some sort of generic void * or some artificial fscrypt_extent embedded structure would also work, those would require additional plumbing which doesn't seem strictly required or clarifying. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 6 ++++++ fs/crypto/keysetup.c | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 0c7b785f1d8c..dc45cd35391f 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -229,6 +229,12 @@ struct fscrypt_info { /* Back-pointer to the inode, for infos owned by a specific inode */ struct inode *ci_inode; + /* + * Back-pointer to the info pointer in the extent, for infos owned + * by an extent + */ + struct fscrypt_info **ci_info_ptr; + /* The superblock of the filesystem to which this fscrypt_info pertains */ struct super_block *ci_sb; diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 04f01da900ca..c611e2613aa6 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -567,7 +567,11 @@ fscrypt_setup_encryption_info(struct inode *inode, if (!crypt_info) return -ENOMEM; - crypt_info->ci_inode = inode; + if (fscrypt_uses_extent_encryption(inode)) + crypt_info->ci_info_ptr = info_ptr; + else + crypt_info->ci_inode = inode; + crypt_info->ci_sb = inode->i_sb; crypt_info->ci_policy = *policy; memcpy(crypt_info->ci_nonce, nonce, FSCRYPT_FILE_NONCE_SIZE); From patchwork Sun Jan 1 05:06:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086321 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 24CA6C46467 for ; Sun, 1 Jan 2023 05:13:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230344AbjAAFNz (ORCPT ); Sun, 1 Jan 2023 00:13:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50854 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232200AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C740663CC for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id EF33A8263A; Sun, 1 Jan 2023 00:06:50 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549611; bh=vKdl56H3Eyn9tkwdYaYdYBVUmySGklaAQ944HyzOxvk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=a+Lj2YATo3BpRGr9IYea1LP7ykI9Ewmd4AvDQKRIxvuJwP0WPf+TAIVTHpY9iUkc9 4hSZdWs+LKQ3HKSvmIG97806Wr78F01nnCrfYJ9qA2mCYtuELHd8jz9ZIjlVtsfu9F HH1iyVil2NEj6P5FTcdPEzqUL8rs/0PAbyTRw/o1aqTf6uEo5cbtt+drvZHRB+nE6g nxE/9VEYxk9LII9/kedErvXZgJUPqr8gilCgg/Joac1YfJIo+bJHwqJQWh723p3LI8 jUNOClmz6Q85BJEup6p53I1ltoq3pbRLDZxXiFrz5ShEol8QFj0v+qiiREXHabEB/r PVkIkfA3Letmg== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 11/17] fscrypt: update all the *per_file_* function names Date: Sun, 1 Jan 2023 00:06:15 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org As they are no longer per-file but per-info, whether that info is per-inode or per-extent, it seems better to rename all the relevant functions to be per_info instead of per-key. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 6 +++--- fs/crypto/keysetup.c | 22 +++++++++++----------- fs/crypto/keysetup_v1.c | 18 +++++++++--------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index dc45cd35391f..a34d2e525ddf 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -687,7 +687,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, void fscrypt_destroy_prepared_key(struct super_block *sb, struct fscrypt_prepared_key *prep_key); -int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key); +int fscrypt_set_per_info_enc_key(struct fscrypt_info *ci, const u8 *raw_key); int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, const struct fscrypt_master_key *mk); @@ -727,10 +727,10 @@ static inline int fscrypt_require_key(struct inode *inode) void fscrypt_put_direct_key(struct fscrypt_direct_key *dk); -int fscrypt_setup_v1_file_key(struct fscrypt_info *ci, +int fscrypt_setup_v1_info_key(struct fscrypt_info *ci, const u8 *raw_master_key); -int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci); +int fscrypt_setup_v1_info_key_via_subscribed_keyrings(struct fscrypt_info *ci); /* policy.c */ diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index c611e2613aa6..1751e3ed9956 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -162,8 +162,8 @@ void fscrypt_destroy_prepared_key(struct super_block *sb, memzero_explicit(prep_key, sizeof(*prep_key)); } -/* Given a per-file encryption key, set up the file's crypto transform object */ -int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key) +/* Given a fscrypt_info, set up an appropriate crypto transform object */ +int fscrypt_set_per_info_enc_key(struct fscrypt_info *ci, const u8 *raw_key) { ci->ci_owns_key = true; return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci); @@ -313,7 +313,7 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci, return 0; } -static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, +static int fscrypt_setup_v2_info_key(struct fscrypt_info *ci, struct fscrypt_master_key *mk, bool need_dirhash_key) { @@ -321,8 +321,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { /* - * DIRECT_KEY: instead of deriving per-file encryption keys, the - * per-file nonce will be included in all the IVs. But unlike + * DIRECT_KEY: instead of deriving per-info encryption keys, the + * per-info nonce will be included in all the IVs. But unlike * v1 policies, for v2 policies in this case we don't encrypt * with the master key directly but rather derive a per-mode * encryption key. This ensures that the master key is @@ -354,7 +354,7 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, if (err) return err; - err = fscrypt_set_per_file_enc_key(ci, derived_key); + err = fscrypt_set_per_info_enc_key(ci, derived_key); memzero_explicit(derived_key, ci->ci_mode->keysize); } if (err) @@ -418,7 +418,7 @@ static bool fscrypt_valid_master_key_size(const struct fscrypt_master_key *mk, * multiple tasks may race to create an fscrypt_info for the same inode), and to * synchronize the master key being removed with a new inode starting to use it. */ -static int setup_file_encryption_key(struct fscrypt_info *ci, +static int setup_info_encryption_key(struct fscrypt_info *ci, bool need_dirhash_key, struct fscrypt_master_key **mk_ret) { @@ -445,7 +445,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, * to before the search of ->s_master_keys, since users * shouldn't be able to override filesystem-level keys. */ - return fscrypt_setup_v1_file_key_via_subscribed_keyrings(ci); + return fscrypt_setup_v1_info_key_via_subscribed_keyrings(ci); } down_read(&mk->mk_sem); @@ -462,10 +462,10 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, switch (ci->ci_policy.version) { case FSCRYPT_POLICY_V1: - err = fscrypt_setup_v1_file_key(ci, mk->mk_secret.raw); + err = fscrypt_setup_v1_info_key(ci, mk->mk_secret.raw); break; case FSCRYPT_POLICY_V2: - err = fscrypt_setup_v2_file_key(ci, mk, need_dirhash_key); + err = fscrypt_setup_v2_info_key(ci, mk, need_dirhash_key); break; default: WARN_ON(1); @@ -584,7 +584,7 @@ fscrypt_setup_encryption_info(struct inode *inode, WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE); crypt_info->ci_mode = mode; - res = setup_file_encryption_key(crypt_info, need_dirhash_key, &mk); + res = setup_info_encryption_key(crypt_info, need_dirhash_key, &mk); if (res) goto out; diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 3cbf1480c457..3c3a203c2a94 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -250,7 +250,7 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) } /* v1 policy, DIRECT_KEY: use the master key directly */ -static int setup_v1_file_key_direct(struct fscrypt_info *ci, +static int setup_v1_info_key_direct(struct fscrypt_info *ci, const u8 *raw_master_key) { struct fscrypt_direct_key *dk; @@ -263,8 +263,8 @@ static int setup_v1_file_key_direct(struct fscrypt_info *ci, return 0; } -/* v1 policy, !DIRECT_KEY: derive the file's encryption key */ -static int setup_v1_file_key_derived(struct fscrypt_info *ci, +/* v1 policy, !DIRECT_KEY: derive the info's encryption key */ +static int setup_v1_info_key_derived(struct fscrypt_info *ci, const u8 *raw_master_key) { u8 *derived_key; @@ -283,21 +283,21 @@ static int setup_v1_file_key_derived(struct fscrypt_info *ci, if (err) goto out; - err = fscrypt_set_per_file_enc_key(ci, derived_key); + err = fscrypt_set_per_info_enc_key(ci, derived_key); out: kfree_sensitive(derived_key); return err; } -int fscrypt_setup_v1_file_key(struct fscrypt_info *ci, const u8 *raw_master_key) +int fscrypt_setup_v1_info_key(struct fscrypt_info *ci, const u8 *raw_master_key) { if (ci->ci_policy.v1.flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) - return setup_v1_file_key_direct(ci, raw_master_key); + return setup_v1_info_key_direct(ci, raw_master_key); else - return setup_v1_file_key_derived(ci, raw_master_key); + return setup_v1_info_key_derived(ci, raw_master_key); } -int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci) +int fscrypt_setup_v1_info_key_via_subscribed_keyrings(struct fscrypt_info *ci) { struct key *key; const struct fscrypt_key *payload; @@ -314,7 +314,7 @@ int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci) if (IS_ERR(key)) return PTR_ERR(key); - err = fscrypt_setup_v1_file_key(ci, payload->raw); + err = fscrypt_setup_v1_info_key(ci, payload->raw); up_read(&key->sem); key_put(key); return err; From patchwork Sun Jan 1 05:06:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086315 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7E347C3DA7D for ; Sun, 1 Jan 2023 05:13:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230510AbjAAFNt (ORCPT ); Sun, 1 Jan 2023 00:13:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50862 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231286AbjAAFNr (ORCPT ); Sun, 1 Jan 2023 00:13:47 -0500 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 22B1D63FB for ; Sat, 31 Dec 2022 21:13:45 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id BB7C88264D; Sun, 1 Jan 2023 00:06:52 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549613; bh=wmLSBF1zgWOIZsmv1JCB3t+Rhraqtpxnys1RB8QVAco=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=w4V8NBvtT8pCpAHwMyrbaV6lFpLY8wyImJXpTjmuMrkZNglylYIF7g/ASCWJ6u0yO hzTyV9FRVPYh2sooEt1WLKX1j086vYHDpzdpqqNH97CFoM0B1lgJZ56kPss81VrWYJ o4tbPs7PCVkItjhBNN/MU0vp4VO+graG7mIHNOkSDdBYgDOfSCWa+73ltBZ/LCRJZ2 JX81K+CNuqpfF1mEsKlQkPxBACeRrjD/JT79r+LRfF164ZCYD6JVGWBQPCaZUp/1Y8 wTO5B/A99kSHikejqrLiKpFAhir+O506us0EkRbmg0k8B9EXrsBIGTSEMhXLo58Plz +ah21spZH2HJg== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 12/17] fscrypt: notify per-extent infos if master key vanishes Date: Sun, 1 Jan 2023 00:06:16 -0500 Message-Id: <6e98cad3640444193ac886267eca0f0a62ea9db0.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org When fscrypt_infos can be owned by an extent instead of an inode, a new method of evicting the per-extent info for a key being removed is needed. This change adds removal handling to per-extent infos for master key removal. This seems racy to me and I'd love to find a better way to do this, but I can't think of it. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keyring.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 846f480da081..0c4e917a5281 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -886,6 +886,13 @@ static void evict_dentries_for_decrypted_objects(struct fscrypt_master_key *mk) list_for_each_entry(ci, &mk->mk_active_infos, ci_master_key_link) { inode = ci->ci_inode; + if (!inode) { + spin_unlock(&mk->mk_active_infos_lock); + ci->ci_sb->s_cop->forget_extent_info(ci->ci_info_ptr); + spin_lock(&mk->mk_active_infos_lock); + continue; + } + spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) { spin_unlock(&inode->i_lock); From patchwork Sun Jan 1 05:06:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086330 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2315BC3DA7D for ; Sun, 1 Jan 2023 05:14:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232334AbjAAFN7 (ORCPT ); Sun, 1 Jan 2023 00:13:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50794 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232561AbjAAFNt (ORCPT ); Sun, 1 Jan 2023 00:13:49 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E935E6403 for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 977B682666; Sun, 1 Jan 2023 00:06:54 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549615; bh=Zek6tJgMgpf4jZZbZ1RTIGxYIEyVbndBB6tiZz5U+Z0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Cy7dhjJZufvJ8Jd9URDZVffFHYdnNbyHNr1XwkS5gMgsTUtUKWCJl6sn32QPUpLey S8JPBplt1Xia1zW5Qtn4G8nwzSnIoA6IKgWhz/TijRJRQSOlI8YFHnyx1/XVKfHKar RpaFaL1JYV/WYdnPvui6uJGsw2qYBnvd3OhvmW9aABl+QxX+gxVKg0uefvxyT8nqme Ieg2ujWqTM8qsgYKEWH8+C+Xc0hLVLxDm098vqfn+hSuArYv4N/qT+618k1YE1Ap2T oDiO+tZMyz7doTp4ssg8HYqmnDOuk7b9m38BCEX47Bg4BK/qE6DDkeyuhVFECNu0TV meXRyGkUG9aRQ== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 13/17] fscrypt: use an optional ino equivalent for per-extent infos Date: Sun, 1 Jan 2023 00:06:17 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org Since per-extent infos are not tied to inodes, an ino-based policy cannot access the inode's i_ino to get the necessary information. Instead, this adds an optional fscrypt_operation pointer to get the ino equivalent for an extent, adds a wrapper to get the ino for an info, and uses this wrapper everywhere where the ci's inode's i_ino is currently accessed. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 5 +++-- fs/crypto/fscrypt_private.h | 18 ++++++++++++++++++ fs/crypto/keyring.c | 6 +++--- fs/crypto/keysetup.c | 8 ++++---- include/linux/fscrypt.h | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 93b83dbe82ee..4760adc1158f 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -85,9 +85,10 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, memset(iv, 0, ci->ci_mode->ivsize); if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { + u64 ino = fscrypt_get_info_ino(ci); WARN_ON_ONCE(lblk_num > U32_MAX); - WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX); - lblk_num |= (u64)ci->ci_inode->i_ino << 32; + WARN_ON_ONCE(ino > U32_MAX); + lblk_num |= (u64)ino << 32; } else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { WARN_ON_ONCE(lblk_num > U32_MAX); lblk_num = (u32)(ci->ci_hashed_ino + lblk_num); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index a34d2e525ddf..d937a320361e 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -344,6 +344,24 @@ fscrypt_get_lblk_info(const struct inode *inode, u64 lblk, u64 *offset, return fscrypt_get_info(inode); } +/** + * fscrypt_get_info_ino() - get the ino or ino equivalent for an info + * + * @ci: the fscrypt_info in question + * + * For inode-based encryption, this will return the info's inode's ino. + * For extent-based encryption, this will return the extent's ino equivalent + * or 0 if it is not implemented. + */ +static inline u64 fscrypt_get_info_ino(const struct fscrypt_info *ci) +{ + if (ci->ci_inode) + return ci->ci_inode->i_ino; + if (!ci->ci_sb->s_cop->get_extent_ino_equivalent) + return 0; + return ci->ci_sb->s_cop->get_extent_ino_equivalent(ci->ci_info_ptr); +} + /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; int fscrypt_initialize(unsigned int cop_flags); diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 0c4e917a5281..48e732628d43 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -933,11 +933,11 @@ static int check_for_busy_inodes(struct super_block *sb, { /* select an example file to show for debugging purposes */ - struct inode *inode = + struct fscrypt_info *ci = list_first_entry(&mk->mk_active_infos, struct fscrypt_info, - ci_master_key_link)->ci_inode; - ino = inode->i_ino; + ci_master_key_link); + ino = fscrypt_get_info_ino(ci); } spin_unlock(&mk->mk_active_infos_lock); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 1751e3ed9956..f32b6f0a8336 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -266,11 +266,11 @@ int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, void fscrypt_hash_inode_number(struct fscrypt_info *ci, const struct fscrypt_master_key *mk) { - WARN_ON(ci->ci_inode->i_ino == 0); + u64 ino = fscrypt_get_info_ino(ci); + WARN_ON(ino == 0); WARN_ON(!mk->mk_ino_hash_key_initialized); - ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino, - &mk->mk_ino_hash_key); + ci->ci_hashed_ino = (u32)siphash_1u64(ino, &mk->mk_ino_hash_key); } static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci, @@ -308,7 +308,7 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci, * New inodes may not have an inode number assigned yet. * Hashing their inode number is delayed until later. */ - if (ci->ci_inode->i_ino) + if (fscrypt_get_info_ino(ci)) fscrypt_hash_inode_number(ci, mk); return 0; } diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 4f5f8a651213..c05e6ad3e729 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -129,6 +129,15 @@ struct fscrypt_operations { */ bool (*empty_dir)(struct inode *inode); + /* + * Inform the filesystem that a particular extent must forget its + * fscrypt_info (for instance, for a key removal). + * + * @info_ptr: a pointer to the location storing the fscrypt_info pointer + * within the opaque extent whose info is to be freed + */ + void (*forget_extent_info)(struct fscrypt_info **info_ptr); + /* * Check whether the filesystem's inode numbers and UUID are stable, * meaning that they will never be changed even by offline operations @@ -160,6 +169,15 @@ struct fscrypt_operations { void (*get_ino_and_lblk_bits)(struct super_block *sb, int *ino_bits_ret, int *lblk_bits_ret); + /* + * Get the inode number equivalent for filesystems using per-extent + * encryption keys. + * + * This function only needs to be implemented if support for one of the + * FSCRYPT_POLICY_FLAG_IV_INO_* flags is needed. + */ + u64 (*get_extent_ino_equivalent)(struct fscrypt_info **info_ptr); + /* * Return an array of pointers to the block devices to which the * filesystem may write encrypted file contents, NULL if the filesystem From patchwork Sun Jan 1 05:06:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086320 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C4614C4167B for ; Sun, 1 Jan 2023 05:13:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229589AbjAAFNy (ORCPT ); Sun, 1 Jan 2023 00:13:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230344AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3CDC16402 for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 3A2388265A; Sun, 1 Jan 2023 00:06:56 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549616; bh=a8XzKLzTV30UHtrV3sNb1efDRQt9J0wbwog5h8XPlpA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UsaakzQgOFu3hMx+HbgT0NeV6o1jessPHqt9qsENi+eMq3/CX7VTB0Ag4mQx0KNJV mkA9X5wRg5tyNuEbvjvu8y6Au3bFki2S+BwY6ESVOHCbfMlnVFNtYOKGQQhFt+TIql WLYlzzt/oNEZ5yOZWLpyYZTgK51khuugb8cLwqRFNFMROnerM3LYbbz97REkoQT68B ZE2md2/x76PQX/d9Gx9xZlIlFgtlTYRtgZu9674l/IpRcNMaIMP56kebwLX3jUbfeu bkTf6UaKB9wDz8k1zjLIh674J9o2KdSoag9ui6hmRZ7I7XxSFomp0KRaPL8rCVjkjs YjTEdvsZeV+7w== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 14/17] fscrypt: add creation/usage/freeing of per-extent infos Date: Sun, 1 Jan 2023 00:06:18 -0500 Message-Id: <9e1c2b101025a3388a6b31a8bdfb2b1cf59bf97c.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org This change adds the superblock function pointer to get the info corresponding to a specific block in an inode for a filesystem using per-extent infos. It allows creating a info for a new extent and freeing that info, and uses the extent's info if appropriate in encrypting blocks of data. This change does not deal with saving and loading an extent's info, but introduces the mechanics necessary therefore. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 6 ++++ fs/crypto/fscrypt_private.h | 14 +++++++-- fs/crypto/keysetup.c | 57 +++++++++++++++++++++++++++++++++++++ include/linux/fscrypt.h | 41 ++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 2 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 4760adc1158f..b2a293e1df29 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -118,6 +118,12 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, return -EINVAL; if (WARN_ON_ONCE(len % FSCRYPT_CONTENTS_ALIGNMENT != 0)) return -EINVAL; + if (!ci) { + fscrypt_err(inode, + "Error %d getting extent info for block %llu", + res, lblk_num); + return -EINVAL; + } fscrypt_generate_iv(&iv, ci_offset, ci); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index d937a320361e..eca911cca8a0 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -294,8 +294,7 @@ static inline bool fscrypt_uses_extent_encryption(const struct inode *inode) if (!S_ISREG(inode->i_mode)) return false; - // No filesystem currently uses per-extent infos - return false; + return !!inode->i_sb->s_cop->get_extent_info; } /** @@ -336,6 +335,17 @@ static inline struct fscrypt_info * fscrypt_get_lblk_info(const struct inode *inode, u64 lblk, u64 *offset, u64 *extent_len) { + if (fscrypt_uses_extent_encryption(inode)) { + struct fscrypt_info *info; + int res; + + res = inode->i_sb->s_cop->get_extent_info(inode, lblk, &info, + offset, extent_len); + if (res == 0) + return info; + return NULL; + } + if (offset) *offset = lblk; if (extent_len) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index f32b6f0a8336..136156487e8f 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -742,6 +742,63 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode, } EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); +/** + * fscrypt_prepare_new_extent() - set up the fscrypt_info for a new extent + * @inode: the inode to which the extent belongs + * @info_ptr: a pointer to return the extent's fscrypt_info into. Should be + * a pointer to a member of the extent struct, as it will be passed + * back to the filesystem if key removal demands removal of the + * info from the extent + * @encrypt_ret: (output) set to %true if the new inode will be encrypted + * + * If the extent is part of an encrypted inode, set up its fscrypt_info in + * preparation for encrypting data and set *encrypt_ret=true. + * + * This isn't %GFP_NOFS-safe, and therefore it should be called before starting + * any filesystem transaction to create the inode. + * + * This doesn't persist the new inode's encryption context. That still needs to + * be done later by calling fscrypt_set_context(). + * + * Return: 0 on success, -ENOKEY if the encryption key is missing, or another + * -errno code + */ +int fscrypt_prepare_new_extent(struct inode *inode, + struct fscrypt_info **info_ptr, + bool *encrypt_ret) +{ + const union fscrypt_policy *policy; + u8 nonce[FSCRYPT_FILE_NONCE_SIZE]; + + policy = fscrypt_policy_to_inherit(inode); + if (policy == NULL) + return 0; + if (IS_ERR(policy)) + return PTR_ERR(policy); + + /* Only regular files can have extents. */ + if (WARN_ON_ONCE(!S_ISREG(inode->i_mode))) + return -EINVAL; + + *encrypt_ret = true; + + get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE); + return fscrypt_setup_encryption_info(inode, policy, nonce, + false, info_ptr); +} +EXPORT_SYMBOL_GPL(fscrypt_prepare_new_extent); + +/** + * fscrypt_free_extent_info() - free an extent's fscrypt_info + * @info_ptr: a pointer containing the extent's fscrypt_info pointer. + */ +void fscrypt_free_extent_info(struct fscrypt_info **info_ptr) +{ + put_crypt_info(*info_ptr); + fscrypt_set_info(info_ptr, NULL, NULL); +} +EXPORT_SYMBOL_GPL(fscrypt_free_extent_info); + /** * fscrypt_put_encryption_info() - free most of an inode's fscrypt data * @inode: an inode being evicted diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index c05e6ad3e729..6afdcb27f8a2 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -113,6 +113,29 @@ struct fscrypt_operations { int (*set_context)(struct inode *inode, const void *ctx, size_t len, void *fs_data); + /* + * Get the fscrypt_info for the given inode at the given block, for + * extent-based encryption only. + * + * @inode: the inode in question + * @lblk: the logical block number in question + * @ci: a pointer to return the fscrypt_info + * @offset: a pointer to return the offset of @lblk into the extent, + * in blocks (may be NULL) + * @extent_len: a pointer to return the number of blocks in this extent + * starting at this point (may be NULL) + * + * May cause the filesystem to allocate memory, which the filesystem + * must do with %GFP_NOFS, including calls into fscrypt to create or + * load an fscrypt_info. + * + * Return: 0 if an extent is found with an info, -ENODATA if the key is + * unavailable, or another -errno. + */ + int (*get_extent_info)(const struct inode *inode, u64 lblk, + struct fscrypt_info **ci, u64 *offset, + u64 *extent_len); + /* * Get the dummy fscrypt policy in use on the filesystem (if any). * @@ -340,6 +363,11 @@ void fscrypt_put_encryption_info(struct inode *inode); void fscrypt_free_inode(struct inode *inode); int fscrypt_drop_inode(struct inode *inode); +int fscrypt_prepare_new_extent(struct inode *inode, + struct fscrypt_info **info_ptr, + bool *encrypt_ret); +void fscrypt_free_extent_info(struct fscrypt_info **info_ptr); + /* fname.c */ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, u8 *out, unsigned int olen); @@ -597,6 +625,19 @@ static inline int fscrypt_drop_inode(struct inode *inode) return 0; } +static inline int fscrypt_prepare_new_extent(struct inode *inode, + struct fscrypt_info **info_ptr, + bool *encrypt_ret) +{ + if (IS_ENCRYPTED(inode)) + return -EOPNOTSUPP; + return 0; +} + +static inline void fscrypt_free_extent_info(struct fscrypt_info **info_ptr) +{ +} + /* fname.c */ static inline int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, From patchwork Sun Jan 1 05:06:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086328 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3FDEEC5479D for ; Sun, 1 Jan 2023 05:13:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232274AbjAAFN6 (ORCPT ); Sun, 1 Jan 2023 00:13:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50806 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229999AbjAAFNt (ORCPT ); Sun, 1 Jan 2023 00:13:49 -0500 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D7AA563EB for ; Sat, 31 Dec 2022 21:13:47 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id 19FD68265C; Sun, 1 Jan 2023 00:06:57 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549618; bh=SfbgwRvRXjakyDVaKMDHVQf4IR1C+seOS2+bYdbuWNI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qqIvraUpNpmm8JGSsr+LuhEm9MOi/T0J4kAZRmyLYcjsXEgDQPcSibxx0/QP14i4N Y8E8O0Qga7P9tvp8sttgwo8p57hCxOl6Xu+BaLbCeRILFN69yRxO9kVCK02Z+UaztW QAl15ABW5BargQiUoAXDTXnYFtteSEzprcwd+OPqcrZfWKo7FjV0Z2Fy/iuQE34FfH AL2xRIqdP6xpZphss+i/jKGnGi43JuqLUHf1zzQ7nylauptxuBOaQup5dGx0M6akhG mPn48El7g1a6cRiCsQHLtLe2R8kvbyRwVyU3Wi6bsdpz0qdh5LC8LdhCNjAW6umY7M HIxcIN9QhqD1w== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 15/17] fscrypt: allow load/save of extent contexts Date: Sun, 1 Jan 2023 00:06:19 -0500 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org The other half of using per-extent infos is saving and loading them from disk. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 50 +++++++++++++++++++++++++++++++++++++++++ fs/crypto/policy.c | 20 +++++++++++++++++ include/linux/fscrypt.h | 17 ++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 136156487e8f..82439fb73dd9 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -799,6 +799,56 @@ void fscrypt_free_extent_info(struct fscrypt_info **info_ptr) } EXPORT_SYMBOL_GPL(fscrypt_free_extent_info); +/** + * fscrypt_load_extent_info() - set up a preexisting extent's fscrypt_info + * @inode: the inode to which the extent belongs. Must be encrypted. + * @buf: a buffer containing the extent's stored context + * @len: the length of the @ctx buffer + * @info_ptr: a pointer to return the extent's fscrypt_info into. Should be + * a pointer to a member of the extent struct, as it will be passed + * back to the filesystem if key removal demands removal of the + * info from the extent + * + * This is not %GFP_NOFS safe, so the caller is expected to call + * memalloc_nofs_save/restore() if appropriate. + * + * Return: 0 if successful, or -errno if it fails. + */ +int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len, + struct fscrypt_info **info_ptr) +{ + int res; + union fscrypt_context ctx; + union fscrypt_policy policy; + + if (!fscrypt_has_encryption_key(inode)) + return -EINVAL; + + memcpy(&ctx, buf, len); + + res = fscrypt_policy_from_context(&policy, &ctx, res); + if (res) { + fscrypt_warn(inode, + "Unrecognized or corrupt encryption context"); + return res; + } + + if (!fscrypt_supported_policy(&policy, inode)) { + return -EINVAL; + } + + res = fscrypt_setup_encryption_info(inode, &policy, + fscrypt_context_nonce(&ctx), + IS_CASEFOLDED(inode) && + S_ISDIR(inode->i_mode), + info_ptr); + + if (res == -ENOPKG) /* Algorithm unavailable? */ + res = 0; + return res; +} +EXPORT_SYMBOL_GPL(fscrypt_load_extent_info); + /** * fscrypt_put_encryption_info() - free most of an inode's fscrypt data * @inode: an inode being evicted diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index e7de4872d375..aab5edc1155e 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -751,6 +751,26 @@ int fscrypt_set_context(struct inode *inode, void *fs_data) } EXPORT_SYMBOL_GPL(fscrypt_set_context); +/** + * fscrypt_set_extent_context() - Set the fscrypt context for an extent + * @ci: info from which to fetch policy and nonce + * @ctx: where context should be written + * @len: the size of ctx + * + * Given an fscrypt_info belonging to an extent (generated via + * fscrypt_prepare_new_extent()), generate a new context and write it to @ctx. + * len is checked to be at least FSCRYPT_SET_CONTEXT_MAX_SIZE bytes. + * + * Return: size of the resulting context or a negative error code. + */ +int fscrypt_set_extent_context(struct fscrypt_info *ci, void *ctx, size_t len) +{ + if (len < FSCRYPT_SET_CONTEXT_MAX_SIZE) + return -EINVAL; + return fscrypt_new_context(ctx, &ci->ci_policy, ci->ci_nonce); +} +EXPORT_SYMBOL_GPL(fscrypt_set_extent_context); + /** * fscrypt_parse_test_dummy_encryption() - parse the test_dummy_encryption mount option * @param: the mount option diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 6afdcb27f8a2..47c2df1061c7 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -324,6 +324,8 @@ int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg); int fscrypt_has_permitted_context(struct inode *parent, struct inode *child); int fscrypt_context_for_new_inode(void *ctx, struct inode *inode); int fscrypt_set_context(struct inode *inode, void *fs_data); +int fscrypt_set_extent_context(struct fscrypt_info *info, void *ctx, + size_t len); struct fscrypt_dummy_policy { const union fscrypt_policy *policy; @@ -367,6 +369,8 @@ int fscrypt_prepare_new_extent(struct inode *inode, struct fscrypt_info **info_ptr, bool *encrypt_ret); void fscrypt_free_extent_info(struct fscrypt_info **info_ptr); +int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len, + struct fscrypt_info **info_ptr); /* fname.c */ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, @@ -532,6 +536,12 @@ static inline int fscrypt_set_context(struct inode *inode, void *fs_data) return -EOPNOTSUPP; } +static inline int fscrypt_set_extent_context(struct fscrypt_info *info, + void *ctx, size_t len) +{ + return -EOPNOTSUPP; +} + struct fscrypt_dummy_policy { }; @@ -638,6 +648,13 @@ static inline void fscrypt_free_extent_info(struct fscrypt_info **info_ptr) { } +static inline int fscrypt_load_extent_info(struct inode *inode, void *buf, + size_t len, + struct fscrypt_info **info_ptr) +{ + return -EOPNOTSUPP; +} + /* fname.c */ static inline int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, From patchwork Sun Jan 1 05:06:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086313 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2E6EEC4167B for ; Sun, 1 Jan 2023 05:13:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229775AbjAAFNs (ORCPT ); Sun, 1 Jan 2023 00:13:48 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50806 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229947AbjAAFNq (ORCPT ); Sun, 1 Jan 2023 00:13:46 -0500 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 22A6D63E9 for ; Sat, 31 Dec 2022 21:13:45 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id BC9CB82670; Sun, 1 Jan 2023 00:06:59 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549620; bh=59kU/7xIENmIwXKjj5p7OjDGbHH5fEFReYyZ3dopUqE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZKu3rfANw9d3ck1QUxwCt5VWEpKOp6MJ13occV7vo2JT5aLnAzw2zlu88dr/356EB /yX0kEpIVifjl4vTKM0aMq7jm+7BYaOVGWxwI3RT75dGMbL+h4nwDQby7fKqm5/OW2 xCv7L+0ZVgq/TV0iwtwYECmi2esta7sW2pn4eRJH+XMjsG/rfDYCm4MuBrozlGgNze 7RC3YOxUAtf9j65JU02NK36NGrf7oMKjvvWClySTK8eVpKX41C2Mm9Ttz/wRH1k7cP 1iup3H9Aj9XyoyvXhnIVQVjDGQQMbXen0iELH11nHfxZHWxg3RQ3o/LjQ7x+VSg42s GftTueelwJ4Nw== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 16/17] fscrypt: disable inline encryption for extent-based encryption Date: Sun, 1 Jan 2023 00:06:20 -0500 Message-Id: <1dce5730bff1479ef9fe6a52c9dd0dfc31576b91.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org I haven't worked out how to do inline-suitable fscrypt_infos for extent-based encryption, so disable the combo for now. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/inline_crypt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 808c8712ebe7..43fb0d933ff4 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -113,6 +113,10 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci) if (!(sb->s_flags & SB_INLINECRYPT)) return 0; + /* The filesystem must not use per-extent infos */ + if (fscrypt_uses_extent_encryption(inode)) + return 0; + /* * When a page contains multiple logically contiguous filesystem blocks, * some filesystem code only calls fscrypt_mergeable_bio() for the first From patchwork Sun Jan 1 05:06:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sweet Tea Dorminy X-Patchwork-Id: 13086319 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCB5BC3DA7D for ; Sun, 1 Jan 2023 05:13:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229437AbjAAFNw (ORCPT ); Sun, 1 Jan 2023 00:13:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50794 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229589AbjAAFNr (ORCPT ); Sun, 1 Jan 2023 00:13:47 -0500 Received: from box.fidei.email (box.fidei.email [IPv6:2605:2700:0:2:a800:ff:feba:dc44]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E95A46400 for ; Sat, 31 Dec 2022 21:13:46 -0800 (PST) Received: from authenticated-user (box.fidei.email [71.19.144.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by box.fidei.email (Postfix) with ESMTPSA id A69EF8266A; Sun, 1 Jan 2023 00:07:01 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1672549622; bh=KL0C188g9dt8V5OCaIsMkxn7efCcK8iX1m7ko9JcsjU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xN6Q6qC0IxAg1SYgRWq4KG77gilR4NS+5D70ViSupI1m43/tWvUNJR7ctAdhi+RFE 89Hlx3I1ez6KQyVefMyXYpsWLrSUxwxWDHGuerLP/iQSoU6QXpsKDI3jQsTa+PbzSS xHxgAZt6bajWcrOQYrt0Uava2NgJM6cU3vw8rLGhnGIXzix/33KxyAu3TtORW/Cor4 0SetUHBs2Y0RZVzbO5vjm8+jptTf144Zlx3aD/uAQ3VUKlZdutqeeQ799Tr5oTuNlU RWBupxRG8ei7OCPC1HCq5FCbsSu+65Q4aHXMWh1Ax1Q48fvklHxVM701K/E3ZN40xZ zndxWV3D1BvZA== From: Sweet Tea Dorminy To: linux-fscrypt@vger.kernel.org, ebiggers@kernel.org, paulcrowley@google.com, linux-btrfs@vger.kernel.org, kernel-team@meta.com Cc: Sweet Tea Dorminy Subject: [RFC PATCH 17/17] fscrypt: update documentation to mention per-extent keys. Date: Sun, 1 Jan 2023 00:06:21 -0500 Message-Id: <5cb75138545bc865a42fb389519ad2adc9d2b678.1672547582.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fscrypt@vger.kernel.org Signed-off-by: Sweet Tea Dorminy --- Documentation/filesystems/fscrypt.rst | 38 ++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 5ba5817c17c2..0ff8abf89422 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -31,7 +31,7 @@ However, except for filenames, fscrypt does not encrypt filesystem metadata. Unlike eCryptfs, which is a stacked filesystem, fscrypt is integrated -directly into supported filesystems --- currently ext4, F2FS, and +directly into supported filesystems --- currently btrfs, ext4, F2FS, and UBIFS. This allows encrypted files to be read and written without caching both the decrypted and encrypted pages in the pagecache, thereby nearly halving the memory used and bringing it in line with @@ -280,6 +280,11 @@ included in the IV. Moreover: key derived using the KDF. Users may use the same master key for other v2 encryption policies. +For filesystems with extent-based content encryption (e.g. btrfs), +this is the only choice. Data shared among multiple inodes must share +the exact same key, therefore necessitating inodes using the same key +for contents encryption. + IV_INO_LBLK_64 policies ----------------------- @@ -374,12 +379,13 @@ to individual filesystems. However, authenticated encryption (AE) modes are not currently supported because of the difficulty of dealing with ciphertext expansion. -Contents encryption -------------------- +Inode-based contents encryption +------------------------------- -For file contents, each filesystem block is encrypted independently. -Starting from Linux kernel 5.5, encryption of filesystems with block -size less than system's page size is supported. +Most filesystems use the previously discussed per-file keys. For these +filesystems, for file contents, each filesystem block is encrypted +independently. Starting from Linux kernel 5.5, encryption of filesystems +with block size less than system's page size is supported. Each block's IV is set to the logical block number within the file as a little endian number, except that: @@ -403,6 +409,26 @@ Note that because file logical block numbers are included in the IVs, filesystems must enforce that blocks are never shifted around within encrypted files, e.g. via "collapse range" or "insert range". +Extent-based contents encryption +-------------------------------- + +For certain filesystems (currently only btrfs), data is encrypted on a +per-extent basis, for whatever the filesystem's notion of an extent is. The +scheme is exactly as with inode-based contents encryption, except that the +'inode number' for an extent is requested from the filesystem instead of from +the file's inode, and the 'logical block number' refers to an offset within the +extent. + +Because the encryption material is per-extent instead of per-inode, as long +as the extent's encryption context does not change, the filesystem may shift +around the position of the extent, and may have multiple files referring to +the same encrypted extent. + +Not all extents within a file are decrypted simultaneously, so it is possible +for a file read to fail partway through the file if it crosses into an extent +whose key is unavailable. However, all writes will succeed, unless the key is +removed mid-write. + Filenames encryption --------------------