All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] lib/crypto: chacha: Handle lengths of 2 GiB or more on 32-bit arm and MIPS
@ 2026-10-14 20:34 ` Vladimir Kukharenko
  0 siblings, 0 replies; 7+ messages in thread
From: Vladimir Kukharenko via B4 Relay @ 2026-10-14 20:34 UTC (permalink / raw)
  To: Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel
  Cc: linux-crypto, linux-kernel, linux-arm-kernel, linux-mips,
	Vladimir Kukharenko

On 32-bit arm (the scalar code) and 32-bit MIPS, the ChaCha assembly
treats the length as signed, so lengths of 2 GiB or more are still
mishandled after "lib/crypto: chacha: Use size_t length", since size_t
is 32 bits there.

Patch 1 makes the arm assembly use unsigned conditions.  The MIPS
assembly relies on the sign of the remaining length, so patch 2 instead
limits each call to 1 GiB from C.

This applies on top of
https://lore.kernel.org/r/20261014152604.323310-1-ebiggers@kernel.org
Feel free to fold these into your series instead.

Tested with the lib/crypto KUnit tests in QEMU on arm (Cortex-A7 and
Cortex-A15) and 32-bit MIPS, plus a temporary 2 GiB test on the
Cortex-A7 and QEMU user mode runs of the MIPS assembly.

An LLM review found these bugs; I used an LLM-based assistant to write
the patches and reviewed its work.

---
Vladimir Kukharenko (2):
      lib/crypto: arm/chacha: Handle lengths of 2 GiB or more in scalar code
      lib/crypto: mips/chacha: Handle lengths of 2 GiB or more

 lib/crypto/arm/chacha-scalar-core.S |  8 ++++----
 lib/crypto/arm/chacha.h             |  2 +-
 lib/crypto/mips/chacha-core.S       |  8 ++++----
 lib/crypto/mips/chacha.h            | 20 +++++++++++++++++++-
 4 files changed, 28 insertions(+), 10 deletions(-)
---
base-commit: 40f47fa10a1d19c74f48a13d97b2eb19d5fb938d
change-id: 20261014-libcrypto-chacha-32bit-2gib-5a3e5e36a061
prerequisite-message-id: <20261014152604.323310-1-ebiggers@kernel.org>
prerequisite-patch-id: f66d78884d3d0cf68e1efc9635c084c6b700352f
prerequisite-patch-id: 64c39ea52fe4e25501701ffa262fb3525af29f0b

Best regards,
--  
Vladimir Kukharenko <vladimir@genproof.com>



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 0/2] lib/crypto: chacha: Handle lengths of 2 GiB or more on 32-bit arm and MIPS
@ 2026-10-14 20:34 ` Vladimir Kukharenko
  0 siblings, 0 replies; 7+ messages in thread
From: Vladimir Kukharenko @ 2026-10-14 20:34 UTC (permalink / raw)
  To: Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel
  Cc: linux-crypto, linux-kernel, linux-arm-kernel, linux-mips,
	Vladimir Kukharenko

On 32-bit arm (the scalar code) and 32-bit MIPS, the ChaCha assembly
treats the length as signed, so lengths of 2 GiB or more are still
mishandled after "lib/crypto: chacha: Use size_t length", since size_t
is 32 bits there.

Patch 1 makes the arm assembly use unsigned conditions.  The MIPS
assembly relies on the sign of the remaining length, so patch 2 instead
limits each call to 1 GiB from C.

This applies on top of
https://lore.kernel.org/r/20261014152604.323310-1-ebiggers@kernel.org
Feel free to fold these into your series instead.

Tested with the lib/crypto KUnit tests in QEMU on arm (Cortex-A7 and
Cortex-A15) and 32-bit MIPS, plus a temporary 2 GiB test on the
Cortex-A7 and QEMU user mode runs of the MIPS assembly.

An LLM review found these bugs; I used an LLM-based assistant to write
the patches and reviewed its work.

---
Vladimir Kukharenko (2):
      lib/crypto: arm/chacha: Handle lengths of 2 GiB or more in scalar code
      lib/crypto: mips/chacha: Handle lengths of 2 GiB or more

 lib/crypto/arm/chacha-scalar-core.S |  8 ++++----
 lib/crypto/arm/chacha.h             |  2 +-
 lib/crypto/mips/chacha-core.S       |  8 ++++----
 lib/crypto/mips/chacha.h            | 20 +++++++++++++++++++-
 4 files changed, 28 insertions(+), 10 deletions(-)
