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@xxxxxxxxxx> --- fs/crypto/keysetup.c | 20 ++++++++++---------- fs/crypto/policy.c | 5 ++--- 2 files changed, 12 insertions(+), 13 deletions(-) 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); -- 2.41.0