@@ -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;
@@ -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)) {
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 <sweettea-kernel@dorminy.me> --- fs/crypto/fscrypt_private.h | 17 +++++++++++++ fs/crypto/keysetup.c | 49 ++++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 14 deletions(-)