[PATCH] arm64: irq: exclude the softirq stack switch from KCOV

From: Karl Mehltretter

Date: Sat Sep 26 2026 - 15:13:51 EST


On IRQ exit, __irq_exit_rcu() drops HARDIRQ_OFFSET before calling
invoke_softirq(). The arm64 do_softirq_own_stack() wrapper and its
____do_softirq() trampoline run before __do_softirq() establishes
softirq context, so KCOV records their PCs in the interrupted task's
coverage buffer. They also run outside softirq accounting when
local_bh_enable() reaches do_softirq().

The IRQ-exit coverage makes the KCOV boot selftest fail even after
the scheduler and timer coverage leaks are suppressed. The generic
softirq.o is already excluded from KCOV, but that exclusion does not
cover the separately compiled arm64 wrappers.

Exclude irq.o from KCOV instrumentation, as is already done for the
arm64 entry code. This covers both wrappers even with compilers that
lack the no_sanitize_coverage attribute. The softirq action functions
remain instrumented for explicit remote coverage.

Fixes: 8eb858c44b98 ("arm64: run softirqs on the per-CPU IRQ stack")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
---
This patch applies without my other pending KCOV or softirq patches.
For testing, the pause series [1] suppresses the other known
timer/scheduler leaks, and the selftest diagnostic [2] reports the
remaining PCs.

Tested on mainline 40288c9206c17 with both prerequisites applied:
- GCC 15.2 arm64 builds, KCOV_INSTRUMENT_ALL and KCOV_SELFTEST enabled.
- QEMU virt/cortex-a76: baseline reports 15 PCs alternating between
the two wrappers and panics. The fix passes three boots with KASLR
and three with nokaslr. All KASLR boots have nonzero relocation.
- Raspberry Pi 500, BCM2712 D0: baseline records seven PCs from each
wrapper. The fixed kernel completes the strict selftest with zero
PCs. The baseline alone replaces the final panic with a diagnostic
and return so SSH can retrieve its log. Recording is unchanged.
- Clang 21 W=1 object builds: irq.o has no KCOV callbacks after the
change, while syscall.o retains its instrumentation.
- Fixed QEMU image: positive PC and comparison coverage remains live
for getpid() and close(-1), with neither buffer saturated.

My softirq IRQ-exit v3 patch [3] makes the boot selftest pass in QEMU
and on the Pi without this patch. It does not cover the task-context
path through local_bh_enable(). A five-send loopback UDP test shows:

v3 v3 + this patch
Wrapper PC entries (five sends) 10 0
Sends covering udp_sendmsg() 5/5 5/5

A bounded syzkaller replay compared my softirq v4 patch [4] alone
against v4 plus this patch. It used 18 reviewed programs with 40
executions per program and variant across four fresh boots in A-B-B-A
order. A is v4 alone; B adds this patch:

v4 v4 + this patch
Program executions 720 720
Wrapper PC entries (40 sends) 80 0
Stable non-wrapper locations 7,172 7,172
Executions to reach 99% 17 17
Greedy fixed corpus 16/4,068 B 16/4,068 B
Executor time 3.932 s 3.956 s

This fixed replay measures coverage cleanup, not syz-manager discovery
or corpus growth.

A longer replay used the same A-B-B-A order and ran the workload for
30 minutes per variant. Excluding a 30-second warmup from each 15-minute
session left 29 measured minutes per variant:

v4 v4 + this patch
Program executions 119,883 119,868
Programs/s 68.898 68.890
Mean executor time/program 5.256 ms 5.285 ms
90%-stable non-wrapper locations 6,959 6,953
Wrapper PC entries (40 sends) 80 0
KCOV overflows 0 0

The 80 entries are 40 instances of each wrapper PC. The variants shared
6,952 stable non-wrapper locations; the six unmatched locations were
route-lookup PCs. The timing differences were not material.

Apply checks pass on v6.1, v6.6, v6.12 and v6.18; those older kernels
have not been built or boot-tested here.

[1] https://lore.kernel.org/all/20260914054632.12877-1-kmehltretter@xxxxxxxxx/
[2] https://lore.kernel.org/all/20260919080220.37633-1-kmehltretter@xxxxxxxxx/
[3] https://lore.kernel.org/all/20260924041538.52574-1-kmehltretter@xxxxxxxxx/
[4] https://lore.kernel.org/r/20260926143505.66024-1-kmehltretter@xxxxxxxxx/

arch/arm64/kernel/Makefile | 3 +++
1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index d2690c3ec5288..ea66339435bf0 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -25,6 +25,9 @@ KASAN_SANITIZE_stacktrace.o := n
KCOV_INSTRUMENT_entry-common.o := n
KCOV_INSTRUMENT_idle.o := n

+# Softirq stack switching can run outside interrupt context.
+KCOV_INSTRUMENT_irq.o := n
+
# Object file lists.
obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
entry-common.o process.o ptrace.o \
--
2.53.0