diff mbox series

[8/8] crypto: cbc - Convert from skcipher to lskcipher

Message ID 20230914082828.895403-9-herbert@gondor.apana.org.au (mailing list archive)
State Accepted
Delegated to: Herbert Xu
Headers show
Series crypto: Add lskcipher API type | expand

Commit Message

Herbert Xu Sept. 14, 2023, 8:28 a.m. UTC
Replace the existing skcipher CBC template with an lskcipher version.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
 crypto/cbc.c | 159 +++++++++++++++++++--------------------------------
 1 file changed, 59 insertions(+), 100 deletions(-)

Comments

Nathan Chancellor Oct. 2, 2023, 8:25 p.m. UTC | #1
Hi Herbert,

On Thu, Sep 14, 2023 at 04:28:28PM +0800, Herbert Xu wrote:
> Replace the existing skcipher CBC template with an lskcipher version.
> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

I am noticing a failure to get to user space when booting OpenSUSE's
armv7hl configuration [1] in QEMU after this change as commit
705b52fef3c7 ("crypto: cbc - Convert from skcipher to lskcipher"). I can
reproduce it with GCC 13.2.0 from kernel.org [2] and QEMU 8.1.1, in case
either of those versions matter.  The rootfs is available at [3] in case
it is relevant.

$ curl -LSso .config https://github.com/openSUSE/kernel-source/raw/master/config/armv7hl/default

$ make -skj"$(nproc)" ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- olddefconfig bzImage

$ qemu-system-arm \
    -display none \
    -nodefaults \
    -no-reboot \
    -machine virt \
    -append 'console=ttyAMA0 earlycon' \
    -kernel arch/arm/boot/zImage \
    -initrd arm-rootfs.cpio \
    -m 512m \
    -serial mon:stdio
