diff mbox series

[RFC,05/17] fscrypt: use parent dir's info for extent-based encryption.

Message ID d145985930958d2c15955438af7468276547d2d3.1672547582.git.sweettea-kernel@dorminy.me (mailing list archive)
State New, archived
Headers show
Series fscrypt: add per-extent encryption keys | expand

Commit Message

Sweet Tea Dorminy Jan. 1, 2023, 5:06 a.m. UTC
For regular files in filesystems using extent-based encryption, the
corresponding inode does
not need a fscrypt_info structure of its own as for inode-based fscrypt, as they will not be
encrypting anything using it. Any new extents written to the inode will
use a per-extent info structure derived from the inode's parent
directory's info structure. However, it is convenient to cache that
parent directory's info structure in the inode; it makes it easy to
check whether the parents' info exists, so that we don't have to get and
put a reference to the parent inode every time we want to get the inode
info. So do that.

Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
 fs/crypto/fscrypt_private.h | 18 ++++++++++++++++++
 fs/crypto/keysetup.c        | 27 ++++++++++++++++++++++++++-
 2 files changed, 44 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 2df28c6fe558..e4c9c483114f 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -262,6 +262,24 @@  typedef enum {
 	FS_ENCRYPT,
 } fscrypt_direction_t;
 
+/**
+ * fscrypt_uses_extent_encryption() -- whether an inode uses per-extent
+ *                                     encryption
+ *
+ * @param inode	 the inode in question
+ *
+ * Return: true if the inode uses per-extent encryption 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 filesystem currently uses per-extent infos
+	return false;
+}
+
 /**
  * fscrypt_get_inode_info() - get the fscrypt_info for a particular inode
  *
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index 4d7ff8244c55..52244e0dd1e4 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -622,6 +622,22 @@  int fscrypt_get_encryption_info(struct inode *inode, bool allow_unsupported)
 	if (fscrypt_has_encryption_key(inode))
 		return 0;
 
+	if (fscrypt_uses_extent_encryption(inode)) {
+		struct dentry *dentry = d_find_any_alias(inode);
+		struct dentry *parent_dentry = dget_parent(dentry);
+		struct inode *dir = parent_dentry->d_inode;
+		struct fscrypt_info *dir_info = fscrypt_get_inode_info(dir);
+		struct fscrypt_master_key *mk = NULL;
+
+		if (dir_info)
+			mk = dir_info->ci_master_key;
+
+		fscrypt_set_inode_info(inode, dir_info, mk);
+		dput(parent_dentry);
+		dput(dentry);
+		return 0;
+	}
+
 	res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
 	if (res < 0) {
 		if (res == -ERANGE && allow_unsupported)
@@ -704,6 +720,14 @@  int fscrypt_prepare_new_inode(struct inode *dir, struct inode *inode,
 
 	*encrypt_ret = true;
 
+	if (fscrypt_uses_extent_encryption(inode)) {
+		struct fscrypt_info *dir_info = fscrypt_get_inode_info(dir);
+
+		fscrypt_set_inode_info(inode, dir_info,
+				       dir_info->ci_master_key);
+		return 0;
+	}
+
 	get_random_bytes(nonce, FSCRYPT_FILE_NONCE_SIZE);
 	return fscrypt_setup_encryption_info(inode, policy, nonce,
 					     IS_CASEFOLDED(dir) &&
@@ -720,7 +744,8 @@  EXPORT_SYMBOL_GPL(fscrypt_prepare_new_inode);
  */
 void fscrypt_put_encryption_info(struct inode *inode)
 {
-	put_crypt_info(fscrypt_get_inode_info(inode));
+	if (!fscrypt_uses_extent_encryption(inode))
+		put_crypt_info(fscrypt_get_inode_info(inode));
 	fscrypt_set_inode_info(inode, NULL, NULL);
 }
 EXPORT_SYMBOL(fscrypt_put_encryption_info);