Skip to content

Commit 7d4df2d

Browse files
xairyakpm00
authored andcommitted
kcov: properly check for softirq context
When collecting coverage from softirqs, KCOV uses in_serving_softirq() to check whether the code is running in the softirq context. Unfortunately, in_serving_softirq() is > 0 even when the code is running in the hardirq or NMI context for hardirqs and NMIs that happened during a softirq. As a result, if a softirq handler contains a remote coverage collection section and a hardirq with another remote coverage collection section happens during handling the softirq, KCOV incorrectly detects a nested softirq coverate collection section and prints a WARNING, as reported by syzbot. This issue was exposed by commit a7f3813 ("usb: gadget: dummy_hcd: Switch to hrtimer transfer scheduler"), which switched dummy_hcd to using hrtimer and made the timer's callback be executed in the hardirq context. Change the related checks in KCOV to account for this behavior of in_serving_softirq() and make KCOV ignore remote coverage collection sections in the hardirq and NMI contexts. This prevents the WARNING printed by syzbot but does not fix the inability of KCOV to collect coverage from the __usb_hcd_giveback_urb when dummy_hcd is in use (caused by a7f3813); a separate patch is required for that. Link: https://lkml.kernel.org/r/[email protected] Fixes: 5ff3b30 ("kcov: collect coverage from interrupts") Signed-off-by: Andrey Konovalov <[email protected]> Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=2388cdaeb6b10f0c13ac Acked-by: Marco Elver <[email protected]> Cc: Alan Stern <[email protected]> Cc: Aleksandr Nogikh <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Dmitry Vyukov <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Marcello Sylvester Bauer <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 37bf7fb commit 7d4df2d

File tree

1 file changed

+12
-3
lines changed

1 file changed

+12
-3
lines changed

kernel/kcov.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,15 @@ static void kcov_remote_area_put(struct kcov_remote_area *area,
161161
kmsan_unpoison_memory(&area->list, sizeof(area->list));
162162
}
163163

164+
/*
165+
* Unlike in_serving_softirq(), this function returns false when called during
166+
* a hardirq or an NMI that happened in the softirq context.
167+
*/
168+
static inline bool in_softirq_really(void)
169+
{
170+
return in_serving_softirq() && !in_hardirq() && !in_nmi();
171+
}
172+
164173
static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t)
165174
{
166175
unsigned int mode;
@@ -170,7 +179,7 @@ static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_stru
170179
* so we ignore code executed in interrupts, unless we are in a remote
171180
* coverage collection section in a softirq.
172181
*/
173-
if (!in_task() && !(in_serving_softirq() && t->kcov_softirq))
182+
if (!in_task() && !(in_softirq_really() && t->kcov_softirq))
174183
return false;
175184
mode = READ_ONCE(t->kcov_mode);
176185
/*
@@ -849,7 +858,7 @@ void kcov_remote_start(u64 handle)
849858

850859
if (WARN_ON(!kcov_check_handle(handle, true, true, true)))
851860
return;
852-
if (!in_task() && !in_serving_softirq())
861+
if (!in_task() && !in_softirq_really())
853862
return;
854863

855864
local_lock_irqsave(&kcov_percpu_data.lock, flags);
@@ -991,7 +1000,7 @@ void kcov_remote_stop(void)
9911000
int sequence;
9921001
unsigned long flags;
9931002

994-
if (!in_task() && !in_serving_softirq())
1003+
if (!in_task() && !in_softirq_really())
9951004
return;
9961005

9971006
local_lock_irqsave(&kcov_percpu_data.lock, flags);

0 commit comments

Comments
 (0)