...
[    0.000000][    T0] Linux version 6.6.0-rc1-default+ (nathan@dev-arch.thelio-3990X) (arm-linux-gnueabi-gcc (GCC) 13.2.0, GNU ld (GNU Binutils) 2.41) #1 SMP Mon Oct  2 13:12:40 MST 2023
...
[    0.743773][    T1] ------------[ cut here ]------------
[    0.743980][    T1] WARNING: CPU: 0 PID: 1 at crypto/algapi.c:506 crypto_unregister_alg+0x124/0x12c
[    0.744693][    T1] Modules linked in:
[    0.745078][    T1] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.6.0-rc1-default+ #1 906712a81ca49f79575cf3062af84575f391802d
[    0.745453][    T1] Hardware name: Generic DT based system
[    0.745700][    T1] Backtrace:
[    0.745901][    T1]  dump_backtrace from show_stack+0x20/0x24
[    0.746181][    T1]  r7:c077851c r6:00000009 r5:00000053 r4:c1595a60
[    0.746373][    T1]  show_stack from dump_stack_lvl+0x48/0x54
[    0.746530][    T1]  dump_stack_lvl from dump_stack+0x18/0x1c
[    0.746703][    T1]  r5:000001fa r4:c1589f2c
[    0.746811][    T1]  dump_stack from __warn+0x88/0x120
[    0.746954][    T1]  __warn from warn_slowpath_fmt+0xb8/0x188
[    0.747115][    T1]  r8:0000012a r7:c077851c r6:c1589f2c r5:00000000 r4:c1e825f0
[    0.747288][    T1]  warn_slowpath_fmt from crypto_unregister_alg+0x124/0x12c
[    0.747475][    T1]  r7:c214e414 r6:00000001 r5:c214e428 r4:c2d590c0
[    0.747628][    T1]  crypto_unregister_alg from crypto_unregister_skcipher+0x1c/0x20
[    0.747824][    T1]  r4:c2d59000
[    0.747911][    T1]  crypto_unregister_skcipher from simd_skcipher_free+0x20/0x2c
[    0.748100][    T1]  simd_skcipher_free from aes_exit+0x30/0x4c
[    0.748264][    T1]  r5:c214e428 r4:c214e418
[    0.748375][    T1]  aes_exit from aes_init+0x88/0xa8
[    0.748521][    T1]  r5:fffffffe r4:c1f12740
[    0.748637][    T1]  aes_init from do_one_initcall+0x44/0x25c
[    0.748803][    T1]  r9:c1dd3d5c r8:c1689880 r7:00000000 r6:c2570000 r5:00000019 r4:c1d0c618
[    0.749008][    T1]  do_one_initcall from kernel_init_freeable+0x23c/0x298
[    0.749187][    T1]  r8:c1689880 r7:00000007 r6:c1dd3d38 r5:00000019 r4:c25f0640
[    0.749364][    T1]  kernel_init_freeable from kernel_init+0x28/0x14c
[    0.749540][    T1]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c0fae978
[    0.749744][    T1]  r4:c1f0b040
[    0.749832][    T1]  kernel_init from ret_from_fork+0x14/0x30
[    0.750033][    T1] Exception stack(0xe080dfb0 to 0xe080dff8)
[    0.750315][    T1] dfa0:                                     00000000 00000000 00000000 00000000
[    0.750546][    T1] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    0.750760][    T1] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
[    0.750967][    T1]  r5:c0fae978 r4:00000000
[    0.751214][    T1] ---[ end trace 0000000000000000 ]---
[    0.751519][    T1] ------------[ cut here ]------------
[    0.751650][    T1] WARNING: CPU: 0 PID: 1 at crypto/algapi.c:506 crypto_unregister_alg+0x124/0x12c
[    0.751873][    T1] Modules linked in:
[    0.752037][    T1] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W          6.6.0-rc1-default+ #1 906712a81ca49f79575cf3062af84575f391802d
[    0.752331][    T1] Hardware name: Generic DT based system
[    0.752464][    T1] Backtrace:
[    0.752551][    T1]  dump_backtrace from show_stack+0x20/0x24
[    0.752702][    T1]  r7:c077851c r6:00000009 r5:00000053 r4:c1595a60
[    0.752853][    T1]  show_stack from dump_stack_lvl+0x48/0x54
[    0.753001][    T1]  dump_stack_lvl from dump_stack+0x18/0x1c
[    0.753151][    T1]  r5:000001fa r4:c1589f2c
[    0.753258][    T1]  dump_stack from __warn+0x88/0x120
[    0.753417][    T1]  __warn from warn_slowpath_fmt+0xb8/0x188
[    0.753572][    T1]  r8:0000012a r7:c077851c r6:c1589f2c r5:00000000 r4:c1e825f0
[    0.753750][    T1]  warn_slowpath_fmt from crypto_unregister_alg+0x124/0x12c
[    0.753938][    T1]  r7:c214e414 r6:00000001 r5:00000002 r4:c1f12bc0
[    0.754096][    T1]  crypto_unregister_alg from crypto_unregister_skciphers+0x30/0x40
[    0.754291][    T1]  r4:c1f12bc0
[    0.754378][    T1]  crypto_unregister_skciphers from aes_exit+0x48/0x4c
[    0.754556][    T1]  r5:c214e428 r4:c214e428
[    0.754666][    T1]  aes_exit from aes_init+0x88/0xa8
[    0.754804][    T1]  r5:fffffffe r4:c1f12740
[    0.754913][    T1]  aes_init from do_one_initcall+0x44/0x25c
[    0.755070][    T1]  r9:c1dd3d5c r8:c1689880 r7:00000000 r6:c2570000 r5:00000019 r4:c1d0c618
[    0.755274][    T1]  do_one_initcall from kernel_init_freeable+0x23c/0x298
[    0.755462][    T1]  r8:c1689880 r7:00000007 r6:c1dd3d38 r5:00000019 r4:c25f0640
[    0.755636][    T1]  kernel_init_freeable from kernel_init+0x28/0x14c
[    0.755807][    T1]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c0fae978
[    0.756007][    T1]  r4:c1f0b040
[    0.756095][    T1]  kernel_init from ret_from_fork+0x14/0x30
[    0.756243][    T1] Exception stack(0xe080dfb0 to 0xe080dff8)
[    0.756390][    T1] dfa0:                                     00000000 00000000 00000000 00000000
[    0.756610][    T1] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    0.756828][    T1] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
[    0.757001][    T1]  r5:c0fae978 r4:00000000
[    0.757178][    T1] ---[ end trace 0000000000000000 ]---
...
[    0.982740][    T1] trusted_key: encrypted_key: failed to alloc_cipher (-2)
...
[    0.993923][   T80] alg: No test for  ()
[    0.994049][   T80] alg: Unexpected test result for : 0

If there is any additional information I can provide or patches I can
test, I am more than happy to do so.

[1]: https://github.com/openSUSE/kernel-source/raw/master/config/armv7hl/default
[2]: https://mirrors.edge.kernel.org/pub/tools/crosstool/
[3]: https://github.com/ClangBuiltLinux/boot-utils/releases

Cheers,
Nathan

