[tip: x86/urgent] x86/csum: Relax the len and proto constraints in 32-bit csum_ipv6_magic()

From: tip-bot2 for Rosen Penev

Date: Sun Nov 01 2026 - 22:57:14 EST


The following commit has been merged into the x86/urgent branch of tip:

Commit-ID: 8a8b11dec31270967fa00caddb2b4453e40078d1
Gitweb: https://git.kernel.org/tip/8a8b11dec31270967fa00caddb2b4453e40078d1
Author: Rosen Penev <rosenp@xxxxxxxxx>
AuthorDate: Mon, 19 Oct 2026 20:32:38 -04:00
Committer: Borislav Petkov (AMD) <bp@xxxxxxxxx>
CommitterDate: Sun, 01 Nov 2026 19:48:14 -08:00

x86/csum: Relax the len and proto constraints in 32-bit csum_ipv6_magic()

Building an i386 allmodconfig kernel with clang fails since allmodconfig
started building netfilter with GCOV profiling:

In file included from net/netfilter/nf_synproxy_core.c:7:
In file included from ./include/linux/skbuff.h:26:
In file included from ./include/net/checksum.h:21:
In file included from ./arch/x86/include/asm/checksum.h:9:
./arch/x86/include/asm/checksum_32.h:149:6: error: inline assembly requires more registers than available

The csum_ipv6_magic() asm needs five registers at once: the early-clobber sum
plus register-only inputs for saddr, daddr, htonl(len) and htonl(proto). With
frame pointers enabled, six general purpose registers are left to choose from.

In synproxy_send_tcp_ipv6(), the GCOV instrumentation lets clang's machine
scheduler move the copies of two incoming register arguments, EDX and ECX,
below the asm.

Both registers then stay live across the asm, which leaves four registers for
its five operands. This is LLVM issue #206307. The error goes away without
either GCOV or frame pointers, and it reproduces with clang 19-22.

Neither len nor proto has to be in a register: ADCL also takes a 32-bit memory
or immediate source operand. Use "g" for both, so the asm needs at most three
registers whatever the caller looks like.

ASM_INPUT_G, which normally replaces "g" to avoid clang's poor handling of it,
is not enough here. It expands to "ir" for clang, so callers that pass
a variable protocol, like nf_ip6_checksum(), would still need five registers.
With "g", clang passes a non-constant len or proto through the stack and still
turns constants into immediates.

[ bp: Make Rosen Penev the author because of a previous identical submission
https://lore.kernel.org/all/20260904000833.2058186-1-rosenp@xxxxxxxxx/ and
Sasha graciously agreeing and giving his much more detailed commit message
explaining the background of why this exists. ]

Fixes: 403cec8ab6d0 ("netfilter: add option for GCOV profiling")
Closes: https://dashboard.kernelci.org/build/maestro:6ad55fe255fda507603d2651
Closes: https://lore.kernel.org/a28df759-d0e9-41c0-97c7-5f89a18d54e2@xxxxxxxxxxxxxxxx
Reported-by: kernelci.org bot <bot@xxxxxxxxxxxx>
Reported-by: Jeff Johnson <jeff.johnson@xxxxxxxxxxxxxxxx>
Assisted-by: LLM
Signed-off-by: Rosen Penev <rosenp@xxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
Signed-off-by: Borislav Petkov (AMD) <bp@xxxxxxxxx>
Acked-by: Nick Desaulniers <ndesaulniers@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
Link: https://github.com/llvm/llvm-project/issues/206307
---
arch/x86/include/asm/checksum_32.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/checksum_32.h b/arch/x86/include/asm/checksum_32.h
index 17da953..f74873a 100644
--- a/arch/x86/include/asm/checksum_32.h
+++ b/arch/x86/include/asm/checksum_32.h
@@ -159,7 +159,7 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
"adcl $0, %0 ;\n"
: "=&r" (sum)
: "r" (saddr), "r" (daddr),
- "r" (htonl(len)), "r" (htonl(proto)), "0" (sum)
+ "g" (htonl(len)), "g" (htonl(proto)), "0" (sum)
: "memory");

return csum_fold(sum);