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@xxxxxxxxxx> --- fs/crypto/fscrypt_private.h | 9 ++++++ fs/crypto/keysetup.c | 62 ++++++++++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 8 deletions(-) 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; -- 2.40.0