Message ID | e0263ab5998ddf723b78ed56a545490e482c29b9.1693630890.git.sweettea-kernel@dorminy.me (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | fscrypt: add extent encryption | expand |
On Sat, Sep 2, 2023 at 1:56 AM Sweet Tea Dorminy <sweettea-kernel@dorminy.me> wrote: > > For contrast purposes, this patch contains the entirety of the changes > necessary to switch between lightweight and heavyweight extents. This > patch could be dropped, or rolled into the former change, without > changing anything else. > > Lightweight extents relying on their parent inode's context for > key and policy information do take up less disk space. Additionally, > they guarantee that if inode open succeeds, then all extents will be > readable and writeable, matching the current inode-based fscrypt > behavior. > > However, heavyweight extents permit greater flexibility for future > extensions: > > - Any form of changing the key for a non-empty directory's > future writes requires that extents have some sort of policy in > addition to the nonce, which is essentially the contents of the full > fscrypt_context. > - This could be approximated using overlayfs writing to a new > encrypted directory, but this would waste space used by overwritten > data and makes it very difficult to have nested subvolumes each with > their own key, so it's very preferable to support this natively in > btrfs. > > - Scrub (verifying checksums) currently iterates over extents, > without interacting with inodes; in an authenticated encryption world, > scrub verifying authentication tags would need to iterate over inodes (a > large departure from the present) or need heavyweight extents storing > the necessary key information. > I've been thinking about this patch set a bit since it was posted, and I've got some thoughts specifically about this. A use-case that is extremely important to me is enabling background encryption of parts or the whole filesystem, but also enabling rekeying the encrypted data too. This can be necessary for a variety of reasons. This is supported in LUKS/dm-crypt and I would like to have this supported in Btrfs native encryption through fscrypt. My understanding of this (after following all the discussions and patch sets) is that heavyweight extents make this a fundamentally cheaper and safer operation because there's no need to traverse through the inodes and change them. This would be fairly expensive and create a situation where inode sharing becomes much more limited as rekeying occurs on active data while not occurring on old snapshots, for example. It's certainly a trade-off that leads to more complexity, but I think it's worth it because key properties that people rely on with Btrfs can be preserved even with encrypted data. -- 真実はいつも一つ!/ Always, there's only one truth!
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 90143377cc61..4146b1380cb5 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -1061,25 +1061,25 @@ int fscrypt_load_extent_info(struct inode *inode, void *buf, size_t len, { int res; union fscrypt_context ctx; - const union fscrypt_policy *policy; + union fscrypt_policy policy; if (!fscrypt_has_encryption_key(inode)) return -EINVAL; - if (len != FSCRYPT_FILE_NONCE_SIZE) { + memcpy(&ctx, buf, len); + + res = fscrypt_policy_from_context(&policy, &ctx, len); + if (res) { fscrypt_warn(inode, "Unrecognized or corrupt encryption context"); - return -EINVAL; + return res; } - policy = fscrypt_policy_to_inherit(inode); - if (policy == NULL) - return 0; - if (IS_ERR(policy)) - return PTR_ERR(policy); + if (!fscrypt_supported_policy(&policy, inode)) + return -EINVAL; - return fscrypt_setup_extent_info(inode, policy, buf, - info_ptr); + return fscrypt_setup_extent_info(inode, &policy, + fscrypt_context_nonce(&ctx), info_ptr); } EXPORT_SYMBOL_GPL(fscrypt_load_extent_info); diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index cfbe83aee847..314bb6e97cec 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -778,10 +778,9 @@ EXPORT_SYMBOL_GPL(fscrypt_set_context); int fscrypt_set_extent_context(struct fscrypt_extent_info *ci, void *ctx, size_t len) { - if (len < FSCRYPT_EXTENT_CONTEXT_MAX_SIZE) + if (len < FSCRYPT_SET_CONTEXT_MAX_SIZE) return -EINVAL; - memcpy(ctx, ci->info.ci_nonce, FSCRYPT_FILE_NONCE_SIZE); - return FSCRYPT_FILE_NONCE_SIZE; + return fscrypt_new_context(ctx, &ci->info.ci_policy, ci->info.ci_nonce); } EXPORT_SYMBOL_GPL(fscrypt_set_extent_context);
For contrast purposes, this patch contains the entirety of the changes necessary to switch between lightweight and heavyweight extents. This patch could be dropped, or rolled into the former change, without changing anything else. Lightweight extents relying on their parent inode's context for key and policy information do take up less disk space. Additionally, they guarantee that if inode open succeeds, then all extents will be readable and writeable, matching the current inode-based fscrypt behavior. However, heavyweight extents permit greater flexibility for future extensions: - Any form of changing the key for a non-empty directory's future writes requires that extents have some sort of policy in addition to the nonce, which is essentially the contents of the full fscrypt_context. - This could be approximated using overlayfs writing to a new encrypted directory, but this would waste space used by overwritten data and makes it very difficult to have nested subvolumes each with their own key, so it's very preferable to support this natively in btrfs. - Scrub (verifying checksums) currently iterates over extents, without interacting with inodes; in an authenticated encryption world, scrub verifying authentication tags would need to iterate over inodes (a large departure from the present) or need heavyweight extents storing the necessary key information. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> --- fs/crypto/keysetup.c | 20 ++++++++++---------- fs/crypto/policy.c | 5 ++--- 2 files changed, 12 insertions(+), 13 deletions(-)