Re: [PATCH] usbip: fix use-after-free in event_handler()
From: Shuah Khan
Date: Mon Aug 10 2026 - 15:33:36 EST
On 8/7/26 08:18, Aleksandr Nogikh wrote:
Hi Shuah,
Thanks for reviewing the patch!
On Tue, Aug 4, 2026 at 7:31 PM Shuah Khan <skhan@xxxxxxxxxxxxxxxxxxx> wrote:
On 8/3/26 09:05, syzbot wrote:
From: Aleksandr Nogikh <nogikh@xxxxxxxxxx>
The event_handler function in drivers/usb/usbip/usbip_event.c is a
workqueue item responsible for processing events for a struct usbip_device.
During device teardown, usbip_stop_eh() is called to wait for the event
handler to finish processing. However, usbip_stop_eh() uses
wait_event_interruptible() and ignores its return value. If the process
unbinding the driver receives a signal, wait_event_interruptible() returns
immediately, causing the teardown process to falsely assume the event
handler has finished.
Does this mean unbinding didn't happen?
The unbinding did happen (and finished freeing the memory), but
without actually waiting for event_handler() in
drivers/usb/usbip/usbip_event.c to finish processing the removal
event. As the device memory was prematurely freed, we got the
use-after-free crash in event_handler().
For reference, here's a C reproducer for the original bug:
https://syzkaller.appspot.com/text?tag=ReproC&x=16ffb7b9580000
It sets up a timer to deliver a signal and wakes up the
wait_event_interruptible() call.
Thanks.
The teardown process then proceeds to free the
usbip_device memory. Meanwhile, the event_handler workqueue is still
running and attempts to access the freed usbip_device, resulting in a KASAN
slab-use-after-free crash.
BUG: KASAN: slab-use-after-free in __mutex_lock_common
kernel/locking/rtmutex_api.c:559 [inline]
BUG: KASAN: slab-use-after-free in mutex_lock_nested+0x5a/0x1d0
kernel/locking/rtmutex_api.c:578
Read of size 1 at addr ffff8881145245b0 by task kworker/u8:5/6177
Call Trace:
<TASK>
lock_acquire+0x84/0x350 kernel/locking/lockdep.c:5842
__mutex_lock_common kernel/locking/rtmutex_api.c:559 [inline]
mutex_lock_nested+0x5a/0x1d0 kernel/locking/rtmutex_api.c:578
event_handler+0x1e3/0x4a0 drivers/usb/usbip/usbip_event.c:73
process_one_work kernel/workqueue.c:3322 [inline]
process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405
worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486
kthread+0x388/0x470 kernel/kthread.c:436
ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
To fix this, change wait_event_interruptible() to wait_event() in
usbip_stop_eh(). This ensures that the teardown process strictly waits for
the event handler to finish its execution and drop all references to the
usbip_device before the memory is freed, preventing the use-after-free.
This change is safe from deadlocks because usbip_stop_eh() is never called
with locks held that the event_handler would need to acquire.
Correct - usbip_stop_eh() is called without lock hold after updating
the shutdown_busid status to true. However I am curious what happens
to the unbinding? Should usbip_stop_eh() check the return value of
wait_event_interruptible() and handle the error instead?
During unbinding, we must wait for the scheduled removal event to
finish before we can safely free the device structures. From what I
see in the code, once we have reached wait_event_interruptible(),
there's no way to abort the process or somehow gracefully handle the
error.
Yes I agree with you on rewinding being hard.
Care to explain the scope of this assist?
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
thanks,
-- Shuah