---
base-commit: 40f47fa10a1d19c74f48a13d97b2eb19d5fb938d
change-id: 20261014-libcrypto-chacha-32bit-2gib-5a3e5e36a061
prerequisite-message-id: <20261014152604.323310-1-ebiggers@kernel.org>
prerequisite-patch-id: f66d78884d3d0cf68e1efc9635c084c6b700352f
prerequisite-patch-id: 64c39ea52fe4e25501701ffa262fb3525af29f0b

Best regards,
--  
Vladimir Kukharenko <vladimir@genproof.com>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] lib/crypto: arm/chacha: Handle lengths of 2 GiB or more in scalar code
  2026-10-14 20:34 ` Vladimir Kukharenko
@ 2026-10-14 20:34   ` Vladimir Kukharenko
  -1 siblings, 0 replies; 7+ messages in thread
From: Vladimir Kukharenko via B4 Relay @ 2026-10-14 20:34 UTC (permalink / raw)
  To: Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel
  Cc: linux-crypto, linux-kernel, linux-arm-kernel, linux-mips,
	Vladimir Kukharenko

From: Vladimir Kukharenko <vladimir@genproof.com>

chacha_doarm() compares the remaining length with signed conditions
(blt, movle/movgt, bgt), and DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE) in
chacha_crypt_arch() wraps above 0xffffffc0, so lengths of 2 GiB or
more are mishandled.  size_t is 32 bits on arm, so declaring the length
as size_t does not avoid this.  On a Cortex-A7, an in-place
chacha20_crypt() of 2 GiB + 4101 bytes changed only one byte.

Use unsigned conditions (blo, movls/movhi, bhi) and
DIV_ROUND_UP_POW2().

This affects the scalar code, which is used when NEON isn't usable and
always on Cortex-A5 and Cortex-A7.  No in-tree caller passes such
lengths.  Tested in QEMU on a Cortex-A7 with CONFIG_VMSPLIT_1G.  An LLM
review of this code found the bug.

Assisted-by: LLM
Signed-off-by: Vladimir Kukharenko <vladimir@genproof.com>
---
 lib/crypto/arm/chacha-scalar-core.S | 8 ++++----
 lib/crypto/arm/chacha.h             | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/crypto/arm/chacha-scalar-core.S b/lib/crypto/arm/chacha-scalar-core.S
index 509b2f277b57..d9d0a8cee941 100644
--- a/lib/crypto/arm/chacha-scalar-core.S
+++ b/lib/crypto/arm/chacha-scalar-core.S
@@ -163,7 +163,7 @@
 
 	// Use slow path if fewer than 64 bytes remain.
 	cmp		r11, #64
-	blt		.Lxor_slowpath\@
+	blo		.Lxor_slowpath\@
 
 	// Use slow path if IN and/or OUT isn't 4-byte aligned.  Needed even on
 	// ARMv6+, since ldmia and stmia (used below) still require alignment.
