On Mon, Sep 05, 2022 at 08:35:20PM -0400, Sweet Tea Dorminy wrote: > Some filesystems need to encrypt data based on extents, rather than on > inodes, due to features incompatible with inode-based encryption. For > instance, btrfs can have multiple inodes referencing a single block of > data, and moves logical data blocks to different physical locations on > disk in the background; these two features mean inode or > physical-location-based policies will not work for btrfs. > > This change introduces fscrypt_extent_context objects, in analogy to > existing context objects based on inodes. For a filesystem which uses > extents, a new hook provides a new fscrypt_extent_context. During file > content encryption/decryption, the existing fscrypt_context object > provides key information, while the new fscrypt_extent_context provides > IV information. For filename encryption, the existing IV generation > methods are still used, since filenames are not stored in extents. > > As individually keyed inodes prevent sharing of extents, such policies > are forbidden for filesystems with extent-based encryption. > > Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx> > --- > fs/crypto/crypto.c | 15 +++++++- > fs/crypto/fscrypt_private.h | 26 ++++++++++++- > fs/crypto/inline_crypt.c | 29 +++++++++++--- > fs/crypto/policy.c | 77 +++++++++++++++++++++++++++++++++++++ > include/linux/fscrypt.h | 41 ++++++++++++++++++++ > 5 files changed, 178 insertions(+), 10 deletions(-) > > diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c > index 7fe5979fbea2..77537736096b 100644 > --- a/fs/crypto/crypto.c > +++ b/fs/crypto/crypto.c > @@ -81,8 +81,19 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, > const struct fscrypt_info *ci) > { > u8 flags = fscrypt_policy_flags(&ci->ci_policy); > + struct inode *inode = ci->ci_inode; > + const struct fscrypt_operations *s_cop = inode->i_sb->s_cop; > > memset(iv, 0, ci->ci_mode->ivsize); > + if (s_cop->get_extent_context && lblk_num != U64_MAX) { > + size_t extent_offset; > + union fscrypt_extent_context ctx; > + int ret = fscrypt_get_extent_context(inode, lblk_num, &ctx, &extent_offset, NULL); Newline between declarations and code, and since you use the warnon i'd do int ret; ret = fscrypt_get_extent_context(); WARN_ON_ONCE(ret); > + WARN_ON_ONCE(ret != 0); > + memcpy(iv->raw, ctx.v1.iv, ci->ci_mode->ivsize); > + iv->lblk_num = iv->lblk_num + cpu_to_le64(extent_offset); > + return; > + } > > /* > * Filename encryption. For inode-based policies, filenames are > @@ -93,8 +104,8 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, > > if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { > 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(inode->i_ino > U32_MAX); > + lblk_num |= (u64)inode->i_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 3afdaa084773..2092ef63c80a 100644 > --- a/fs/crypto/fscrypt_private.h > +++ b/fs/crypto/fscrypt_private.h > @@ -165,6 +165,27 @@ fscrypt_policy_flags(const union fscrypt_policy *policy) > BUG(); > } > > +#define FSCRYPT_MAX_IV_SIZE 32 > + > +/* > + * fscrypt_extent_context - the encryption context for an extent > + * Whitespace. > + * For filesystems that support extent encryption, this context provides the > + * necessary randomly-initialized IV in order to encrypt/decrypt the data > + * stored in the extent. It is stored alongside each extent, and is > + * insufficient to decrypt the extent: the extent's owning inode(s) provide the > + * policy information (including key identifier) necessary to decrypt. > + */ > +struct fscrypt_extent_context_v1 { > + u8 version; > + u8 iv[FSCRYPT_MAX_IV_SIZE]; > +}; > + > +union fscrypt_extent_context { > + u8 version; > + struct fscrypt_extent_context_v1 v1; > +}; > + > /* > * For encrypted symlinks, the ciphertext length is stored at the beginning > * of the string in little-endian format. > @@ -279,8 +300,6 @@ fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...); > #define fscrypt_err(inode, fmt, ...) \ > fscrypt_msg((inode), KERN_ERR, fmt, ##__VA_ARGS__) > > -#define FSCRYPT_MAX_IV_SIZE 32 > - > union fscrypt_iv { > struct { > /* logical block number within the file */ > @@ -628,5 +647,8 @@ int fscrypt_policy_from_context(union fscrypt_policy *policy_u, > const union fscrypt_context *ctx_u, > int ctx_size); > const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir); > +int fscrypt_get_extent_context(const struct inode *inode, u64 lblk_num, > + union fscrypt_extent_context *ctx, > + size_t *extent_offset, size_t *extent_length); > > #endif /* _FSCRYPT_PRIVATE_H */ > diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c > index 90f3e68f166e..0537f710047e 100644 > --- a/fs/crypto/inline_crypt.c > +++ b/fs/crypto/inline_crypt.c > @@ -1,3 +1,4 @@ > + Whitespace. Thanks, Josef