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

From: Borislav Petkov

Date: Sat Oct 31 2026 - 16:31:07 EST


On Sat, Oct 31, 2026 at 09:36:38AM -0400, Sasha Levin wrote:
> Gentle ping on this one, I don't see it in tip yet. The clang i386
> allmodconfig build of mainline is still failing on it.

Yah, lost in the avalanche of mail. :-\

I have queued this below, it should appear next week, when the MW is over.

---

commit e0837307007837088ce417d8f061f90105f1b20c (HEAD -> refs/heads/queue)
Author: Rosen Penev <rosenp@xxxxxxxxx>
Date: Mon Oct 19 20:32:38 2026 -0400

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

diff --git a/arch/x86/include/asm/checksum_32.h b/arch/x86/include/asm/checksum_32.h
index 17da95387997..f74873a5e351 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);

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette