mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH (draft)] kcov: fix potential kcov_mode corruption under CONFIG_PREEMPT_RT
@ 2026-05-04 15:30 Tetsuo Handa
  2026-05-04 15:39 ` Tetsuo Handa
  2026-05-05  8:15 ` [PATCH] " Tetsuo Handa
  0 siblings, 2 replies; 29+ messages in thread
From: Tetsuo Handa @ 2026-05-04 15:30 UTC (permalink / raw)
  To: kasan-dev, LKML; +Cc: Dmitry Vyukov, Alexander Potapenko

Problem Description:

  syzbot has reported intermittent kcov_mode corruption when running with
  CONFIG_PREEMPT_RT=y. Specifically, struct task_struct->kcov_mode is found
  to be unexpectedly modified (e.g., changed from 0 to 2) during workqueue
  execution, even when the work handler itself does not use KCOV [1].

Root Cause Analysis:

  The issue stems from the ambiguity of in_task() under CONFIG_PREEMPT_RT.
  Since commit 5ff3b30ab57d ("kcov: collect coverage from interrupts"),
  kcov_remote_start() uses in_task() to decide whether to use a per-CPU
  preallocated buffer (irq_area) or a task-specific buffer (allocated via
  vmalloc).

  In a CONFIG_PREEMPT_RT kernel, in_task() returns true even for threaded
  softirqs (e.g., ksoftirqd or threaded IRQ handlers), unless they are
  explicitly within a local_bh_disable() region at the time of the check.
  This leads to several critical issues:

    1. Context Mismatch: A threaded interrupt handler (like usb_giveback_urb_bh)
    might be identified as a "task" context. If it starts a remote KCOV
    session, it incorrectly modifies the kworker's task_struct->kcov_mode
    using the logic intended for system calls.

    2. State Leakage: If the result of in_task() differs between
    kcov_remote_start() and kcov_remote_stop() due to the subtle state
    changes in RT scheduling, the cleanup code (kcov_stop()) might be skipped
    or applied to the wrong context. This leaves kcov_mode set to a non-zero
    value (e.g., KCOV_MODE_TRACE_CMP) when the worker returns to
    process_one_work().

    3. Evidence: Debug logs show the pr_err from process_one_work()
    carrying a [ C1] (CPU-based) prefix instead of a [Txxx] (Task-based)
    prefix. This confirms that at the moment of the error,
    in_serving_softirq() was true, causing in_task() to be false, which
    contradicts the state when the work started.

Proposed Fix:

  Introduce a more strict context check, in_task_really(), which
  explicitly excludes any softirq context (including threaded ones) by
  checking in_serving_softirq() regardless of the CONFIG_PREEMPT_RT
  configuration. This ensures that threaded interrupts always use the
  irq_area path and do not corrupt the task_struct state of the worker
  threads they happen to preempt.

I wrote this patch's body, but patch description above was generated
using Google AI mode. I can't tell whether above explanation is correct.
Therefore, please review but don't accept yet. For now:

Link: https://syzkaller.appspot.com/bug?extid=a21650c1666eae7b2aae [1]
Analyzed-by: https://share.google/aimode/5aL6wtYxiS3koWnAx (expires in 7 days)
Not-yet-signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Fixes: 5ff3b30ab57d ("kcov: collect coverage from interrupts")
Reported-by: syzbot+3f51ad7ac3ae57a6fdcc@syzkaller.appspotmail.com
Maybe-closes: https://syzkaller.appspot.com/bug?extid=3f51ad7ac3ae57a6fdcc
---
 kernel/kcov.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/kernel/kcov.c b/kernel/kcov.c
index 0b369e88c7c9..c20d3c2712d7 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -171,6 +171,15 @@ static __always_inline bool in_softirq_really(void)
 	return in_serving_softirq() && !in_hardirq() && !in_nmi();
 }
 