# bad: [df964ce9ef9fea10cf131bf6bad8658fde7956f6] Add linux-next specific files for 20230929
# good: [9ed22ae6be817d7a3f5c15ca22cbc9d3963b481d] Merge tag 'spi-fix-v6.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
git bisect start 'df964ce9ef9fea10cf131bf6bad8658fde7956f6' '9ed22ae6be817d7a3f5c15ca22cbc9d3963b481d'
# good: [2afef4020a647c2034c72a5ab765ad06338024c1] Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git
git bisect good 2afef4020a647c2034c72a5ab765ad06338024c1
# bad: [621abed2c5eb145b5c8f25aa08f4eaac3a4880df] Merge branch 'drm-next' of https://gitlab.freedesktop.org/agd5f/linux
git bisect bad 621abed2c5eb145b5c8f25aa08f4eaac3a4880df
# good: [fcdecb00fb04c2db761851b194547d291ba532c5] Merge branch 'main' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git
git bisect good fcdecb00fb04c2db761851b194547d291ba532c5
# bad: [62edfd0bd4ac7b7c6b5eff0ea290261ff5ab6d1c] Merge branch 'drm-next' of git://git.freedesktop.org/git/drm/drm.git
git bisect bad 62edfd0bd4ac7b7c6b5eff0ea290261ff5ab6d1c
# good: [9896f0608f9fe0b49badd2fd6ae76ec761c70624] Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
git bisect good 9896f0608f9fe0b49badd2fd6ae76ec761c70624
# good: [d856c84b8cbc2f5bc6e906deebf3fa912bb6c1c3] Merge branch 'spi-nor/next' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git
git bisect good d856c84b8cbc2f5bc6e906deebf3fa912bb6c1c3
# good: [39e0b96d61b6f5ad880d9953dc2b4c5b3ee145b3] drm/bridge/analogix/anx78xx: Drop ID table
git bisect good 39e0b96d61b6f5ad880d9953dc2b4c5b3ee145b3
# good: [3102bbcdcd3c945ef0bcea498d3a0c6384536d6c] crypto: qat - refactor deprecated strncpy
git bisect good 3102bbcdcd3c945ef0bcea498d3a0c6384536d6c
# bad: [bb4277c7e617e8b271eb7ad75d5bdb6b8a249613] Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
git bisect bad bb4277c7e617e8b271eb7ad75d5bdb6b8a249613
# bad: [aa3f80500382ca864b7cfcff4e5ca2fa6a0e977d] crypto: hisilicon/zip - support deflate algorithm
git bisect bad aa3f80500382ca864b7cfcff4e5ca2fa6a0e977d
# good: [b64d143b752932ef483d0ed8d00958f1832dd6bc] crypto: hash - Hide CRYPTO_ALG_TYPE_AHASH_MASK
git bisect good b64d143b752932ef483d0ed8d00958f1832dd6bc
# good: [3dfe8786b11a4a3f9ced2eb89c6c5d73eba84700] crypto: testmgr - Add support for lskcipher algorithms
git bisect good 3dfe8786b11a4a3f9ced2eb89c6c5d73eba84700
# bad: [705b52fef3c73655701d9c8868e744f1fa03e942] crypto: cbc - Convert from skcipher to lskcipher
git bisect bad 705b52fef3c73655701d9c8868e744f1fa03e942
# good: [32a8dc4afcfb098ef4e8b465c90db17d22d90107] crypto: ecb - Convert from skcipher to lskcipher
git bisect good 32a8dc4afcfb098ef4e8b465c90db17d22d90107
# first bad commit: [705b52fef3c73655701d9c8868e744f1fa03e942] crypto: cbc - Convert from skcipher to lskcipher
diff mbox series

Patch

diff --git a/crypto/cbc.c b/crypto/cbc.c
index 6c03e96b945f..28345b8d921c 100644
--- a/crypto/cbc.c
+++ b/crypto/cbc.c
@@ -5,8 +5,6 @@ 
  * Copyright (c) 2006-2016 Herbert Xu <herbert@gondor.apana.org.au>
  */
 
-#include <crypto/algapi.h>
-#include <crypto/internal/cipher.h>
 #include <crypto/internal/skcipher.h>
 #include <linux/err.h>
 #include <linux/init.h>
@@ -14,99 +12,71 @@ 
 #include <linux/log2.h>
 #include <linux/module.h>
 
-static int crypto_cbc_encrypt_segment(struct skcipher_walk *walk,
-				      struct crypto_skcipher *skcipher)
+static int crypto_cbc_encrypt_segment(struct crypto_lskcipher *tfm,
+				      const u8 *src, u8 *dst, unsigned nbytes,
+				      u8 *iv)
 {
-	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
-	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
-	unsigned int nbytes = walk->nbytes;
-	u8 *src = walk->src.virt.addr;
-	u8 *dst = walk->dst.virt.addr;
-	struct crypto_cipher *cipher;
-	struct crypto_tfm *tfm;
-	u8 *iv = walk->iv;
+	unsigned int bsize = crypto_lskcipher_blocksize(tfm);
 
-	cipher = skcipher_cipher_simple(skcipher);
-	tfm = crypto_cipher_tfm(cipher);
-	fn = crypto_cipher_alg(cipher)->cia_encrypt;
-
-	do {
+	for (; nbytes >= bsize; src += bsize, dst += bsize, nbytes -= bsize) {
 		crypto_xor(iv, src, bsize);
-		fn(tfm, dst, iv);
+		crypto_lskcipher_encrypt(tfm, iv, dst, bsize, NULL);
 		memcpy(iv, dst, bsize);
-
-		src += bsize;
-		dst += bsize;
-	} while ((nbytes -= bsize) >= bsize);
+	}
 
 	return nbytes;
 }
 
-static int crypto_cbc_encrypt_inplace(struct skcipher_walk *walk,
-				      struct crypto_skcipher *skcipher)
+static int crypto_cbc_encrypt_inplace(struct crypto_lskcipher *tfm,
+				      u8 *src, unsigned nbytes, u8 *oiv)
 {
-	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
-	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
-	unsigned int nbytes = walk->nbytes;
-	u8 *src = walk->src.virt.addr;
-	struct crypto_cipher *cipher;
-	struct crypto_tfm *tfm;
-	u8 *iv = walk->iv;
+	unsigned int bsize = crypto_lskcipher_blocksize(tfm);
+	u8 *iv = oiv;
 
-	cipher = skcipher_cipher_simple(skcipher);
-	tfm = crypto_cipher_tfm(cipher);
-	fn = crypto_cipher_alg(cipher)->cia_encrypt;
+	if (nbytes < bsize)
+		goto out;
 
 	do {
 		crypto_xor(src, iv, bsize);
-		fn(tfm, src, src);
+		crypto_lskcipher_encrypt(tfm, src, src, bsize, NULL);
 		iv = src;
 
 		src += bsize;
 	} while ((nbytes -= bsize) >= bsize);
 
-	memcpy(walk->iv, iv, bsize);
+	memcpy(oiv, iv, bsize);
 
+out:
 	return nbytes;
 }
 
-static int crypto_cbc_encrypt(struct skcipher_request *req)
+static int crypto_cbc_encrypt(struct crypto_lskcipher *tfm, const u8 *src,
+			      u8 *dst, unsigned len, u8 *iv, bool final)
 {
-	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
-	struct skcipher_walk walk;
-	int err;
+	struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm);
+	struct crypto_lskcipher *cipher = *ctx;
+	int rem;
 
-	err = skcipher_walk_virt(&walk, req, false);
+	if (src == dst)
+		rem = crypto_cbc_encrypt_inplace(cipher, dst, len, iv);
+	else
+		rem = crypto_cbc_encrypt_segment(cipher, src, dst, len, iv);
 
-	while (walk.nbytes) {
-		if (walk.src.virt.addr == walk.dst.virt.addr)
-			err = crypto_cbc_encrypt_inplace(&walk, skcipher);
-		else
-			err = crypto_cbc_encrypt_segment(&walk, skcipher);
-		err = skcipher_walk_done(&walk, err);
-	}
-
-	return err;
+	return rem && final ? -EINVAL : rem;
 }
 
-static int crypto_cbc_decrypt_segment(struct skcipher_walk *walk,
-				      struct crypto_skcipher *skcipher)
+static int crypto_cbc_decrypt_segment(struct crypto_lskcipher *tfm,
+				      const u8 *src, u8 *dst, unsigned nbytes,
+				      u8 *oiv)
 {
-	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
-	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
-	unsigned int nbytes = walk->nbytes;
-	u8 *src = walk->src.virt.addr;
-	u8 *dst = walk->dst.virt.addr;
-	struct crypto_cipher *cipher;
-	struct crypto_tfm *tfm;
-	u8 *iv = walk->iv;
+	unsigned int bsize = crypto_lskcipher_blocksize(tfm);
+	const u8 *iv = oiv;
 
-	cipher = skcipher_cipher_simple(skcipher);
-	tfm = crypto_cipher_tfm(cipher);
-	fn = crypto_cipher_alg(cipher)->cia_decrypt;
+	if (nbytes < bsize)
+		goto out;
 
 	do {
-		fn(tfm, dst, src);
+		crypto_lskcipher_decrypt(tfm, src, dst, bsize, NULL);
 		crypto_xor(dst, iv, bsize);
 		iv = src;
 
@@ -114,83 +84,72 @@  static int crypto_cbc_decrypt_segment(struct skcipher_walk *walk,
 		dst += bsize;
 	} while ((nbytes -= bsize) >= bsize);
 
-	memcpy(walk->iv, iv, bsize);
+	memcpy(oiv, iv, bsize);
 
+out:
 	return nbytes;
 }
 
-static int crypto_cbc_decrypt_inplace(struct skcipher_walk *walk,
-				      struct crypto_skcipher *skcipher)
+static int crypto_cbc_decrypt_inplace(struct crypto_lskcipher *tfm,
+				      u8 *src, unsigned nbytes, u8 *iv)
 {
-	unsigned int bsize = crypto_skcipher_blocksize(skcipher);
-	void (*fn)(struct crypto_tfm *, u8 *, const u8 *);
-	unsigned int nbytes = walk->nbytes;
-	u8 *src = walk->src.virt.addr;
+	unsigned int bsize = crypto_lskcipher_blocksize(tfm);
 	u8 last_iv[MAX_CIPHER_BLOCKSIZE];
-	struct crypto_cipher *cipher;
-	struct crypto_tfm *tfm;
 
-	cipher = skcipher_cipher_simple(skcipher);
-	tfm = crypto_cipher_tfm(cipher);
-	fn = crypto_cipher_alg(cipher)->cia_decrypt;
+	if (nbytes < bsize)
+		goto out;
 
 	/* Start of the last block. */
 	src += nbytes - (nbytes & (bsize - 1)) - bsize;
 	memcpy(last_iv, src, bsize);
 
 	for (;;) {
-		fn(tfm, src, src);
+		crypto_lskcipher_decrypt(tfm, src, src, bsize, NULL);
 		if ((nbytes -= bsize) < bsize)
 			break;
 		crypto_xor(src, src - bsize, bsize);
 		src -= bsize;
 	}
 
-	crypto_xor(src, walk->iv, bsize);
-	memcpy(walk->iv, last_iv, bsize);
+	crypto_xor(src, iv, bsize);
+	memcpy(iv, last_iv, bsize);
 
+out:
 	return nbytes;
 }
 
-static int crypto_cbc_decrypt(struct skcipher_request *req)
+static int crypto_cbc_decrypt(struct crypto_lskcipher *tfm, const u8 *src,
+			      u8 *dst, unsigned len, u8 *iv, bool final)
 {
-	struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
-	struct skcipher_walk walk;
-	int err;
+	struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm);
+	struct crypto_lskcipher *cipher = *ctx;
+	int rem;
 
-	err = skcipher_walk_virt(&walk, req, false);
+	if (src == dst)
+		rem = crypto_cbc_decrypt_inplace(cipher, dst, len, iv);
+	else
+		rem = crypto_cbc_decrypt_segment(cipher, src, dst, len, iv);
 
-	while (walk.nbytes) {
-		if (walk.src.virt.addr == walk.dst.virt.addr)
-			err = crypto_cbc_decrypt_inplace(&walk, skcipher);
-		else
-			err = crypto_cbc_decrypt_segment(&walk, skcipher);
-		err = skcipher_walk_done(&walk, err);
-	}
-
-	return err;
+	return rem && final ? -EINVAL : rem;
 }
 
 static int crypto_cbc_create(struct crypto_template *tmpl, struct rtattr **tb)
 {
-	struct skcipher_instance *inst;
-	struct crypto_alg *alg;
+	struct lskcipher_instance *inst;
 	int err;
 
-	inst = skcipher_alloc_instance_simple(tmpl, tb);
+	inst = lskcipher_alloc_instance_simple(tmpl, tb);
 	if (IS_ERR(inst))
 		return PTR_ERR(inst);
 
-	alg = skcipher_ialg_simple(inst);
-
 	err = -EINVAL;
-	if (!is_power_of_2(alg->cra_blocksize))
+	if (!is_power_of_2(inst->alg.co.base.cra_blocksize))
 		goto out_free_inst;
 
 	inst->alg.encrypt = crypto_cbc_encrypt;
 	inst->alg.decrypt = crypto_cbc_decrypt;
 
-	err = skcipher_register_instance(tmpl, inst);
+	err = lskcipher_register_instance(tmpl, inst);
 	if (err) {
 out_free_inst:
 		inst->free(inst);