From nobody Fri Jul 24 20:48:47 2026 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AB4403002D8 for ; Fri, 24 Jul 2026 19:21:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784920894; cv=none; b=GoVQ18SHsF8zI/RUiIF4OfvTkNTM2oRtMF1gwPjOlKyuAPjms20Sr/uy3FG1xCvASJDUXSW2Wfowcuxowl7qJs3XPaftHKCLilSQUuTRvuenT++qMmjF3kUdFAYFNXkyF3/IuJJXmUSKuUOoEOfmVF6sDCD+3xuOfwCJkPY79ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784920894; c=relaxed/simple; bh=0br/BhN46KH6/9zLtcTzmdgli52yUUfxTj2NnVyoqtg=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=cxR4ofZYd0zsnBWfptZBg8y3UuYtMs9/3otTE/rUfv2bwLytSrb7eWZmBrFjW37dtUDP07e+2y6cAJk/6rDTxTu3eiPzmBQPwmbkywHqHK+9izm9M+FrVmfu/R/Y4mbqmGze2G5rmGI52p56tnoLa/sfBrWi4eTCUePDjWNyvjg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=HH3o7YS6; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="HH3o7YS6" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-472326ca506so613562f8f.2 for ; Fri, 24 Jul 2026 12:21:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784920891; x=1785525691; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=Yt7QEqdGvUpHBl3AB0utes+k1j7dbZTUwyvnmarpHRA=; b=HH3o7YS6xjR9zOAwV+YdashN3963aCF0QzXPh5oS7Jor7AcgHV8oN9pzQ6oISSUjJn /IoO1v7hL3PPcqpFn3kyJpSBAQzmPt0PWGE/VNvjwmPqns8qtzoIvLv6VhAb2ffeSG2c /aQfCCE/u49w3lpSNfXDTAPpmr2IQe7FRQD2DrrI6gTCWARrjYl1hJqor3ju1rohNh6R 9IHLhiPdUhyr8HHJ4i7RAmjSRtgw7L1HEn1BIgI6Mot/avepOM7XvK+3oZAIsh6Uz9oT 0mviNqJ9/JDWD6dULqBRWu5dSIymF5i9t2th9xEm5vsrYtkemqyY55iv/E85y2ouY/Rr 8uGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784920891; x=1785525691; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Yt7QEqdGvUpHBl3AB0utes+k1j7dbZTUwyvnmarpHRA=; b=FhNkmHG7SS0k8osS3DMmoHBySfzKFWD1yrzKTl6uKYOOHHKFwo+Zicq+VgMwgzuBql wXp4DKdKQDN0v9jO3RNPbpvxUtQjXFTwKsOPepFF5nqbSGbVRO1tgZ+phD0eQ+t4uAMT S1o7ujJotWJN3RVw4/IKiec2LcCYiH3/AazIuV0IMv1WxELWaI1qse7g7XA1tSIT/j2e cFnIJ+sZZsDLx6eWSMOr495nioHeSxbysb44FJMpo+Xb2ycg7UFBycyWGV0bOskHpGSf kXzfwaBKNg2MjCUL23dLijTr6/GbPdmlebqH0QQ8RYWlXefFg+Ddl3S0dL7UqnxFuFJn T+rQ== X-Forwarded-Encrypted: i=1; AHgh+RoYWGFSr0/LIRhYfH1eZom2tsUibJn7LsNvm2bxTAybqfK6J6uSmNcWNjkkhsoay4fSfwbWADRodfJALW0=@vger.kernel.org X-Gm-Message-State: AOJu0YxRxnvNmlhOibwHH9Gs4LrVjtV1mRtyLzzBTpMQOY8vCYr3nYEE R32el7lnEkyMZpB0Lfj6oi5j0+Lghm1hKcrhomcuKYs0d5Nhz+TDvUy0 X-Gm-Gg: AR+sD11U04csHR1TNCv3e6rKDyCVnnJZuDU8dfRJDO7TjylJLEpM6KN9t8KGlABmstG WgO0RFZxLOFKmwkE18om4w4g5eov6qlNLeTjdVbMNfg0HZK75FJ5djtMcV8YXnOGtDCIUMx5ZJT 6Leqm9efzanZZgJVagH92JRuN9uWdIFQ/lIVTzJjSJv57JM3QtGw98wGIb54rWQeN4mxlJUPGJq Y8ddjE6zhEI28TyL3OlMF3Sz3FjMwvZuxAAAiihu3lD7oJASYicNl9QyoUz8RDzDYGSA6rsPKOm oms3FSLRGdCKAbaoSWjoubBhafB86TdlqcbmDfkeDZ53cYF/4OXUf5eqD9R8uYjoaPEXh1b/VXo jTlrPx+FvzJuvX9moIPBlXLTxT8fVMTbXqI1d5/u76pmU7rfqFBZ+XcDmYpGU0Hw0qrd0GA6Vee g4Cn+P/63fez9VZ0el8R1ye3CC/lDKSQl21iZfPau4vIRq4MoPOZbwo/5sQfawzN0GF42OS9SaS KQmLIZMiE4dIlQHcBM+itxfGJN/b8IyHh5UcT8AlWBSHKKConfXTAhTr4bqOHpsD56ji9VhpDnt 0LndPmx7 X-Received: by 2002:a05:6000:2387:b0:475:f0f0:9ef8 with SMTP id ffacd0b85a97d-47f8d76ee54mr11166320f8f.61.1784920890650; Fri, 24 Jul 2026 12:21:30 -0700 (PDT) Received: from localhost.localdomain (dynamic-2a02-3100-ae93-f301-cdd9-d5ea-080d-9131.310.pool.telefonica.de. [2a02:3100:ae93:f301:cdd9:d5ea:80d:9131]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f85c52fc0sm26203367f8f.23.2026.07.24.12.21.28 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 24 Jul 2026 12:21:30 -0700 (PDT) From: Karl Mehltretter To: Andrey Konovalov Cc: Karl Mehltretter , Alexander Potapenko , Dmitry Vyukov , Marco Elver , Bradley Morgan , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org Subject: [PATCH v2] kcov: report the first spurious PC in the interrupt selftest Date: Fri, 24 Jul 2026 21:21:22 +0200 Message-Id: <20260724192122.73080-1-kmehltretter@gmail.com> X-Mailer: git-send-email 2.39.5 (Apple Git-154) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 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 detec= ted 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; } =20 +#ifdef CONFIG_KCOV_SELFTEST +static unsigned long decanonicalize_ip(unsigned long ip) +{ +#ifdef CONFIG_RANDOMIZE_BASE + ip +=3D 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); =20 #ifdef CONFIG_KCOV_SELFTEST +static unsigned long selftest_area[2] __initdata; + static void __init selftest(void) { - unsigned long start; + unsigned long start, ip; =20 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 =3D 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 =3D 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 --=20 2.53.0