@@ -324,8 +324,8 @@
 	ldr		r14, [sp, #160]		// OUT
 	cmp		r9, #64
 	  mov		r0, sp
-	movle		r1, r9
-	movgt		r1, #64
+	movls		r1, r9
+	movhi		r1, #64
 	// r1 is number of bytes to XOR, in range [1, 64]
 
 .if __LINUX_ARM_ARCH__ < 6
@@ -360,7 +360,7 @@
 .Lxor_slowpath_done\@:
 	subs		r9, #64
 	add		sp, #96
-	bgt		.Lprepare_for_next_block\@
+	bhi		.Lprepare_for_next_block\@
 
 .Ldone\@:
 .endm	// _chacha
diff --git a/lib/crypto/arm/chacha.h b/lib/crypto/arm/chacha.h
index 8ce5375f58aa..5b366f4de78d 100644
--- a/lib/crypto/arm/chacha.h
+++ b/lib/crypto/arm/chacha.h
@@ -78,7 +78,7 @@ static void chacha_crypt_arch(struct chacha_state *state, u8 *dst,
 	if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable() ||
 	    bytes <= CHACHA_BLOCK_SIZE) {
 		chacha_doarm(dst, src, bytes, state, nrounds);
-		state->x[12] += DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE);
+		state->x[12] += DIV_ROUND_UP_POW2(bytes, CHACHA_BLOCK_SIZE);
 		return;
 	}
 

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 1/2] lib/crypto: arm/chacha: Handle lengths of 2 GiB or more in scalar code
@ 2026-10-14 20:34   ` Vladimir Kukharenko
  0 siblings, 0 replies; 7+ messages in thread
From: Vladimir Kukharenko @ 2026-10-14 20:34 UTC (permalink / raw)
  To: Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel
  Cc: linux-crypto, linux-kernel, linux-arm-kernel, linux-mips,
	Vladimir Kukharenko

chacha_doarm() compares the remaining length with signed conditions
(blt, movle/movgt, bgt), and DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE) in
chacha_crypt_arch() wraps above 0xffffffc0, so lengths of 2 GiB or
more are mishandled.  size_t is 32 bits on arm, so declaring the length
as size_t does not avoid this.  On a Cortex-A7, an in-place
chacha20_crypt() of 2 GiB + 4101 bytes changed only one byte.

Use unsigned conditions (blo, movls/movhi, bhi) and
DIV_ROUND_UP_POW2().

This affects the scalar code, which is used when NEON isn't usable and
always on Cortex-A5 and Cortex-A7.  No in-tree caller passes such
lengths.  Tested in QEMU on a Cortex-A7 with CONFIG_VMSPLIT_1G.  An LLM
review of this code found the bug.

Assisted-by: LLM
Signed-off-by: Vladimir Kukharenko <vladimir@genproof.com>
---
 lib/crypto/arm/chacha-scalar-core.S | 8 ++++----
 lib/crypto/arm/chacha.h             | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/crypto/arm/chacha-scalar-core.S b/lib/crypto/arm/chacha-scalar-core.S
index 509b2f277b57..d9d0a8cee941 100644
--- a/lib/crypto/arm/chacha-scalar-core.S
+++ b/lib/crypto/arm/chacha-scalar-core.S
@@ -163,7 +163,7 @@
 
 	// Use slow path if fewer than 64 bytes remain.
 	cmp		r11, #64
-	blt		.Lxor_slowpath\@
+	blo		.Lxor_slowpath\@
 
 	// Use slow path if IN and/or OUT isn't 4-byte aligned.  Needed even on
 	// ARMv6+, since ldmia and stmia (used below) still require alignment.
@@ -324,8 +324,8 @@
 	ldr		r14, [sp, #160]		// OUT
 	cmp		r9, #64
 	  mov		r0, sp
-	movle		r1, r9
-	movgt		r1, #64
+	movls		r1, r9
+	movhi		r1, #64
 	// r1 is number of bytes to XOR, in range [1, 64]
 
 .if __LINUX_ARM_ARCH__ < 6
@@ -360,7 +360,7 @@
 .Lxor_slowpath_done\@:
 	subs		r9, #64
 	add		sp, #96
-	bgt		.Lprepare_for_next_block\@
+	bhi		.Lprepare_for_next_block\@
 
 .Ldone\@:
 .endm	// _chacha
diff --git a/lib/crypto/arm/chacha.h b/lib/crypto/arm/chacha.h
index 8ce5375f58aa..5b366f4de78d 100644
--- a/lib/crypto/arm/chacha.h
+++ b/lib/crypto/arm/chacha.h
@@ -78,7 +78,7 @@ static void chacha_crypt_arch(struct chacha_state *state, u8 *dst,
 	if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable() ||
 	    bytes <= CHACHA_BLOCK_SIZE) {
 		chacha_doarm(dst, src, bytes, state, nrounds);
-		state->x[12] += DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE);
+		state->x[12] += DIV_ROUND_UP_POW2(bytes, CHACHA_BLOCK_SIZE);
 		return;
 	}
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] lib/crypto: mips/chacha: Handle lengths of 2 GiB or more
  2026-10-14 20:34 ` Vladimir Kukharenko
@ 2026-10-14 20:34   ` Vladimir Kukharenko
  -1 siblings, 0 replies; 7+ messages in thread
From: Vladimir Kukharenko via B4 Relay @ 2026-10-14 20:34 UTC (permalink / raw)
  To: Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel
  Cc: linux-crypto, linux-kernel, linux-arm-kernel, linux-mips,
	Vladimir Kukharenko

From: Vladimir Kukharenko <vladimir@genproof.com>

The MIPS ChaCha assembly, which is chacha_crypt_arch() itself, tests
the remaining length with signed branches, so for 2 GiB + 64 bytes or
more it takes the final partial block path too early and processes less
than requested.  It is only used on 32-bit kernels, where size_t is 32
bits, so declaring the length as size_t does not avoid this.  No
in-tree caller passes such lengths.

The partial block code also keeps the remaining length as a negative
value, so instead of changing the assembly, rename it to
chacha_crypt_mips() and add a C chacha_crypt_arch() that passes it at
most 1 GiB per call.

Tested in QEMU user mode: with a length of 0xfffff045 the assembly
processed about 4 KiB and advanced the block counter by 64; with the
same 1 GiB loop in C, a 1.25 GiB + 4101 byte buffer matches a C
reference.  An LLM review of this code found the bug.

Assisted-by: LLM
Signed-off-by: Vladimir Kukharenko <vladimir@genproof.com>
---
 lib/crypto/mips/chacha-core.S |  8 ++++----
 lib/crypto/mips/chacha.h      | 20 +++++++++++++++++++-
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/lib/crypto/mips/chacha-core.S b/lib/crypto/mips/chacha-core.S
index 706aeb850fb0..1a2253d91af7 100644
--- a/lib/crypto/mips/chacha-core.S
+++ b/lib/crypto/mips/chacha-core.S
@@ -196,9 +196,9 @@ CONCAT3(.Lchacha_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \
 .text
 .set	reorder
 .set	noat
-.globl	chacha_crypt_arch
-.ent	chacha_crypt_arch
-chacha_crypt_arch:
+.globl	chacha_crypt_mips
+.ent	chacha_crypt_mips
+chacha_crypt_mips:
 	.frame	$sp, STACK_SIZE, $ra
 
 	/* Load number of rounds */
@@ -414,7 +414,7 @@ chacha_crypt_arch:
 
 	/* Jump table */
 	FOR_EACH_WORD(JMPTBL_UNALIGNED)
-.end chacha_crypt_arch
+.end chacha_crypt_mips
 .set at
 
 /* Input arguments
diff --git a/lib/crypto/mips/chacha.h b/lib/crypto/mips/chacha.h
index 5a565d0a8c26..15b39c744c28 100644
--- a/lib/crypto/mips/chacha.h
+++ b/lib/crypto/mips/chacha.h
@@ -6,8 +6,26 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/sizes.h>
 
-asmlinkage void chacha_crypt_arch(struct chacha_state *state, u8 *dst,
+asmlinkage void chacha_crypt_mips(struct chacha_state *state, u8 *dst,
 				  const u8 *src, size_t bytes, int nrounds);
 asmlinkage void hchacha_block_arch(const struct chacha_state *state,
 				   u32 out[HCHACHA_OUT_WORDS], int nrounds);
+
+static void chacha_crypt_arch(struct chacha_state *state, u8 *dst,
+			      const u8 *src, size_t bytes, int nrounds)
+{
+	/*
+	 * chacha_crypt_mips() compares the length as a signed value, so pass
+	 * it at most 1 GiB at a time.
+	 */
+	do {
+		size_t todo = min(bytes, SZ_1G);
+
+		chacha_crypt_mips(state, dst, src, todo, nrounds);
+		bytes -= todo;
+		src += todo;
+		dst += todo;
+	} while (bytes);
+}

-- 
2.43.0



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] lib/crypto: mips/chacha: Handle lengths of 2 GiB or more
@ 2026-10-14 20:34   ` Vladimir Kukharenko
  0 siblings, 0 replies; 7+ messages in thread
From: Vladimir Kukharenko @ 2026-10-14 20:34 UTC (permalink / raw)
  To: Eric Biggers, Jason A. Donenfeld, Ard Biesheuvel
  Cc: linux-crypto, linux-kernel, linux-arm-kernel, linux-mips,
	Vladimir Kukharenko

The MIPS ChaCha assembly, which is chacha_crypt_arch() itself, tests
the remaining length with signed branches, so for 2 GiB + 64 bytes or
more it takes the final partial block path too early and processes less
than requested.  It is only used on 32-bit kernels, where size_t is 32
bits, so declaring the length as size_t does not avoid this.  No
in-tree caller passes such lengths.

The partial block code also keeps the remaining length as a negative
value, so instead of changing the assembly, rename it to
chacha_crypt_mips() and add a C chacha_crypt_arch() that passes it at
most 1 GiB per call.

Tested in QEMU user mode: with a length of 0xfffff045 the assembly
processed about 4 KiB and advanced the block counter by 64; with the
same 1 GiB loop in C, a 1.25 GiB + 4101 byte buffer matches a C
reference.  An LLM review of this code found the bug.

Assisted-by: LLM
Signed-off-by: Vladimir Kukharenko <vladimir@genproof.com>
---
 lib/crypto/mips/chacha-core.S |  8 ++++----
 lib/crypto/mips/chacha.h      | 20 +++++++++++++++++++-
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/lib/crypto/mips/chacha-core.S b/lib/crypto/mips/chacha-core.S
index 706aeb850fb0..1a2253d91af7 100644
--- a/lib/crypto/mips/chacha-core.S
+++ b/lib/crypto/mips/chacha-core.S
@@ -196,9 +196,9 @@ CONCAT3(.Lchacha_mips_xor_aligned_, PLUS_ONE(x), _b: ;) \
 .text
 .set	reorder
 .set	noat
-.globl	chacha_crypt_arch
-.ent	chacha_crypt_arch
-chacha_crypt_arch:
+.globl	chacha_crypt_mips
+.ent	chacha_crypt_mips
+chacha_crypt_mips:
 	.frame	$sp, STACK_SIZE, $ra
 
 	/* Load number of rounds */
@@ -414,7 +414,7 @@ chacha_crypt_arch:
 
 	/* Jump table */
 	FOR_EACH_WORD(JMPTBL_UNALIGNED)
-.end chacha_crypt_arch
+.end chacha_crypt_mips
 .set at
 
 /* Input arguments
diff --git a/lib/crypto/mips/chacha.h b/lib/crypto/mips/chacha.h
index 5a565d0a8c26..15b39c744c28 100644
--- a/lib/crypto/mips/chacha.h
+++ b/lib/crypto/mips/chacha.h
@@ -6,8 +6,26 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/sizes.h>
 
-asmlinkage void chacha_crypt_arch(struct chacha_state *state, u8 *dst,
+asmlinkage void chacha_crypt_mips(struct chacha_state *state, u8 *dst,
 				  const u8 *src, size_t bytes, int nrounds);
 asmlinkage void hchacha_block_arch(const struct chacha_state *state,
 				   u32 out[HCHACHA_OUT_WORDS], int nrounds);
+
+static void chacha_crypt_arch(struct chacha_state *state, u8 *dst,
+			      const u8 *src, size_t bytes, int nrounds)
+{
+	/*
+	 * chacha_crypt_mips() compares the length as a signed value, so pass
+	 * it at most 1 GiB at a time.
+	 */
+	do {
+		size_t todo = min(bytes, SZ_1G);
+
+		chacha_crypt_mips(state, dst, src, todo, nrounds);
+		bytes -= todo;
+		src += todo;
+		dst += todo;
+	} while (bytes);
+}

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] lib/crypto: chacha: Handle lengths of 2 GiB or more on 32-bit arm and MIPS
  2026-10-14 20:34 ` Vladimir Kukharenko
                   ` (2 preceding siblings ...)
  (?)
@ 2026-10-16  7:28 ` Eric Biggers
  -1 siblings, 0 replies; 7+ messages in thread
From: Eric Biggers @ 2026-10-16  7:28 UTC (permalink / raw)
  To: vladimir
  Cc: Jason A. Donenfeld, Ard Biesheuvel, linux-crypto, linux-kernel,
	linux-arm-kernel, linux-mips

On Wed, Oct 14, 2026 at 08:34:20PM +0000, Vladimir Kukharenko via B4 Relay wrote:
> On 32-bit arm (the scalar code) and 32-bit MIPS, the ChaCha assembly
> treats the length as signed, so lengths of 2 GiB or more are still
> mishandled after "lib/crypto: chacha: Use size_t length", since size_t
> is 32 bits there.
> 
> Patch 1 makes the arm assembly use unsigned conditions.  The MIPS
> assembly relies on the sign of the remaining length, so patch 2 instead
> limits each call to 1 GiB from C.
> 
> This applies on top of
> https://lore.kernel.org/r/20261014152604.323310-1-ebiggers@kernel.org
> Feel free to fold these into your series instead.
> 
> Tested with the lib/crypto KUnit tests in QEMU on arm (Cortex-A7 and
> Cortex-A15) and 32-bit MIPS, plus a temporary 2 GiB test on the
> Cortex-A7 and QEMU user mode runs of the MIPS assembly.
> 
> An LLM review found these bugs; I used an LLM-based assistant to write
> the patches and reviewed its work.
> 
> ---

Applied to https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next

- Eric

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-10-16  7:28 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14 20:34 [PATCH 0/2] lib/crypto: chacha: Handle lengths of 2 GiB or more on 32-bit arm and MIPS Vladimir Kukharenko via B4 Relay
2026-10-14 20:34 ` Vladimir Kukharenko
2026-10-14 20:34 ` [PATCH 1/2] lib/crypto: arm/chacha: Handle lengths of 2 GiB or more in scalar code Vladimir Kukharenko via B4 Relay
2026-10-14 20:34   ` Vladimir Kukharenko
2026-10-14 20:34 ` [PATCH 2/2] lib/crypto: mips/chacha: Handle lengths of 2 GiB or more Vladimir Kukharenko via B4 Relay
2026-10-14 20:34   ` Vladimir Kukharenko
2026-10-16  7:28 ` [PATCH 0/2] lib/crypto: chacha: Handle lengths of 2 GiB or more on 32-bit arm and MIPS Eric Biggers

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.