For extent-based encryption, we plan to use pooled prepared keys, since it's unsafe to allocate a new crypto_skcipher when performing IO. This will require being able to set up a pre-allocated prepared key, while the current code requires allocating and setting up simultaneously. This pulls apart fscrypt_allocate_skcipher() to only allocate; pulls allocation out of fscrypt_prepare_inline_crypt_key(); creates a new function fscrypt_allocate_key_member() that allocates the appropriate member of a prepared key; and reflects these changes throughout. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx> --- fs/crypto/fscrypt_private.h | 14 +++++++++++ fs/crypto/inline_crypt.c | 20 ++++++++++------ fs/crypto/keysetup.c | 47 ++++++++++++++++++++++++++----------- fs/crypto/keysetup_v1.c | 4 ++++ 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 7253cdb5e4d8..97323b1e71e7 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -358,6 +358,9 @@ fscrypt_using_inline_encryption(const struct fscrypt_info *ci) return ci->ci_inlinecrypt; } +int fscrypt_allocate_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci); + int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, const struct fscrypt_info *ci); @@ -400,6 +403,14 @@ fscrypt_using_inline_encryption(const struct fscrypt_info *ci) return false; } +static inline int +fscrypt_allocate_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) +{ + WARN_ON(1); + return -EOPNOTSUPP; +} + static inline int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, @@ -616,6 +627,9 @@ struct fscrypt_mode { extern struct fscrypt_mode fscrypt_modes[]; +int fscrypt_allocate_key_member(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci); + int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, const struct fscrypt_info *ci); diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c index ce952dedba77..7b3b96b8a916 100644 --- a/fs/crypto/inline_crypt.c +++ b/fs/crypto/inline_crypt.c @@ -157,16 +157,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const struct inode *inode = ci->ci_inode; struct super_block *sb = inode->i_sb; enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode; - struct blk_crypto_key *blk_key; + struct blk_crypto_key *blk_key = prep_key->blk_key; struct block_device **devs; unsigned int num_devs; unsigned int i; int err; - blk_key = kmalloc(sizeof(*blk_key), GFP_KERNEL); - if (!blk_key) - return -ENOMEM; - err = blk_crypto_init_key(blk_key, raw_key, crypto_mode, fscrypt_get_dun_bytes(ci), sb->s_blocksize); if (err) { @@ -190,8 +186,6 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, fscrypt_err(inode, "error %d starting to use blk-crypto", err); goto fail; } - - prep_key->blk_key = blk_key; return 0; fail: @@ -199,6 +193,18 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, return err; } +int fscrypt_allocate_inline_crypt_key(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) +{ + struct blk_crypto_key *blk_key = kmalloc(sizeof(*blk_key), GFP_KERNEL); + + if (!blk_key) + return -ENOMEM; + + prep_key->blk_key = blk_key; + return 0; +} + void fscrypt_destroy_inline_crypt_key(struct super_block *sb, struct fscrypt_prepared_key *prep_key) { diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 6efac89d49ec..7fc7dc632b3e 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -100,9 +100,9 @@ select_encryption_mode(const union fscrypt_policy *policy, return ERR_PTR(-EINVAL); } -/* Create a symmetric cipher object for the given encryption mode and key */ +/* Create a symmetric cipher object for the given encryption mode */ static struct crypto_skcipher * -fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, +fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const struct inode *inode) { struct crypto_skcipher *tfm; @@ -135,10 +135,6 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, goto err_free_tfm; } crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); - err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize); - if (err) - goto err_free_tfm; - return tfm; err_free_tfm: @@ -146,11 +142,28 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, return ERR_PTR(err); } +/* Allocate the relevant encryption member for the prepared key */ +int fscrypt_allocate_key_member(struct fscrypt_prepared_key *prep_key, + const struct fscrypt_info *ci) +{ + struct crypto_skcipher *tfm; + + if (fscrypt_using_inline_encryption(ci)) + return fscrypt_allocate_inline_crypt_key(prep_key, ci); + + tfm = fscrypt_allocate_skcipher(ci->ci_mode, ci->ci_inode); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + prep_key->tfm = tfm; + return 0; +} + /* * 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 * implementation (fs-layer or blk-crypto) will be used (@ci->ci_inlinecrypt), - * and IV generation method (@ci->ci_policy.flags). + * and IV generation method (@ci->ci_policy.flags). The relevant member must + * already be allocated and set in @prep_key. */ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, const struct fscrypt_info *ci) @@ -162,14 +175,10 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, if (inlinecrypt) { err = fscrypt_prepare_inline_crypt_key(prep_key, raw_key, ci); } else { - struct crypto_skcipher *tfm; + err = crypto_skcipher_setkey(prep_key->tfm, raw_key, + ci->ci_mode->keysize); - tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - } - prep_key->tfm = tfm; } /* @@ -186,7 +195,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, */ smp_store_release(&prep_key->prepared_members, prep_key->prepared_members | prepared_member); - return 0; + return err; } /* Destroy a crypto transform object and/or blk-crypto key. */ @@ -201,11 +210,17 @@ void fscrypt_destroy_prepared_key(struct super_block *sb, /* Given a per-file encryption key, set up the file's crypto transform object */ 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; 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); } @@ -290,6 +305,10 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk, if (fscrypt_is_key_prepared(prep_key, ci)) goto out_unlock; + err = fscrypt_allocate_key_member(prep_key, ci); + if (err) + goto out_unlock; + BUILD_BUG_ON(sizeof(mode_num) != 1); BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); BUILD_BUG_ON(sizeof(hkdf_info) != 17); diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 1e785cedead0..760efa8eeb3a 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -239,6 +239,10 @@ fscrypt_get_direct_key(const struct fscrypt_info *ci, const u8 *raw_key) refcount_set(&dk->dk_refcount, 1); dk->dk_mode = ci->ci_mode; dk->dk_key.type = FSCRYPT_KEY_DIRECT_V1; + err = fscrypt_allocate_key_member(&dk->dk_key, ci); + if (err) + goto err_free_dk; + err = fscrypt_prepare_key(&dk->dk_key, raw_key, ci); if (err) goto err_free_dk; -- 2.40.0