diff mbox series

[v1,1/7] fscrypt: add new pooled prepared keys.

Message ID 833c7892da7981e46e13d1be9aa4629926448bd1.1681871298.git.sweettea-kernel@dorminy.me (mailing list archive)
State Superseded
Headers show
Series fscrypt: add pooled prepared keys facility | expand

Commit Message

Sweet Tea Dorminy April 19, 2023, 2:42 a.m. UTC
For extent-based encryption, we need to avoid allocating prepared keys
at IO time, since crypto_skcipher allocation takes a lock and can do IO
itself. As such, we will need to use pooled prepared keys. This change
begins adding pooled prepared keys, but doesn't use them yet.

For testing, fscrypt_using_pooled_prepared_keys() can be changed to use
pooled keys for leaf inodes, so that pooled prepared keys are used for
contents encryption for v2 default-key policies.

Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
 fs/crypto/fscrypt_private.h |  9 ++++++
 fs/crypto/keysetup.c        | 62 ++++++++++++++++++++++++++++++++-----
 2 files changed, 63 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index eb302e342fb9..4942a8ae2061 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -30,6 +30,11 @@ 
 #define FSCRYPT_CONTEXT_V1	1
 #define FSCRYPT_CONTEXT_V2	2
 
+#define FSCRYPT_POLICY_FLAGS_KEY_MASK		\
+	(FSCRYPT_POLICY_FLAG_DIRECT_KEY		\
+	 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64	\
+	 | FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)
+
 /* Keep this in sync with include/uapi/linux/fscrypt.h */
 #define FSCRYPT_MODE_MAX	FSCRYPT_MODE_AES_256_HCTR2
 
@@ -185,11 +190,15 @@  struct fscrypt_symlink_data {
  *			    part of a fscrypt_master_key, shared between all
  *			    users of this master key having this mode and
  *			    policy.
+ * @FSCRYPT_KEY_POOLED: this prepared key is embedded in a
+ *			fscrypt_pooled_prepared_key. It should be returned to
+ *			its pool when no longer in use.
  */
 enum fscrypt_prepared_key_type {
 	FSCRYPT_KEY_PER_INFO = 1,
 	FSCRYPT_KEY_DIRECT_V1,
 	FSCRYPT_KEY_MASTER_KEY,
+	FSCRYPT_KEY_POOLED,
 } __packed;
 
 /**
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index 9cd60e09b0c5..171114fd5590 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -89,6 +89,10 @@  struct fscrypt_mode fscrypt_modes[] = {
 
 static DEFINE_MUTEX(fscrypt_mode_key_setup_mutex);
 
+struct fscrypt_pooled_prepared_key {
+	struct fscrypt_prepared_key prep_key;
+};
+
 static struct fscrypt_mode *
 select_encryption_mode(const union fscrypt_policy *policy,
 		       const struct inode *inode)
@@ -117,6 +121,21 @@  static int lock_master_key(struct fscrypt_master_key *mk)
 	return 0;
 }
 
+static inline bool
+fscrypt_using_pooled_prepared_key(const struct fscrypt_info *ci)
+{
+	if (ci->ci_policy.version != FSCRYPT_POLICY_V2)
+		return false;
+	if (ci->ci_policy.v2.flags & FSCRYPT_POLICY_FLAGS_KEY_MASK)
+		return false;
+	if (fscrypt_using_inline_encryption(ci))
+		return false;
+
+	if (!S_ISREG(ci->ci_inode->i_mode))
+		return false;
+	return false;
+}
+
 /*
  * Prepare the crypto transform object or blk-crypto key in @prep_key, given the
  * raw key, encryption mode (@ci->ci_mode), flag indicating which encryption
@@ -140,7 +159,6 @@  int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
 	return err;
 }
 
-
 /* Create a symmetric cipher object for the given encryption mode */
 static struct crypto_skcipher *
 fscrypt_allocate_skcipher(struct fscrypt_mode *mode,
@@ -213,14 +231,31 @@  int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key)
 {
 	int err;
 
-	ci->ci_enc_key = kzalloc(sizeof(*ci->ci_enc_key), GFP_KERNEL);
-	if (!ci->ci_enc_key)
-		return -ENOMEM;
+	if (fscrypt_using_pooled_prepared_key(ci)) {
+		struct fscrypt_pooled_prepared_key *pooled_key;
 
-	ci->ci_enc_key->type = FSCRYPT_KEY_PER_INFO;
-	err = fscrypt_allocate_key_member(ci->ci_enc_key, ci);
-	if (err)
-		return err;
+		pooled_key = kzalloc(sizeof(*pooled_key), GFP_KERNEL);
+		if (!pooled_key)
+			return -ENOMEM;
+
+		err = fscrypt_allocate_key_member(&pooled_key->prep_key, ci);
+		if (err) {
+			kfree(pooled_key);
+			return err;
+		}
+
+		pooled_key->prep_key.type = FSCRYPT_KEY_POOLED;
+		ci->ci_enc_key = &pooled_key->prep_key;
+	} else {
+		ci->ci_enc_key = kzalloc(sizeof(*ci->ci_enc_key), GFP_KERNEL);
+		if (!ci->ci_enc_key)
+			return -ENOMEM;
+
+		ci->ci_enc_key->type = FSCRYPT_KEY_PER_INFO;
+		err = fscrypt_allocate_key_member(ci->ci_enc_key, ci);
+		if (err)
+			return err;
+	}
 
 	return fscrypt_prepare_key(ci->ci_enc_key, raw_key, ci);
 }
@@ -616,6 +651,17 @@  static void put_crypt_info(struct fscrypt_info *ci)
 						     ci->ci_enc_key);
 			kfree_sensitive(ci->ci_enc_key);
 		}
+		if (type == FSCRYPT_KEY_POOLED) {
+			struct fscrypt_pooled_prepared_key *pooled_key;
+
+			pooled_key = container_of(ci->ci_enc_key,
+						  struct fscrypt_pooled_prepared_key,
+						  prep_key);
+
+			fscrypt_destroy_prepared_key(ci->ci_inode->i_sb,
+						     ci->ci_enc_key);
+			kfree_sensitive(pooled_key);
+		}
 	}
 
 	mk = ci->ci_master_key;