@@ -355,6 +355,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);
@@ -388,6 +391,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,
@@ -604,6 +615,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);
@@ -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) {
@@ -191,7 +187,6 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
goto fail;
}
- prep_key->blk_key = blk_key;
return 0;
fail:
@@ -199,6 +194,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)
{
@@ -106,9 +106,33 @@ select_encryption_mode(const union fscrypt_policy *policy,
return ERR_PTR(-EINVAL);
}
-/* Create a symmetric cipher object for the given encryption mode and key */
+/*
+ * 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). 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)
+{
+ int err;
+ bool inlinecrypt = fscrypt_using_inline_encryption(ci);
+
+ if (inlinecrypt) {
+ err = fscrypt_prepare_inline_crypt_key(prep_key, raw_key, ci);
+ } else {
+ err = crypto_skcipher_setkey(prep_key->tfm, raw_key,
+ ci->ci_mode->keysize);
+ }
+
+ return err;
+}
+
+
+/* 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;
@@ -141,10 +165,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:
@@ -152,21 +172,16 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
return ERR_PTR(err);
}
-/*
- * 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).
- */
-int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
- const u8 *raw_key, const struct fscrypt_info *ci)
+/* 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_prepare_inline_crypt_key(prep_key, raw_key, ci);
+ return fscrypt_allocate_inline_crypt_key(prep_key, ci);
- tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode);
+ tfm = fscrypt_allocate_skcipher(ci->ci_mode, ci->ci_inode);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
prep_key->tfm = tfm;
@@ -185,11 +200,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);
}
@@ -271,6 +292,10 @@ static int setup_new_mode_prepared_key(struct fscrypt_master_key *mk,
*/
+ err = fscrypt_allocate_key_member(prep_key, ci);
+ if (err)
+ return err;
+
BUILD_BUG_ON(sizeof(mode_num) != 1);
BUILD_BUG_ON(sizeof(sb->s_uuid) != 16);
BUILD_BUG_ON(sizeof(hkdf_info) != MAX_MODE_KEY_HKDF_INFO_SIZE);
@@ -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;
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@dorminy.me> --- fs/crypto/fscrypt_private.h | 14 +++++++++ fs/crypto/inline_crypt.c | 19 +++++++++---- fs/crypto/keysetup.c | 57 ++++++++++++++++++++++++++----------- fs/crypto/keysetup_v1.c | 4 +++ 4 files changed, 72 insertions(+), 22 deletions(-)