When fuzzing USB with syzkaller on a PREEMPT_RT enabled kernel, following bug is triggered in the ksoftirqd context.
| BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48 | in_atomic(): 0, irqs_disabled(): 1, non_block: 0, pid: 30, name: ksoftirqd/1 | preempt_count: 0, expected: 0 | RCU nest depth: 2, expected: 2 | CPU: 1 UID: 0 PID: 30 Comm: ksoftirqd/1 Tainted: G W 6.16.0-rc1-rt1 #11 PREEMPT_RT | Tainted: [W]=WARN | Hardware name: QEMU KVM Virtual Machine, BIOS 2025.02-8 05/13/2025 | Call trace: | show_stack+0x2c/0x3c (C) | __dump_stack+0x30/0x40 | dump_stack_lvl+0x148/0x1d8 | dump_stack+0x1c/0x3c | __might_resched+0x2e4/0x52c | rt_spin_lock+0xa8/0x1bc | kcov_remote_start+0xb0/0x490 | __usb_hcd_giveback_urb+0x2d0/0x5e8 | usb_giveback_urb_bh+0x234/0x3c4 | process_scheduled_works+0x678/0xd18 | bh_worker+0x2f0/0x59c | workqueue_softirq_action+0x104/0x14c | tasklet_action+0x18/0x8c | handle_softirqs+0x208/0x63c | run_ksoftirqd+0x64/0x264 | smpboot_thread_fn+0x4ac/0x908 | kthread+0x5e8/0x734 | ret_from_fork+0x10/0x20
To reproduce on PREEMPT_RT kernel:
$ git remote add rt-devel git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git $ git fetch rt-devel $ git checkout -b v6.16-rc1-rt1 v6.16-rc1-rt1
I have attached the syzlang and the C source code converted by syz-prog2c:
Link: https://gist.github.com/kzall0c/9455aaa246f4aa1135353a51753adbbe
Then, run with a PREEMPT_RT config.
This issue was introduced by commit f85d39dd7ed8 ("kcov, usb: disable interrupts in kcov_remote_start_usb_softirq").
However, this creates a conflict on PREEMPT_RT kernels. The local_irq_save() call establishes an atomic context where sleeping is forbidden. Inside this context, kcov_remote_start() is called, which on PREEMPT_RT uses sleeping locks (spinlock_t and local_lock_t are mapped to rt_mutex). This results in a sleeping function called from invalid context.
On PREEMPT_RT, interrupt handlers are threaded, so the re-entrancy scenario is already safely handled by the existing local_lock_t and the global kcov_remote_lock within kcov_remote_start(). Therefore, the outer local_irq_save() is not necessary.
This preserves the intended re-entrancy protection for non-RT kernels while resolving the locking violation on PREEMPT_RT kernels.
After making this modification and testing it, syzkaller fuzzing the PREEMPT_RT kernel is now running without stopping on latest announced Real-time Linux.
Link: https://lore.kernel.org/linux-rt-devel/20250610080307.LMm1hleC@linutronix.de... Fixes: f85d39dd7ed8 ("kcov, usb: disable interrupts in kcov_remote_start_usb_softirq") Cc: Andrey Konovalov andreyknvl@gmail.com Cc: Tetsuo Handa penguin-kernel@i-love.sakura.ne.jp Cc: Alan Stern stern@rowland.harvard.edu Cc: Dmitry Vyukov dvyukov@google.com Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Thomas Gleixner tglx@linutronix.de Cc: Sebastian Andrzej Siewior bigeasy@linutronix.de Cc: Byungchul Park byungchul@sk.com Cc: stable@vger.kernel.org Cc: kasan-dev@googlegroups.com Cc: syzkaller@googlegroups.com Cc: linux-usb@vger.kernel.org Cc: linux-rt-devel@lists.linux.dev Signed-off-by: Yunseong Kim ysk@kzalloc.com --- include/linux/kcov.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 75a2fb8b16c3..c5e1b2dd0bb7 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -85,7 +85,9 @@ static inline unsigned long kcov_remote_start_usb_softirq(u64 id) unsigned long flags = 0;
if (in_serving_softirq()) { +#ifndef CONFIG_PREEMPT_RT local_irq_save(flags); +#endif kcov_remote_start_usb(id); }
@@ -96,7 +98,9 @@ static inline void kcov_remote_stop_softirq(unsigned long flags) { if (in_serving_softirq()) { kcov_remote_stop(); +#ifndef CONFIG_PREEMPT_RT local_irq_restore(flags); +#endif } }