Now that fscrypt uses only synchronous skciphers, switch to the actual sync_skcipher API and the corresponding on-stack requests. This eliminates a heap allocation per en/decryption operation.
Signed-off-by: Eric Biggers <ebigg...@kernel.org> --- fs/crypto/crypto.c | 24 ++++++----------- fs/crypto/fname.c | 53 ++++++++++++------------------------ fs/crypto/fscrypt_private.h | 2 +- fs/crypto/keysetup.c | 23 ++++++++-------- fs/crypto/keysetup_v1.c | 54 +++++++++++++++++-------------------- 5 files changed, 63 insertions(+), 93 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 43d1658e07cec..646b1831e6831 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -111,48 +111,40 @@ int fscrypt_crypt_data_unit(const struct fscrypt_inode_info *ci, fscrypt_direction_t rw, u64 index, struct page *src_page, struct page *dest_page, unsigned int len, unsigned int offs, gfp_t gfp_flags) { + struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm; + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); union fscrypt_iv iv; - struct skcipher_request *req = NULL; struct scatterlist dst, src; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; - int res = 0; + int err; if (WARN_ON_ONCE(len <= 0)) return -EINVAL; if (WARN_ON_ONCE(len % FSCRYPT_CONTENTS_ALIGNMENT != 0)) return -EINVAL; fscrypt_generate_iv(&iv, index, ci); - req = skcipher_request_alloc(tfm, gfp_flags); - if (!req) - return -ENOMEM; - skcipher_request_set_callback( req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); - sg_init_table(&dst, 1); sg_set_page(&dst, dest_page, len, offs); sg_init_table(&src, 1); sg_set_page(&src, src_page, len, offs); skcipher_request_set_crypt(req, &src, &dst, len, &iv); if (rw == FS_DECRYPT) - res = crypto_skcipher_decrypt(req); + err = crypto_skcipher_decrypt(req); else - res = crypto_skcipher_encrypt(req); - skcipher_request_free(req); - if (res) { + err = crypto_skcipher_encrypt(req); + if (err) fscrypt_err(ci->ci_inode, "%scryption failed for data unit %llu: %d", - (rw == FS_DECRYPT ? "De" : "En"), index, res); - return res; - } - return 0; + (rw == FS_DECRYPT ? "De" : "En"), index, err); + return err; } /** * fscrypt_encrypt_pagecache_blocks() - Encrypt data from a pagecache folio * @folio: the locked pagecache folio containing the data to encrypt diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 17edc24ccd42f..f9f6713e144f7 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -92,48 +92,37 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) * Return: 0 on success, -errno on failure */ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, u8 *out, unsigned int olen) { - struct skcipher_request *req = NULL; const struct fscrypt_inode_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; + struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm; + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); union fscrypt_iv iv; struct scatterlist sg; - int res; + int err; /* * Copy the filename to the output buffer for encrypting in-place and * pad it with the needed number of NUL bytes. */ if (WARN_ON_ONCE(olen < iname->len)) return -ENOBUFS; memcpy(out, iname->name, iname->len); memset(out + iname->len, 0, olen - iname->len); - /* Initialize the IV */ fscrypt_generate_iv(&iv, 0, ci); - /* Set up the encryption request */ - req = skcipher_request_alloc(tfm, GFP_NOFS); - if (!req) - return -ENOMEM; skcipher_request_set_callback( req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); sg_init_one(&sg, out, olen); skcipher_request_set_crypt(req, &sg, &sg, olen, &iv); - - /* Do the encryption */ - res = crypto_skcipher_encrypt(req); - skcipher_request_free(req); - if (res < 0) { - fscrypt_err(inode, "Filename encryption failed: %d", res); - return res; - } - - return 0; + err = crypto_skcipher_encrypt(req); + if (err) + fscrypt_err(inode, "Filename encryption failed: %d", err); + return err; } EXPORT_SYMBOL_GPL(fscrypt_fname_encrypt); /** * fname_decrypt() - decrypt a filename @@ -147,37 +136,29 @@ EXPORT_SYMBOL_GPL(fscrypt_fname_encrypt); */ static int fname_decrypt(const struct inode *inode, const struct fscrypt_str *iname, struct fscrypt_str *oname) { - struct skcipher_request *req = NULL; - struct scatterlist src_sg, dst_sg; const struct fscrypt_inode_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; + struct crypto_sync_skcipher *tfm = ci->ci_enc_key.tfm; + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); union fscrypt_iv iv; - int res; + struct scatterlist src_sg, dst_sg; + int err; + + fscrypt_generate_iv(&iv, 0, ci); - /* Allocate request */ - req = skcipher_request_alloc(tfm, GFP_NOFS); - if (!req) - return -ENOMEM; skcipher_request_set_callback( req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); - - /* Initialize IV */ - fscrypt_generate_iv(&iv, 0, ci); - - /* Create decryption request */ sg_init_one(&src_sg, iname->name, iname->len); sg_init_one(&dst_sg, oname->name, oname->len); skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv); - res = crypto_skcipher_decrypt(req); - skcipher_request_free(req); - if (res < 0) { - fscrypt_err(inode, "Filename decryption failed: %d", res); - return res; + err = crypto_skcipher_decrypt(req); + if (err) { + fscrypt_err(inode, "Filename decryption failed: %d", err); + return err; } oname->len = strnlen(oname->name, iname->len); return 0; } diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 06fa8f2b2d081..bffeb14501fd0 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -237,11 +237,11 @@ struct fscrypt_symlink_data { * @blk_key: key for blk-crypto * * Normally only one of the fields will be non-NULL. */ struct fscrypt_prepared_key { - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT struct blk_crypto_key *blk_key; #endif }; diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 74d4a2e1ad23a..4f3b9ecbfe4e6 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -95,19 +95,19 @@ select_encryption_mode(const union fscrypt_policy *policy, inode->i_ino, (inode->i_mode & S_IFMT)); return ERR_PTR(-EINVAL); } /* Create a symmetric cipher object for the given encryption mode and key */ -static struct crypto_skcipher * +static struct crypto_sync_skcipher * fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, const struct inode *inode) { - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; int err; - tfm = crypto_alloc_skcipher(mode->cipher_str, 0, - FSCRYPT_CRYPTOAPI_MASK); + tfm = crypto_alloc_sync_skcipher(mode->cipher_str, 0, + FSCRYPT_CRYPTOAPI_MASK); if (IS_ERR(tfm)) { if (PTR_ERR(tfm) == -ENOENT) { fscrypt_warn(inode, "Missing crypto API support for %s (API name: \"%s\")", mode->friendly_name, mode->cipher_str); @@ -123,25 +123,26 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, * crypto algorithm implementation is used. Help people debug * performance problems by logging the ->cra_driver_name the * first time a mode is used. */ pr_info("fscrypt: %s using implementation \"%s\"\n", - mode->friendly_name, crypto_skcipher_driver_name(tfm)); + mode->friendly_name, + crypto_skcipher_driver_name(&tfm->base)); } - if (WARN_ON_ONCE(crypto_skcipher_ivsize(tfm) != mode->ivsize)) { + if (WARN_ON_ONCE(crypto_sync_skcipher_ivsize(tfm) != mode->ivsize)) { err = -EINVAL; goto err_free_tfm; } - crypto_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); - err = crypto_skcipher_setkey(tfm, raw_key, mode->keysize); + crypto_sync_skcipher_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); + err = crypto_sync_skcipher_setkey(tfm, raw_key, mode->keysize); if (err) goto err_free_tfm; return tfm; err_free_tfm: - crypto_free_skcipher(tfm); + crypto_free_sync_skcipher(tfm); return ERR_PTR(err); } /* * Prepare the crypto transform object or blk-crypto key in @prep_key, given the @@ -150,11 +151,11 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, * 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_inode_info *ci) { - struct crypto_skcipher *tfm; + struct crypto_sync_skcipher *tfm; if (fscrypt_using_inline_encryption(ci)) return fscrypt_prepare_inline_crypt_key(prep_key, raw_key, ci->ci_mode->keysize, false, ci); @@ -174,11 +175,11 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key, /* Destroy a crypto transform object and/or blk-crypto key. */ void fscrypt_destroy_prepared_key(struct super_block *sb, struct fscrypt_prepared_key *prep_key) { - crypto_free_skcipher(prep_key->tfm); + crypto_free_sync_skcipher(prep_key->tfm); fscrypt_destroy_inline_crypt_key(sb, prep_key); memzero_explicit(prep_key, sizeof(*prep_key)); } /* Given a per-file encryption key, set up the file's crypto transform object */ diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 75b0f1211a1e6..4a93b4763469f 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -46,42 +46,38 @@ static DEFINE_SPINLOCK(fscrypt_direct_keys_lock); */ static int derive_key_aes(const u8 *master_key, const u8 nonce[FSCRYPT_FILE_NONCE_SIZE], u8 *derived_key, unsigned int derived_keysize) { - int res = 0; - struct skcipher_request *req = NULL; - struct scatterlist src_sg, dst_sg; - struct crypto_skcipher *tfm = - crypto_alloc_skcipher("ecb(aes)", 0, FSCRYPT_CRYPTOAPI_MASK); - - if (IS_ERR(tfm)) { - res = PTR_ERR(tfm); - tfm = NULL; - goto out; - } - req = skcipher_request_alloc(tfm, GFP_KERNEL); - if (!req) { - res = -ENOMEM; - goto out; - } - skcipher_request_set_callback( - req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, - NULL, NULL); - res = crypto_skcipher_setkey(tfm, nonce, FSCRYPT_FILE_NONCE_SIZE); - if (res < 0) + struct crypto_sync_skcipher *tfm; + int err; + + tfm = crypto_alloc_sync_skcipher("ecb(aes)", 0, FSCRYPT_CRYPTOAPI_MASK); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + err = crypto_sync_skcipher_setkey(tfm, nonce, FSCRYPT_FILE_NONCE_SIZE); + if (err) goto out; - sg_init_one(&src_sg, master_key, derived_keysize); - sg_init_one(&dst_sg, derived_key, derived_keysize); - skcipher_request_set_crypt(req, &src_sg, &dst_sg, derived_keysize, - NULL); - res = crypto_skcipher_encrypt(req); + { + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); + struct scatterlist src_sg, dst_sg; + + skcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + NULL, NULL); + sg_init_one(&src_sg, master_key, derived_keysize); + sg_init_one(&dst_sg, derived_key, derived_keysize); + skcipher_request_set_crypt(req, &src_sg, &dst_sg, + derived_keysize, NULL); + err = crypto_skcipher_encrypt(req); + } out: - skcipher_request_free(req); - crypto_free_skcipher(tfm); - return res; + crypto_free_sync_skcipher(tfm); + return err; } /* * Search the current task's subscribed keyrings for a "logon" key with * description prefix:descriptor, and if found acquire a read lock on it and -- 2.50.0