From patchwork Thu Jun 29 00:29:31 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: 13296470 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 918E8EB64DD for ; Thu, 29 Jun 2023 00:34:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230340AbjF2Aeb (ORCPT ); Wed, 28 Jun 2023 20:34:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58268 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230099AbjF2Aea (ORCPT ); Wed, 28 Jun 2023 20:34:30 -0400 X-Greylist: delayed 321 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Wed, 28 Jun 2023 17:34:28 PDT 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 AA2CE2102; Wed, 28 Jun 2023 17:34:28 -0700 (PDT) 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 BDA7480B08; Wed, 28 Jun 2023 20:34:27 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998868; bh=BANyZkPSFuy2bDBhnuzG9Pf7Z/O08lmSVAs1RBZ5k/c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qvuEU5HC9UUJuXpqbER3aDs8p1ZxFCCINKEg7TY1hvDWiq0USPmpr8Qx+Wgf48KOR zPDIDdLonnkNGpljoMeGc1qVIKt4aMu+hDfinper9VbSjR8aW48WxwOZiudS/kvhJp KiVPJ50A7vMNpmHC1xgtzlhv3Bz2Qt9Q6Y1ybO7/RuCGkALGH6N7znuGWgWREvjURG aZgtEwW9RM7iEUUZPnBwmdkm+LkkkpdX2iilRGwwN1TDg1uSz56dvX2H38BG5+5s3g cTlqg6NYF6NSU6gGqwuRqpxHuMKj3YWjsg2nqXnKccN+1cWk2qN37Puavy1RSAhhIM 2QhpO9OWUqMUA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 01/12] fscrypt: factor helper for locking master key Date: Wed, 28 Jun 2023 20:29:31 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org When we are making extent infos, we'll need to lock the master key in more places, so go on and factor out a helper. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keysetup.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index be3a84508806..6cbb42a8a537 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -106,7 +106,18 @@ select_encryption_mode(const union fscrypt_policy *policy, return ERR_PTR(-EINVAL); } -/* Create a symmetric cipher object for the given encryption mode and key */ +static int lock_master_key(struct fscrypt_master_key *mk) +{ + down_read(&mk->mk_sem); + + /* Has the secret been removed (via FS_IOC_REMOVE_ENCRYPTION_KEY)? */ + if (!is_master_key_secret_present(&mk->mk_secret)) + return -ENOKEY; + + return 0; +} + +/* Create a symmetric cipher object for the given encryption mode */ static struct crypto_skcipher * fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, const struct inode *inode) @@ -556,13 +567,10 @@ static int find_and_lock_master_key(const struct fscrypt_info *ci, *mk_ret = NULL; return 0; } - down_read(&mk->mk_sem); - /* Has the secret been removed (via FS_IOC_REMOVE_ENCRYPTION_KEY)? */ - if (!is_master_key_secret_present(&mk->mk_secret)) { - err = -ENOKEY; + err = lock_master_key(mk); + if (err) goto out_release_key; - } if (!fscrypt_valid_master_key_size(mk, ci)) { err = -ENOKEY; From patchwork Thu Jun 29 00:29:32 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: 13296471 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 AE2C7EB64DA for ; Thu, 29 Jun 2023 00:34:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230420AbjF2Aed (ORCPT ); Wed, 28 Jun 2023 20:34:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58276 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230311AbjF2Aec (ORCPT ); Wed, 28 Jun 2023 20:34:32 -0400 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 389D51FC2; Wed, 28 Jun 2023 17:34:31 -0700 (PDT) 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 7AE8180727; Wed, 28 Jun 2023 20:34:30 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998871; bh=yVWm7KLlu7NKE61m0sljinnH3SFPEiIbkY1fo9BhNoc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Wvgbg9EPF87+81vT7Co1GPGbGwrFb8Z5oam7INRolGlQurdn5+qxhzqec7+DBWHOo 7vAYCyFxrW+gdyluQRahudCbH0TDE5UnBKS1ajrWMRMPdA2GVRWKmhpVktLZNOUqtM 5Iva/NKF6IyMn4iFuEanIvZCgGA1I8F4m2c5YVpcv74gl6Kf920MIUaNv08vT/UpNX 9HpI2p187AvLpmAbB6NKKsbAmIcfh/BncENTxtI1NNbh51Q6fJempfxOvhI8rnRiFZ aumBGzDn0xY5tCIa+zCRrISdybeaoO2epA80SVTXLuQP+5p+hcRxe3jrXLP0Zww6y6 G7vAV9EOBmVXg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 02/12] fscrypt: factor getting info for a specific block Date: Wed, 28 Jun 2023 20:29:32 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@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 grabbing inode->i_crypt_info will be insufficient; the caller must specifically request the inode info or the info for a specific block. Add fscrypt_get_lblk_info() to get info for a specific block, and update all relevant callsites. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/crypto.c | 3 ++- fs/crypto/fscrypt_private.h | 29 +++++++++++++++++++++++++++++ fs/crypto/inline_crypt.c | 10 ++++++---- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 9f3bda18c797..1b7e375b1c6b 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 = inode->i_crypt_info; + 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/fscrypt_private.h b/fs/crypto/fscrypt_private.h index e726a1fb9f7e..4d1e67bc1e62 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -277,6 +277,35 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; +/** + * 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 inode->i_crypt_info; +} + + /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; int fscrypt_initialize(struct super_block *sb); diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 2063f7941ce6..885a2ec3d711 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -270,7 +270,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_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); @@ -349,21 +349,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 != inode->i_crypt_info->ci_enc_key->blk_key) + if (bc->bc_key != ci->ci_enc_key->blk_key) return false; - fscrypt_generate_dun(inode->i_crypt_info, 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); @@ -465,7 +467,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_lblk_info(inode, lblk, NULL, NULL); if (!(fscrypt_policy_flags(&ci->ci_policy) & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)) return nr_blocks; From patchwork Thu Jun 29 00:29:33 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: 13296472 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 B210FC001B1 for ; Thu, 29 Jun 2023 00:34:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230458AbjF2Aef (ORCPT ); Wed, 28 Jun 2023 20:34:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58288 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230311AbjF2Aee (ORCPT ); Wed, 28 Jun 2023 20:34:34 -0400 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 C14A01FC2; Wed, 28 Jun 2023 17:34:33 -0700 (PDT) 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 0267A80B0C; Wed, 28 Jun 2023 20:34:32 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998873; bh=BIdg34OLmPUpDpRKC4NmZKILUZwUGsXTWhefVvmTUSw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HbtL6dGLz/QYHDq9vfZbTKj3vH1lcqnvCeyLrfF1i1FGFjydG+K0hZ7yy6ZfmzXYY 2YW22OBYvsDQCeEBchs+afaSZWT7Ivu/qz7CXJTS2u9VR83p1wHEFjWvPol0MPjqsc 8FXy57z8v4UYIjYd/oQcTRwR0V2LQAgRPZIQgNFAq7qP8KuTey9N8VkO52qg2ZFbdc P6+UXZla/pw/FcCuK7XsZiB7Y6rPOAcKDjDRG+b3W0Oj2Op5Way2//GREvrpjiNzzM 0Ik4Pyb8fR5FBxg4Y9fNighQOqDzm2I6vuKtjYqN4wlwFK4oM5WC56U0CnVZQEnsDA 3JHITfWjOfkmg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 03/12] fscrypt: adjust effective lblks based on extents Date: Wed, 28 Jun 2023 20:29:33 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@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 | 3 ++- fs/crypto/inline_crypt.c | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 1b7e375b1c6b..d75f1b3f5795 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; + u64 ci_offset = 0; struct fscrypt_info *ci = - fscrypt_get_lblk_info(inode, lblk_num, NULL, NULL); + fscrypt_get_lblk_info(inode, lblk_num, &ci_offset, NULL); struct crypto_skcipher *tfm = ci->ci_enc_key->tfm; int res = 0; diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index 885a2ec3d711..689ab342ae34 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -267,12 +267,15 @@ 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); + if (!ci) + return; - 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); @@ -350,13 +353,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 @@ -365,7 +369,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); @@ -460,6 +464,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 = 0; + u64 extent_len = 0; if (!fscrypt_inode_uses_inline_crypto(inode)) return nr_blocks; @@ -467,14 +473,18 @@ 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 Thu Jun 29 00:29:34 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: 13296473 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 51A2AEB64DD for ; Thu, 29 Jun 2023 00:34:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231133AbjF2Aei (ORCPT ); Wed, 28 Jun 2023 20:34:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58298 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230470AbjF2Aeh (ORCPT ); Wed, 28 Jun 2023 20:34:37 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4C0141FC2; Wed, 28 Jun 2023 17:34:36 -0700 (PDT) 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 8CC6A80727; Wed, 28 Jun 2023 20:34:35 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998876; bh=GTvEkAuIgIHlz1mowy9K8wgGxzF1JtGO6jkIJDJvyiw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gqEx57zPGiW++2SK+uayzJ/OG9EjAcAPiLheinVkQlQULi4tlZbi++GGIiHuPN22y /niAiS/Tj170fuhCzE083Spd592pOm3pB8QKnNSHrDKaCSPgXohaA+JH3wZlrKy0Jv hH/v/jlIPbOTSR6MKscHJvE5H4xMzmSD3VYpJrdEyzbFlwgFlEgtPwrRDoKaX9VjQ6 58/t1V/+Vud1ykr0eOZB/dmfXSRmwsyF5stk5oMhEOjSo5ipEc/mYczpeh+fHBpqWa hSZDegOV9TlcOqoRwh8IHT5dwAJn+pQslAG/sP5D2zy5Z/6ywQlaJMyu4DzAfOFvwk QFENU+Mac7B/A== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 04/12] fscrypt: add a super_block pointer to fscrypt_info Date: Wed, 28 Jun 2023 20:29:34 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@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 | 4 ++-- fs/crypto/keysetup.c | 10 +++++----- fs/crypto/keysetup_v1.c | 6 +++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 4d1e67bc1e62..c04454c289fd 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -241,6 +241,9 @@ struct fscrypt_info { /* Back-pointer to the inode */ struct inode *ci_inode; + /* The superblock of the filesystem to which this 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 689ab342ae34..f1a610a0f6bf 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; @@ -155,7 +155,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 6cbb42a8a537..67a5749a9543 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -250,8 +250,7 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, struct fscrypt_prepared_key *prep_key, const struct fscrypt_info *ci) { - const struct inode *inode = ci->ci_inode; - const struct super_block *sb = inode->i_sb; + const struct super_block *sb = ci->ci_sb; unsigned int policy_flags = fscrypt_policy_flags(&ci->ci_policy); struct fscrypt_mode *mode = ci->ci_mode; const u8 mode_num = mode - fscrypt_modes; @@ -525,7 +524,7 @@ static bool fscrypt_valid_master_key_size(const struct fscrypt_master_key *mk, static int find_and_lock_master_key(const struct fscrypt_info *ci, struct fscrypt_master_key **mk_ret) { - struct super_block *sb = ci->ci_inode->i_sb; + struct super_block *sb = ci->ci_sb; struct fscrypt_key_specifier mk_spec; struct fscrypt_master_key *mk; int err; @@ -599,7 +598,7 @@ static void put_crypt_info(struct fscrypt_info *ci) if (type == FSCRYPT_KEY_DIRECT_V1) fscrypt_put_direct_key(ci->ci_enc_key); if (type == FSCRYPT_KEY_PER_INFO) { - fscrypt_destroy_prepared_key(ci->ci_inode->i_sb, + fscrypt_destroy_prepared_key(ci->ci_sb, ci->ci_enc_key); kfree_sensitive(ci->ci_enc_key); } @@ -616,7 +615,7 @@ static void put_crypt_info(struct fscrypt_info *ci) spin_lock(&mk->mk_decrypted_inodes_lock); list_del(&ci->ci_master_key_link); spin_unlock(&mk->mk_decrypted_inodes_lock); - fscrypt_put_master_key_activeref(ci->ci_inode->i_sb, mk); + fscrypt_put_master_key_activeref(ci->ci_sb, mk); } memzero_explicit(ci, sizeof(*ci)); kmem_cache_free(fscrypt_info_cachep, ci); @@ -642,6 +641,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 1e785cedead0..41d317f08aeb 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -235,7 +235,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; dk->dk_key.type = FSCRYPT_KEY_DIRECT_V1; @@ -309,8 +309,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 Thu Jun 29 00:29:35 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: 13296474 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 7FFCFC001B0 for ; Thu, 29 Jun 2023 00:34:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230470AbjF2Ael (ORCPT ); Wed, 28 Jun 2023 20:34:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58306 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230311AbjF2Aej (ORCPT ); Wed, 28 Jun 2023 20:34:39 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E0DC11FC2; Wed, 28 Jun 2023 17:34:38 -0700 (PDT) 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 1E1EF80B08; Wed, 28 Jun 2023 20:34:37 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998878; bh=5QOeWXF39VG4eTOdkVZEzpQcyOFLzHDC+snBZKaf5vo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Qz3y1jbr7rfKdbz22l4cCQWgjmgFBX0CjK2Wx+TiPKLUQwM5Kz8gAUVznKEN0Guej 8qlWr1yoaVcPGhfJ6lOWx2F5G6SnmYj57OYQdAJh9RpmUQCkMZgL01augb2o/3nuw7 g1KCNZppaQ1YHacRPDo9FMb2eGzxLA0Wgmm1P/D18dkS/n12jfpsZRtdhsNZz/v2/f /VVpwGkTJIDPGFh+jv1UQjpLUFlZNMokvrvrNljMttqmffeOaqr7RIGYsKfse541sM Av137LjSOtpZEuJ7hEaEGxsGL+KCEOxczPFxGRKDJiDNN23ISw0XCD6lQgjEQQ0f+1 rYYbuz+Ad/qvw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 05/12] fscrypt: setup leaf inodes for extent encryption Date: Wed, 28 Jun 2023 20:29:35 -0400 Message-Id: <703b51d9bd9897ddb0b290e24a1260647c96eb6f.1687988246.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org For extent-based encryption, leaf/regular file inodes are special: it's useful to set their i_crypt_info field so that it's easy to inherit their encryption policy for a new extent, but they never need to do any encyption themselves. Additionally, since encryption can only be set up on a directory, not a single file, their encryption policy can always duplicate their parent inode's policy. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 17 +++++++++++++ fs/crypto/keysetup.c | 49 ++++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index c04454c289fd..260635e8b558 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -308,6 +308,23 @@ fscrypt_get_lblk_info(const struct inode *inode, u64 lblk, u64 *offset, return inode->i_crypt_info; } +/** + * fscrypt_uses_extent_encryption() -- whether an inode uses per-extent + * encryption + * + * @inode: the inode in question + * + * Return: true if the inode uses per-extent fscrypt_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 filesystems currently use per-extent infos + return false; +} /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 67a5749a9543..d79a42a54906 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -747,27 +747,48 @@ fscrypt_setup_encryption_info(struct inode *inode, int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) { int res; - union fscrypt_context ctx; + union fscrypt_context ctx = { 0 }; union fscrypt_policy policy; if (fscrypt_has_encryption_key(inode)) return 0; - res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); - if (res < 0) { - if (res == -ERANGE && allow_unsupported) - return 0; - fscrypt_warn(inode, "Error %d getting encryption context", res); - return res; - } + if (fscrypt_uses_extent_encryption(inode)) { + /* + * Nothing will be encrypted with this info, so we can borrow + * the parent (dir) inode's policy and use a zero nonce. + */ + struct dentry *dentry = d_find_any_alias(inode); + struct dentry *parent_dentry = dget_parent(dentry); + struct inode *dir = parent_dentry->d_inode; + bool found = false; - res = fscrypt_policy_from_context(&policy, &ctx, res); - if (res) { - if (allow_unsupported) + if (dir->i_crypt_info) { + found = true; + policy = dir->i_crypt_info->ci_policy; + nonce = dir->i_crypt_info->ci_nonce; + } + dput(parent_dentry); + dput(dentry); + if (!found) return 0; - fscrypt_warn(inode, - "Unrecognized or corrupt encryption context"); - return res; + } else { + res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); + if (res < 0) { + if (res == -ERANGE && allow_unsupported) + return 0; + fscrypt_warn(inode, "Error %d getting encryption context", res); + return res; + } + + res = fscrypt_policy_from_context(&policy, &ctx, res); + if (res) { + if (allow_unsupported) + return 0; + fscrypt_warn(inode, + "Unrecognized or corrupt encryption context"); + return res; + } } if (!fscrypt_supported_policy(&policy, inode)) { From patchwork Thu Jun 29 00:29:36 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: 13296475 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 DBF6CEB64D7 for ; Thu, 29 Jun 2023 00:34:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230311AbjF2Aeo (ORCPT ); Wed, 28 Jun 2023 20:34:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58338 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231163AbjF2Aen (ORCPT ); Wed, 28 Jun 2023 20:34:43 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 73135210E; Wed, 28 Jun 2023 17:34:41 -0700 (PDT) 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 C27FF80727; Wed, 28 Jun 2023 20:34:40 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998881; bh=DLqq2HY+W5zb44E3MxJifBgNp4jqCXCAnFCmU+FEj9Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wTB+/VWscN9wFP07k6HDp3hrdwn1Bv131vqwzl25YKxbgtfSl6veDw/Y1scLC+9J/ iPAyVSjQxXcS7Ja/Ufuy8N26/HE2dSdrnCyDq5oqWrPa7/hirYIlEQ311joVjibSfw Sck7FJAXEl1MxmU0tzyKlDe78e/iT07Cmayse2ksCo5kj8EVJUNNr1eojXrq0ltIKn S42iGHTC0v3iLn2Yyd3KcAxqB+dhfHoUwcxFTyR7bgX01nyLM6nMhFR3JSHpJbH0dK GYM5aNrhHQh3vqtZ9JN1/aLe9qxumiedAmYxhEQnjN0kX0WMpJhg9Z6j7GOVT0kzTv Ns+1+DYRu3aRQ== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 06/12] fscrypt: allow infos to be owned by extents Date: Wed, 28 Jun 2023 20:29:36 -0400 Message-Id: <0146ec71756e5b5b409d9c1b41d3e81bc957b5b8.1687988246.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@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 | 49 ++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 260635e8b558..1674e66e72e3 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -241,6 +241,12 @@ struct fscrypt_info { /* Back-pointer to the 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 info pertains */ struct super_block *ci_sb; diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index d79a42a54906..1aa5b2a0096e 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -625,12 +625,17 @@ 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; struct fscrypt_master_key *mk = NULL; int res; + bool info_for_extent = !!info_ptr; + + if (!info_ptr) + info_ptr = &inode->i_crypt_info; res = fscrypt_initialize(inode->i_sb); if (res) @@ -640,7 +645,11 @@ fscrypt_setup_encryption_info(struct inode *inode, if (!crypt_info) return -ENOMEM; - crypt_info->ci_inode = inode; + if (fscrypt_uses_extent_encryption(inode) && info_for_extent) + 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); @@ -656,6 +665,12 @@ fscrypt_setup_encryption_info(struct inode *inode, res = fscrypt_select_encryption_impl(crypt_info); if (res) goto out; + if (info_for_extent && !fscrypt_using_inline_encryption(crypt_info)) { + fscrypt_warn(inode, + "extent encryption requires inlinecrypt mount option"); + res = -EINVAL; + goto out; + } res = find_and_lock_master_key(crypt_info, &mk); if (res) @@ -701,7 +716,7 @@ fscrypt_setup_encryption_info(struct inode *inode, * 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) { + if (cmpxchg_release(info_ptr, 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. @@ -735,7 +750,7 @@ fscrypt_setup_encryption_info(struct inode *inode, * %false unless the operation being performed is needed in * order for files (or directories) to be deleted. * - * Set up ->i_crypt_info, if it hasn't already been done. + * Set up inode->i_crypt_info, if it hasn't already been done. * * Note: unless ->i_crypt_info is already set, this isn't %GFP_NOFS-safe. So * generally this shouldn't be called from within a filesystem transaction. @@ -747,8 +762,9 @@ fscrypt_setup_encryption_info(struct inode *inode, int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) { int res; - union fscrypt_context ctx = { 0 }; + union fscrypt_context ctx; union fscrypt_policy policy; + const u8 *nonce; if (fscrypt_has_encryption_key(inode)) return 0; @@ -756,7 +772,7 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) if (fscrypt_uses_extent_encryption(inode)) { /* * Nothing will be encrypted with this info, so we can borrow - * the parent (dir) inode's policy and use a zero nonce. + * the parent (dir) inode's policy and nonce. */ struct dentry *dentry = d_find_any_alias(inode); struct dentry *parent_dentry = dget_parent(dentry); @@ -789,6 +805,7 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) "Unrecognized or corrupt encryption context"); return res; } + nonce = fscrypt_context_nonce(&ctx); } if (!fscrypt_supported_policy(&policy, inode)) { @@ -797,10 +814,10 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) return -EINVAL; } - res = fscrypt_setup_encryption_info(inode, &policy, - fscrypt_context_nonce(&ctx), + res = fscrypt_setup_encryption_info(inode, &policy, nonce, IS_CASEFOLDED(inode) && - S_ISDIR(inode->i_mode)); + S_ISDIR(inode->i_mode), + NULL); if (res == -ENOPKG && allow_unsupported) /* Algorithm unavailable? */ res = 0; @@ -834,7 +851,8 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode, bool *encrypt_ret) { const union fscrypt_policy *policy; - u8 nonce[FSCRYPT_FILE_NONCE_SIZE]; + u8 nonce_bytes[FSCRYPT_FILE_NONCE_SIZE]; + const u8 *nonce; policy = fscrypt_policy_to_inherit(dir); if (policy == NULL) @@ -856,10 +874,17 @@ int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode, *encrypt_ret = true; - get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE); + if (fscrypt_uses_extent_encryption(inode)) { + nonce = dir->i_crypt_info->ci_nonce; + } else { + get_random_bytes(nonce_bytes, FSCRYPT_FILE_NONCE_SIZE); + nonce = nonce_bytes; + } + return fscrypt_setup_encryption_info(inode, policy, nonce, IS_CASEFOLDED(dir) && - S_ISDIR(inode->i_mode)); + S_ISDIR(inode->i_mode), + NULL); } EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode); From patchwork Thu Jun 29 00:29:37 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: 13296476 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 CF271C001B0 for ; Thu, 29 Jun 2023 00:34:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231207AbjF2Aet (ORCPT ); Wed, 28 Jun 2023 20:34:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58358 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231169AbjF2Aep (ORCPT ); Wed, 28 Jun 2023 20:34:45 -0400 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 69A3E1FC2; Wed, 28 Jun 2023 17:34:44 -0700 (PDT) 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 3191580B08; Wed, 28 Jun 2023 20:34:43 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998884; bh=c0ZpFqyAVXIr8pO5aROXx6op1NfcoKbP2yZeD+lzIGA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Rr3nvXEu0O4RY6fAC4+AXC8MPu1n2mgpcJRHW6U5V+D9YVivvApO3b8wxJJ0m0EKt uE2ANX2c5EM3+IGxmfQDbsWVGEa1M539K+xubrMGO00i6YQEolaXRFO7ZGEhclxyJn w2K3ZzOM5kXFaCuJIvi0tXCLbPM0uWL/1rm1cdn3tz+2VdJc7Vu8a+GRjUJyDRVrcY dL2KZIb/4rjKyjuU9qqikEnI+yECzv7+Tn6kerg+bOcgctZDZowBKTBkr3NtE2ardX 6cEpXuU7e5TL139U/926yBZuRsK3C8txqciDuLYd7sWS/lsWAqbI4aCAoTggYP+qhT UeNmcwaWeG7kA== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 07/12] fscrypt: notify per-extent infos if master key vanishes Date: Wed, 28 Jun 2023 20:29:37 -0400 Message-Id: <0d2d18a27ed7a24cbca6d3fe8b33f6677e541dfd.1687988246.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org When fscrypt_infos can be owned by an extent, we need some way to attempt to evict the extent infos in the same way we evict inodes. This change adds a function pointer to allow a filesystem to optionally provide a way to evict extents; locking if needed must be handled by the filesystem. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/keyring.c | 11 ++++++++++- include/linux/fscrypt.h | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 7cbb1fd872ac..0aad825087c1 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -875,6 +875,16 @@ static void evict_dentries_for_decrypted_inodes(struct fscrypt_master_key *mk) list_for_each_entry(ci, &mk->mk_decrypted_inodes, ci_master_key_link) { inode = ci->ci_inode; + if (!inode) { + if (!ci->ci_sb->s_cop->forget_extent_info) + continue; + + spin_unlock(&mk->mk_decrypted_inodes_lock); + ci->ci_sb->s_cop->forget_extent_info(ci->ci_info_ptr); + spin_lock(&mk->mk_decrypted_inodes_lock); + continue; + } + spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) { spin_unlock(&inode->i_lock); @@ -887,7 +897,6 @@ static void evict_dentries_for_decrypted_inodes(struct fscrypt_master_key *mk) shrink_dcache_inode(inode); iput(toput_inode); toput_inode = inode; - spin_lock(&mk->mk_decrypted_inodes_lock); } diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index c895b12737a1..378a1f41c62f 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 From patchwork Thu Jun 29 00:29:38 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: 13296477 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 C07CEC001DB for ; Thu, 29 Jun 2023 00:34:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229622AbjF2Aeu (ORCPT ); Wed, 28 Jun 2023 20:34:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231285AbjF2Aer (ORCPT ); Wed, 28 Jun 2023 20:34:47 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 67F021FC2; Wed, 28 Jun 2023 17:34:46 -0700 (PDT) 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 9EFD780727; Wed, 28 Jun 2023 20:34:45 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998886; bh=Y0WDotJSfCnJc4p490NH9YnL9447SClLpBHKbbUWyCE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BE5sMLUHlyCudejWT8VP5EccJE4/MnHk+9w/SLomuLw/gvA9oVBaXfHqS2xTjFtJW YBdAAa/XuK74vjum5ihliYW4UpmyYAPI1K5HLpy1vw37FYJs4Bl+bQDz5E0PGKg4f5 R68fzSQhXKUOkyeDBSas9/eetNAfoBKS7XnUUa+gGTKnIT0lmZPo1PEbImys9dMKLD Y/I064wWcrEsj3pEB/UCjmebVczP2DYYskwSGOfFbzjQPgkG2lwTSDgEa3yDzSoPad kwhcZSIihUgXiW2df0qWyim3M+rlVsnQZwevC17FU5JIEm/WUskoSP3BqKNFAH5cn5 TUljrsDwgFYQg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 08/12] fscrypt: use an optional ino equivalent for per-extent infos Date: Wed, 28 Jun 2023 20:29:38 -0400 Message-Id: In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@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/fscrypt_private.h | 18 ++++++++++++++++++ fs/crypto/keyring.c | 8 ++++---- fs/crypto/keysetup.c | 6 +++--- include/linux/fscrypt.h | 9 +++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 1674e66e72e3..8bf27ceeecd1 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -332,6 +332,24 @@ static inline bool fscrypt_uses_extent_encryption(const struct inode *inode) return false; } +/** + * fscrypt_get_info_ino() - get the ino or ino equivalent for an info + * + * @ci: the fscrypt_info in question + * + * Return: 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(struct super_block *sb); diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 0aad825087c1..bfcd2ecbe481 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -923,12 +923,12 @@ static int check_for_busy_inodes(struct super_block *sb, } { - /* select an example file to show for debugging purposes */ - struct inode *inode = + /* select an example info to show for debugging purposes */ + struct fscrypt_info *ci = list_first_entry(&mk->mk_decrypted_inodes, 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_decrypted_inodes_lock); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 1aa5b2a0096e..f166fabb7f73 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -380,10 +380,10 @@ 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_ONCE(ci->ci_inode->i_ino == 0); + WARN_ON_ONCE(fscrypt_get_info_ino(ci) == 0); WARN_ON_ONCE(!mk->mk_ino_hash_key_initialized); - ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino, + ci->ci_hashed_ino = (u32)siphash_1u64(fscrypt_get_info_ino(ci), &mk->mk_ino_hash_key); } @@ -706,7 +706,7 @@ fscrypt_setup_encryption_info(struct inode *inode, if (res) goto out; - if (inode->i_ino) + if (fscrypt_get_info_ino(crypt_info)) fscrypt_hash_inode_number(crypt_info, mk); } diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 378a1f41c62f..22affbb15706 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -169,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 Thu Jun 29 00:29:39 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: 13296478 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 05AD5C001B1 for ; Thu, 29 Jun 2023 00:34:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231317AbjF2Aev (ORCPT ); Wed, 28 Jun 2023 20:34:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58386 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231305AbjF2Aet (ORCPT ); Wed, 28 Jun 2023 20:34:49 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 455F61FC2; Wed, 28 Jun 2023 17:34:48 -0700 (PDT) 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 D22BF80B08; Wed, 28 Jun 2023 20:34:47 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998888; bh=8v03nnczaIeh7mNlBa4A7aeLNxXZn5vYckHRNeknOOk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nImJzyVHzC3hNlt9+uUmuFQsosZug3xD90vrPV2Krw+7bhbFV011ta7SqH9p23Uf1 p2W6Ka5vekNnz45lqT4BaV1rIpgEskjXQHk3eUaZU4RWmhpi4lW9jn9Pw0xIwEBSMy p4u9aVC41Br8Zw3ACAOzIRU23LTYlXof0ZL+C4BG95KDYCOlxM2c6pvnrkIlfo+3R/ 1W43ZNmaFoE4Djcovrv3pwwpR+pAGdu5nh/J96VNnWxZLL6wQoZmFnjOI9wzcwkrvs XS8iIqCIFmKPPk7rrcLdluyOFbseBJMKezt3ZIpRSHtaMFIKpqM0A/YRL8K6QME22S nCbQqrUPZ/PGw== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 09/12] fscrypt: add creation/usage/freeing of per-extent infos Date: Wed, 28 Jun 2023 20:29:39 -0400 Message-Id: <69695a1673993911f080ea16d565055fa619ffee.1687988246.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@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 | 2 ++ fs/crypto/fscrypt_private.h | 46 ++++++++++++++++++----------- fs/crypto/keyring.c | 15 +++++++++- fs/crypto/keysetup.c | 59 +++++++++++++++++++++++++++++++++++-- include/linux/fscrypt.h | 39 ++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 21 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index d75f1b3f5795..0f0c721e40fe 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -113,6 +113,8 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, struct crypto_skcipher *tfm = ci->ci_enc_key->tfm; int res = 0; + if (!ci) + return -EINVAL; if (WARN_ON_ONCE(len <= 0)) return -EINVAL; if (WARN_ON_ONCE(len % FSCRYPT_CONTENTS_ALIGNMENT != 0)) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 8bf27ceeecd1..5eafa50a3298 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -286,6 +286,23 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; +/** + * fscrypt_uses_extent_encryption() -- whether an inode uses per-extent + * encryption + * + * @inode: the inode in question + * + * Return: true if the inode uses per-extent fscrypt_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; + + return !!inode->i_sb->s_cop->get_extent_info; +} + /** * fscrypt_get_lblk_info() - get the fscrypt_info to crypt a particular block * @@ -306,6 +323,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) @@ -314,24 +342,6 @@ fscrypt_get_lblk_info(const struct inode *inode, u64 lblk, u64 *offset, return inode->i_crypt_info; } -/** - * fscrypt_uses_extent_encryption() -- whether an inode uses per-extent - * encryption - * - * @inode: the inode in question - * - * Return: true if the inode uses per-extent fscrypt_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 filesystems currently use per-extent infos - return false; -} - /** * fscrypt_get_info_ino() - get the ino or ino equivalent for an info * diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index bfcd2ecbe481..93f99b0fc20a 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -875,7 +875,7 @@ static void evict_dentries_for_decrypted_inodes(struct fscrypt_master_key *mk) list_for_each_entry(ci, &mk->mk_decrypted_inodes, ci_master_key_link) { inode = ci->ci_inode; - if (!inode) { + if (ci->ci_info_ptr) { if (!ci->ci_sb->s_cop->forget_extent_info) continue; @@ -1036,6 +1036,19 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users) mk = fscrypt_find_master_key(sb, &arg.key_spec); if (!mk) return -ENOKEY; + + /* + * For filesystems with extent encryption, there may be extents which + * need to come into existence and get the key, lest their data be + * stuck in memory and not be flushable for lack of key. So just sync + * the filesystem to encourage all the dirty pages to be written out. + */ + if (sb->s_cop->get_extent_info) { + down_read(&sb->s_umount); + sync_filesystem(sb); + up_read(&sb->s_umount); + } + down_write(&mk->mk_sem); /* If relevant, remove current user's (or all users) claim to the key */ diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index f166fabb7f73..0efa2800b50d 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -647,8 +647,8 @@ fscrypt_setup_encryption_info(struct inode *inode, if (fscrypt_uses_extent_encryption(inode) && info_for_extent) crypt_info->ci_info_ptr = info_ptr; - else - crypt_info->ci_inode = inode; + + crypt_info->ci_inode = inode; crypt_info->ci_sb = inode->i_sb; crypt_info->ci_policy = *policy; @@ -662,6 +662,7 @@ fscrypt_setup_encryption_info(struct inode *inode, WARN_ON_ONCE(mode->ivsize > FSCRYPT_MAX_IV_SIZE); crypt_info->ci_mode = mode; + pr_err("fsei1"); res = fscrypt_select_encryption_impl(crypt_info); if (res) goto out; @@ -888,6 +889,60 @@ 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) +{ + 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; + + 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); + *info_ptr = 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 22affbb15706..1965b900f62f 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). * @@ -348,6 +371,10 @@ 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); +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); @@ -609,6 +636,18 @@ 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) +{ + 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 Thu Jun 29 00:29:40 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: 13296479 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 311CBC001DE for ; Thu, 29 Jun 2023 00:34:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231293AbjF2Aew (ORCPT ); Wed, 28 Jun 2023 20:34:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58396 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231285AbjF2Aev (ORCPT ); Wed, 28 Jun 2023 20:34:51 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10B96210E; Wed, 28 Jun 2023 17:34:50 -0700 (PDT) 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 7976180727; Wed, 28 Jun 2023 20:34:49 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998889; bh=yk12HUPAnXYWMby3ezkN2KaffBIK1o/8QvPuAZitzlw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=heSTIYk5rLoH22R0RVEANLxdeRVuym+6D3a35QxYgV/9WjMfsommtO90WUu9+pLV/ pKLF9fZG3UOM1sYaLSqn2R23E/nZVmI3YRAPOhEwYOPp4aXnlnJAiqGTzNzKI4gkN+ VRv7I84Q9jSI5Jqmv4Nk8fKHtr/XyTy7JEDdGglO4qeK/6gqIuhVad4OA+6UZBPIUt PzUcyXEguYuFm5UmvstQVTVfAoBfxeGOj4kflNZKOOW4y2JjOOIyhyAc+3TAopudcY QmguTS6OEBh2+5cTcSk9uIVZFECHOIUkwKGhIiUYIA4zQlIq5e2C1hNczq0IHJSM1B 1z+FdI4waOG4A== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 10/12] fscrypt: allow load/save of extent contexts Date: Wed, 28 Jun 2023 20:29:40 -0400 Message-Id: <812beca69e0f3a9f96b0d079b79f5f7f1f442a29.1687988246.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@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, 86 insertions(+), 1 deletion(-) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 0efa2800b50d..50fa8955ae2c 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -819,7 +819,6 @@ int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported) IS_CASEFOLDED(inode) && S_ISDIR(inode->i_mode), NULL); - if (res == -ENOPKG && allow_unsupported) /* Algorithm unavailable? */ res = 0; if (res == -ENOKEY) @@ -943,6 +942,55 @@ 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, len); + 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 f4456ecb3f87..9ecb01e49d33 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -762,6 +762,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 1965b900f62f..9c7255b48f1d 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -334,6 +334,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; @@ -374,6 +376,8 @@ int fscrypt_drop_inode(struct inode *inode); int fscrypt_prepare_new_extent(struct inode *inode, struct fscrypt_info **info_ptr); 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, @@ -550,6 +554,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 { }; @@ -648,6 +658,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 Thu Jun 29 00:29:41 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: 13296480 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 33AC6EB64DD for ; Thu, 29 Jun 2023 00:34:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231340AbjF2Aey (ORCPT ); Wed, 28 Jun 2023 20:34:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231169AbjF2Aew (ORCPT ); Wed, 28 Jun 2023 20:34:52 -0400 Received: from box.fidei.email (box.fidei.email [71.19.144.250]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D34F1FC2; Wed, 28 Jun 2023 17:34:51 -0700 (PDT) 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 12DD080B08; Wed, 28 Jun 2023 20:34:50 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998891; bh=yT+T/CU256NsOeG+y9Jts+NtvBICj/npbIOSdxl6kVI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EzZT/dw1aegN2l+yDpghXsX0Lm1disa882zzEVZ/YPd20ClKQczWAI+z/YpupcCc/ q8KcW8EoPCtiIaoeCOzPb3aVf3tzuJXjKOlCotEvvs9bXrwIWSqD+cygN9aGNdabTt np1pf8DgLblSOiJzDNgxQmmfObI503Ijtu599k5If8/mzvOK93eNkQ4X8auiFfJ1F/ trL8zUR5EGjEcBgeUFiLNsP4Iy0dkPWfTKACsEhvDrjl+HhdhV0rFxO1aiMr2WZOyR hv2UTw2W3/PAn/Jv4PIviSEHZX+bt4AX/OSM1j/unf9aIR6MgtBuV/3oEFK+X2oAzF DMNbdgclplL4w== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 11/12] fscrypt: save session key credentials for extent infos Date: Wed, 28 Jun 2023 20:29:41 -0400 Message-Id: <0c8d98959d1498611452be66fe5704773ac860d1.1687988246.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org For v1 encryption policies using per-session keys, the thread which opens the inode and therefore initializes the encryption info is part of the session, so it can get the key from the session keyring. However, for extent encryption, the extent infos are likely loaded from a different thread, which does not have access to the session keyring. This change saves the credentials of the inode opening thread and reuses those credentials temporarily when dealing with extent infos, allowing finding the encryption key correctly. v1 encryption policies using per-session keys should probably not exist for new usages such as extent encryption, but this makes more tests work without change; maybe the right answer is to disallow v1 session keys plus extent encryption and deal with editing tests to not use v1 session encryption so much. Signed-off-by: Sweet Tea Dorminy --- fs/crypto/fscrypt_private.h | 8 ++++++++ fs/crypto/keysetup.c | 13 +++++++++++++ fs/crypto/keysetup_v1.c | 1 + 3 files changed, 22 insertions(+) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 5eafa50a3298..5c7649717aac 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -231,6 +231,14 @@ struct fscrypt_info { */ bool ci_inlinecrypt; #endif + /* Credential struct from the thread which created this info. This is + * only used in v1 session keyrings with extent encryption; it allows + * the thread creating extents for an inode to join the session + * keyring temporarily, since otherwise the thread is usually part of + * kernel writeback and therefore unrelated to the thread with the + * right session key. + */ + struct cred *ci_session_creds; /* * Encryption mode used for this inode. It corresponds to either the diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 50fa8955ae2c..cfe0f93919fe 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -617,6 +617,8 @@ static void put_crypt_info(struct fscrypt_info *ci) spin_unlock(&mk->mk_decrypted_inodes_lock); fscrypt_put_master_key_activeref(ci->ci_sb, mk); } + if (ci->ci_session_creds) + abort_creds(ci->ci_session_creds); memzero_explicit(ci, sizeof(*ci)); kmem_cache_free(fscrypt_info_cachep, ci); } @@ -633,6 +635,7 @@ fscrypt_setup_encryption_info(struct inode *inode, struct fscrypt_master_key *mk = NULL; int res; bool info_for_extent = !!info_ptr; + const struct cred *creds = NULL; if (!info_ptr) info_ptr = &inode->i_crypt_info; @@ -677,7 +680,17 @@ fscrypt_setup_encryption_info(struct inode *inode, if (res) goto out; + if (info_for_extent && inode->i_crypt_info->ci_session_creds) + creds = override_creds(inode->i_crypt_info->ci_session_creds); + /* + * The inode this is being created for is using a session key, + * so we have to join this thread to that session temporarily + * in order to be able to find the right key... + */ + res = fscrypt_setup_file_key(crypt_info, mk); + if (creds) + revert_creds(creds); if (res) goto out; diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 41d317f08aeb..4f2be2377dfa 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -318,6 +318,7 @@ int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci) return PTR_ERR(key); err = fscrypt_setup_v1_file_key(ci, payload->raw); + ci->ci_session_creds = prepare_creds(); up_read(&key->sem); key_put(key); return err; From patchwork Thu Jun 29 00:29:42 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: 13296481 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 05742EB64DD for ; Thu, 29 Jun 2023 00:34:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230526AbjF2Ae4 (ORCPT ); Wed, 28 Jun 2023 20:34:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58414 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231169AbjF2Aey (ORCPT ); Wed, 28 Jun 2023 20:34:54 -0400 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 918681FC2; Wed, 28 Jun 2023 17:34:53 -0700 (PDT) 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 9927680727; Wed, 28 Jun 2023 20:34:52 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=dorminy.me; s=mail; t=1687998893; bh=OU3phguMvW6dB4K+YYW4zI9XIY0ZO0OgTtdZGLxn5UQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wi8h+uGAIz/FpxQu/0pNrDjn1DWsZPLLMzZh0kkftOfnJqbbEhR8TZreMaxjqk1wq CS1M3LmqKIKwdZy8FgZmsEi1ys5eaSmYaWGdAhq+h41X+zGDfrg2M8py/sS/JICzBW omL+N7XwTTs5ePXlW+4jcyTdr2+QpVRIagnAhjdrE2Qc0v+mVxX7W41ncKs6XmZeaL drvSDATB4/7UGbMc7ygfDzniu26pD6RRS+S9WPBAOQSgrADtFoJqmDQn6mA9D9ndrC BBbGod9ruSNpKkGfPjmGMMAEsvb4oVQClhOxvfbh1Fh9qR+ym4hHWxnFkj+W8unzCN qS7uz5MYDNshg== From: Sweet Tea Dorminy To: Chris Mason , Josef Bacik , David Sterba , Eric Biggers , "Theodore Y. Ts'o" , Jaegeuk Kim , kernel-team@meta.com, linux-btrfs@vger.kernel.org, linux-fscrypt@vger.kernel.org Cc: Sweet Tea Dorminy Subject: [PATCH v1 12/12] fscrypt: update documentation for per-extent keys Date: Wed, 28 Jun 2023 20:29:42 -0400 Message-Id: <212cb3d0b8f4abf657671f05dbe0b3d9d858211d.1687988246.git.sweettea-kernel@dorminy.me> In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Add some documentation of how extent-based encryption works, hopefully enough for future filesystem users. 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 eccd327e6df5..9bbfcd84a29f 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 ----------------------- @@ -381,12 +386,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: @@ -410,6 +416,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 --------------------