+static __always_inline bool in_task_really(void)
+{
+#ifdef CONFIG_PREEMPT_RT
+	return !in_serving_softirq() && !in_hardirq() && !in_nmi();
+#else
+	return in_task();
+#endif
+}
+
 static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
 {
 	unsigned int mode;
@@ -903,7 +912,7 @@ void kcov_remote_start(u64 handle)
 		return;
 	}
 	kcov_debug("handle = %llx, context: %s\n", handle,
-			in_task() ? "task" : "softirq");
+		   in_task_really() ? "task" : "softirq");
 	kcov = remote->kcov;
 	/* Put in kcov_remote_stop(). */
 	kcov_get(kcov);
@@ -915,7 +924,7 @@ void kcov_remote_start(u64 handle)
 	 */
 	mode = context_unsafe(kcov->mode);
 	sequence = kcov->sequence;
-	if (in_task()) {
+	if (in_task_really()) {
 		size = kcov->remote_size;
 		area = kcov_remote_area_get(size);
 	} else {
@@ -924,7 +933,7 @@ void kcov_remote_start(u64 handle)
 	}
 	spin_unlock(&kcov_remote_lock);
 
-	/* Can only happen when in_task(). */
+	/* Can only happen when in_task_really(). */
 	if (!area) {
 		local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
 		area = vmalloc(size * sizeof(unsigned long));
@@ -1069,7 +1078,7 @@ void kcov_remote_stop(void)
 		kcov_move_area(kcov->mode, kcov->area, kcov->size, area);
 	spin_unlock(&kcov->lock);
 
-	if (in_task()) {
+	if (in_task_really()) {
 		spin_lock(&kcov_remote_lock);
 		kcov_remote_area_put(area, size);
 		spin_unlock(&kcov_remote_lock);
-- 
2.47.3


^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2026-07-16  9:13 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-04 15:30 [PATCH (draft)] kcov: fix potential kcov_mode corruption under CONFIG_PREEMPT_RT Tetsuo Handa
2026-05-04 15:39 ` Tetsuo Handa
2026-05-05  8:15 ` [PATCH] " Tetsuo Handa
2026-05-06 11:55   ` [PATCH v2] kcov: fix state corruption under CONFIG_PREEMPT_RT by eliminating per-cpu data Tetsuo Handa
2026-05-09  8:09     ` [PATCH v3] kcov: move kcov_remote_data to task_struct for RT and remove local_lock Tetsuo Handa
2026-05-15  7:10       ` Dmitry Vyukov
2026-05-20 10:33         ` Tetsuo Handa
2026-05-20 15:12       ` Sebastian Andrzej Siewior
2026-05-21  8:38       ` Sebastian Andrzej Siewior
2026-05-21 15:28         ` Tetsuo Handa
2026-05-21 18:14           ` Sebastian Andrzej Siewior
2026-05-22  2:39             ` Tetsuo Handa
2026-05-22 11:10               ` [PATCH v4] kcov: move kcov_remote_data to task_struct " Tetsuo Handa
2026-05-22 13:27                 ` Sebastian Andrzej Siewior
2026-05-29  6:35                 ` Tetsuo Handa
2026-06-27  9:58                   ` [PATCH v5] kcov: fix data corruption and race conditions on PREEMPT_RT by moving saved remote state to task_struct Tetsuo Handa
2026-07-07 13:36                     ` Tetsuo Handa
2026-07-07 15:00                       ` Alexander Potapenko
2026-07-07 22:07                         ` Tetsuo Handa
2026-07-08 15:28                     ` Alexander Potapenko
2026-07-09 13:35                       ` Tetsuo Handa
2026-07-10 10:43                         ` Alexander Potapenko
2026-07-10 11:32                           ` [PATCH v6] " Tetsuo Handa
2026-07-10 12:16                             ` Alexander Potapenko
2026-07-15 23:01                               ` [PATCH v7] kcov: fix data corruption and race conditions on PREEMPT_RT Tetsuo Handa
2026-07-16  9:12                                 ` Alexander Potapenko
2026-07-10 14:24                             ` [PATCH v6] kcov: fix data corruption and race conditions on PREEMPT_RT by moving saved remote state to task_struct Sebastian Andrzej Siewior
2026-05-21 13:06       ` [PATCH v3] kcov: move kcov_remote_data to task_struct for RT and remove local_lock Alexander Potapenko
2026-05-21 14:39         ` Tetsuo Handa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox