From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from latitanza.investici.org (latitanza.investici.org [185.218.207.228]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 14B1B35675E for ; Fri, 24 Jul 2026 19:27:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.218.207.228 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784921234; cv=none; b=T+pt9vwTPb4eFFW1xojGkesM7SOIDmFuhNO6cEMcdXEwF8rJKQtIvCBtL10EYeOIHrMSMZO6uxr+aSQqt5jJQtcAyf7xAUyOdiJIirv2lrSheX9mUVPHlnnWKIBTZA+ZtoXM4jTnEiRPMQPYViS0muAHH/ZoHOFnsA6Q0YPGESA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784921234; c=relaxed/simple; bh=OdSM2Vzlm/Nb5uF+QKwHpufmugZEbH3yCPnBS4uihho=; h=Date:From:To:CC:Subject:In-Reply-To:References:Message-ID: MIME-Version:Content-Type; b=c+Gp6oRuMfamQ8MK+RBjzrhUxNtwE22KVMfJyAVgXBBGVPZxcxpCFOkmprXVsO2cR2grHmt34tQ5ZBMXgYb4+GyposK6CXZtAUBDnUGje5oke43ToMxXG5s0ZSPjQZGi7Ixofkd7u0WXiaGJFt8Y11PRnqLowKUcqjMMzqM2S+s= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net; spf=pass smtp.mailfrom=grrlz.net; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b=Q4WXGhcA; arc=none smtp.client-ip=185.218.207.228 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=grrlz.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=grrlz.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=grrlz.net header.i=@grrlz.net header.b="Q4WXGhcA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=grrlz.net; s=stigmate; t=1784921228; bh=CGe4jAgHpNPoHjpOV+pBMVWDHQeUqMFAUPLKmHMfTL4=; h=Date:From:To:CC:Subject:In-Reply-To:References:From; b=Q4WXGhcACRTlITIKt2+vznrV8Cczvx1a4Azc3e+55s+FAQUIWAmwmcGu8bEyYl67b dew6L9FeoJulOQNocdY9o3RCMC9hmjaudR6xb0ltSHk3Uf8DuBYbSJS5H8QIDCHoRJ sLrOa9k6EIGVPmgfQ21A9MZbmBZpVKgDV/0HQ+UQ= Received: from mx3.investici.org (unknown [127.0.0.1]) by latitanza.investici.org (Postfix) with ESMTP id 4h6J0D6tC1zGpPb; Fri, 24 Jul 2026 19:27:08 +0000 (UTC) Received: by mx3.investici.org (Postfix) id 4h6J0D3PB4zGpPY; Fri, 24 Jul 2026 19:27:08 +0000 (UTC) Date: Fri, 24 Jul 2026 20:27:07 +0100 From: Bradley Morgan To: Karl Mehltretter , Andrey Konovalov CC: Alexander Potapenko , Dmitry Vyukov , Marco Elver , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org Subject: =?US-ASCII?Q?Re=3A_=5BPATCH_v2=5D_kcov=3A_report_the_first?= =?US-ASCII?Q?_spurious_PC_in_the_interrupt_selftest?= In-Reply-To: <20260724192122.73080-1-kmehltretter@gmail.com> References: <20260724192122.73080-1-kmehltretter@gmail.com> Message-ID: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit On 24 July 2026 20:21:22 BST, Karl Mehltretter wrote: >The KCOV interrupt selftest enables KCOV_MODE_TRACE_PC without a >coverage area so that spurious coverage causes a fault. If the fault >path is instrumented, the coverage callback faults recursively. >Observed failure modes include a stack overflow on x86_64 and arm32 >getting stuck in abort handling, neither of which identifies the >original coverage event. > >The recursive failure is not new, but commit 9a79524d1420 ("kcov: use >WRITE_ONCE() for selftest mode stores") made the selftest effective on >configurations where the compiler had previously removed the mode >store, exposing it more broadly. > >Use a two-word buffer to record the first spurious PC. Once one is >recorded, disable KCOV, report the PC, and panic. This preserves the >selftest's hard failure while avoiding the recursive fault path. > >Add decanonicalize_ip() as the inverse of canonicalize_ip(), which >subtracts kaslr_offset() from recorded PCs, and use it before printing >the PC with %pS. > >Fixes: 6cd0dd934b03 ("kcov: Add interrupt handling self test") >Assisted-by: Claude:claude-opus-4-8 >Signed-off-by: Karl Mehltretter the selftest keeps its hard failure but now names the offending PC instead of recursing into an undebuggable fault, and the enable ordering lives in kcov_start()/kcov_stop() instead of a second open coded copy. LGTM, Reviewed-by: Bradley Morgan >--- >Changes in v2: >- Use kcov_start() and kcov_stop() instead of open-coding their logic. >- Add decanonicalize_ip() next to canonicalize_ip() and use it when > reporting the recorded PC. >- Retest under QEMU on arm64, mips64le, and x86_64. > >This patch improves the failure diagnostics. > >With CONFIG_KCOV_SELFTEST, I observed failures under QEMU on arm, >arm64, riscv64, s390x, ppc64le, mips64le, loongarch, and x86_64. The >reported PCs indicate that this likely needs a global KCOV fix rather >than separate exclusions for each architecture. > >For example, arm64 defconfig with KCOV and KCOV_SELFTEST reports: > > [ 2.741175] kcov: running self test > [ 2.748637] kcov: spurious coverage detected during interrupt selftest: return_address+0x28/0xa8 > [ 2.750623] Kernel panic - not syncing: kcov: interrupt selftest detected spurious coverage > [ 2.752147] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.2.0-rc3-...-dirty #25 PREEMPT(full) > > kernel/kcov.c | 40 ++++++++++++++++++++++++++++++++-------- > 1 file changed, 32 insertions(+), 8 deletions(-) > >diff --git a/kernel/kcov.c b/kernel/kcov.c >index 1df373fb562b..7ddfd01ccd8a 100644 >--- a/kernel/kcov.c >+++ b/kernel/kcov.c >@@ -202,6 +202,16 @@ static notrace unsigned long canonicalize_ip(unsigned long ip) > return ip; > } > >+#ifdef CONFIG_KCOV_SELFTEST >+static unsigned long decanonicalize_ip(unsigned long ip) >+{ >+#ifdef CONFIG_RANDOMIZE_BASE >+ ip += kaslr_offset(); >+#endif >+ return ip; >+} >+#endif >+ > /* > * Entry point from instrumented code. > * This is called once per basic-block/edge. >@@ -1102,9 +1112,11 @@ struct kcov_common_handle_id kcov_common_handle(void) > EXPORT_SYMBOL(kcov_common_handle); > > #ifdef CONFIG_KCOV_SELFTEST >+static unsigned long selftest_area[2] __initdata; >+ > static void __init selftest(void) > { >- unsigned long start; >+ unsigned long start, ip; > > pr_err("running self test\n"); > /* >@@ -1114,15 +1126,27 @@ static void __init selftest(void) > * leaks out of that section and leads to spurious coverage. > * It's hard to call the actual interrupt handler directly, > * so we just loop here for a bit waiting for a timer interrupt. >- * We set kcov_mode to enable tracing, but don't setup the area, >- * so any attempt to trace will crash. Note: we must not call any >- * potentially traced functions in this region. >+ * We set up a two-word coverage area rather than leaving it NULL: >+ * a leak then records its PC instead of crashing on a NULL >+ * dereference, and we can report the offending PC. Note: we >+ * must not call any potentially traced functions in this region. > */ >+ kcov_start(current, NULL, ARRAY_SIZE(selftest_area), >+ selftest_area, KCOV_MODE_TRACE_PC, 0); > start = jiffies; >- WRITE_ONCE(current->kcov_mode, KCOV_MODE_TRACE_PC); >- while ((jiffies - start) * MSEC_PER_SEC / HZ < 300) >- ; >- WRITE_ONCE(current->kcov_mode, 0); >+ while ((jiffies - start) * MSEC_PER_SEC / HZ < 300) { >+ if (READ_ONCE(selftest_area[0])) >+ break; >+ cpu_relax(); >+ } >+ kcov_stop(current); >+ >+ if (selftest_area[0]) { >+ ip = decanonicalize_ip(selftest_area[1]); >+ pr_err("spurious coverage detected during interrupt selftest: %pS\n", >+ (void *)ip); >+ panic("kcov: interrupt selftest detected spurious coverage"); >+ } > pr_err("done running self test\n"); > } > #endif > Thanks!