diff mbox series

[RFC,13/17] fscrypt: use an optional ino equivalent for per-extent infos

Message ID f2b7d9f5412a2e8d2bb2c88d41a76495c6c1bc89.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
Since per-extent infos are not tied to inodes, an ino-based policy
cannot access the inode's i_ino to get the necessary information.
Instead, this adds an optional fscrypt_operation pointer to get the ino
equivalent for an extent, adds a wrapper to get the ino for an info, and
uses this wrapper everywhere where the ci's inode's i_ino is currently
accessed.

Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
 fs/crypto/crypto.c          |  5 +++--
 fs/crypto/fscrypt_private.h | 18 ++++++++++++++++++
 fs/crypto/keyring.c         |  6 +++---
 fs/crypto/keysetup.c        |  8 ++++----
 include/linux/fscrypt.h     | 18 ++++++++++++++++++
 5 files changed, 46 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 93b83dbe82ee..4760adc1158f 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -85,9 +85,10 @@  void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
 	memset(iv, 0, ci->ci_mode->ivsize);
 
 	if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
+		u64 ino = fscrypt_get_info_ino(ci);
 		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(ino > U32_MAX);
+		lblk_num |= (u64)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 a34d2e525ddf..d937a320361e 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -344,6 +344,24 @@  fscrypt_get_lblk_info(const struct inode *inode, u64 lblk, u64 *offset,
 	return fscrypt_get_info(inode);
 }
 
+/**
+ * fscrypt_get_info_ino() - get the ino or ino equivalent for an info
+ *
+ * @ci: the fscrypt_info in question
+ *
+ * For inode-based encryption, this will return the info's inode's ino.
+ * For extent-based encryption, this will return the extent's ino equivalent
+ * or 0 if it is not implemented.
+ */
+static inline u64 fscrypt_get_info_ino(const struct fscrypt_info *ci)
+{
+	if (ci->ci_inode)
+		return ci->ci_inode->i_ino;
+	if (!ci->ci_sb->s_cop->get_extent_ino_equivalent)
+		return 0;
+	return ci->ci_sb->s_cop->get_extent_ino_equivalent(ci->ci_info_ptr);
+}
+
 /* crypto.c */
 extern struct kmem_cache *fscrypt_info_cachep;
 int fscrypt_initialize(unsigned int cop_flags);
diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
index 0c4e917a5281..48e732628d43 100644
--- a/fs/crypto/keyring.c
+++ b/fs/crypto/keyring.c
@@ -933,11 +933,11 @@  static int check_for_busy_inodes(struct super_block *sb,
 
 	{
 		/* select an example file to show for debugging purposes */
-		struct inode *inode =
+		struct fscrypt_info *ci =
 			list_first_entry(&mk->mk_active_infos,
 					 struct fscrypt_info,
-					 ci_master_key_link)->ci_inode;
-		ino = inode->i_ino;
+					 ci_master_key_link);
+		ino = fscrypt_get_info_ino(ci);
 	}
 	spin_unlock(&mk->mk_active_infos_lock);
 
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index 1751e3ed9956..f32b6f0a8336 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -266,11 +266,11 @@  int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
 void fscrypt_hash_inode_number(struct fscrypt_info *ci,
 			       const struct fscrypt_master_key *mk)
 {
-	WARN_ON(ci->ci_inode->i_ino == 0);
+	u64 ino = fscrypt_get_info_ino(ci);
+	WARN_ON(ino == 0);
 	WARN_ON(!mk->mk_ino_hash_key_initialized);
 
-	ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino,
-					      &mk->mk_ino_hash_key);
+	ci->ci_hashed_ino = (u32)siphash_1u64(ino, &mk->mk_ino_hash_key);
 }
 
 static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci,
@@ -308,7 +308,7 @@  static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci,
 	 * New inodes may not have an inode number assigned yet.
 	 * Hashing their inode number is delayed until later.
 	 */
-	if (ci->ci_inode->i_ino)
+	if (fscrypt_get_info_ino(ci))
 		fscrypt_hash_inode_number(ci, mk);
 	return 0;
 }
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 4f5f8a651213..c05e6ad3e729 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -129,6 +129,15 @@  struct fscrypt_operations {
 	 */
 	bool (*empty_dir)(struct inode *inode);
 
+	/*
+	 * Inform the filesystem that a particular extent must forget its
+	 * fscrypt_info (for instance, for a key removal).
+	 *
+	 * @info_ptr: a pointer to the location storing the fscrypt_info pointer
+	 *            within the opaque extent whose info is to be freed
+	 */
+	void (*forget_extent_info)(struct fscrypt_info **info_ptr);
+
 	/*
 	 * Check whether the filesystem's inode numbers and UUID are stable,
 	 * meaning that they will never be changed even by offline operations
@@ -160,6 +169,15 @@  struct fscrypt_operations {
 	void (*get_ino_and_lblk_bits)(struct super_block *sb,
 				      int *ino_bits_ret, int *lblk_bits_ret);
 
+	/*
+	 * Get the inode number equivalent for filesystems using per-extent
+	 * encryption keys.
+	 *
+	 * This function only needs to be implemented if support for one of the
+	 * FSCRYPT_POLICY_FLAG_IV_INO_* flags is needed.
+	 */
+	u64 (*get_extent_ino_equivalent)(struct fscrypt_info **info_ptr);
+
 	/*
 	 * Return an array of pointers to the block devices to which the
 	 * filesystem may write encrypted file contents, NULL if the filesystem