[PATCH] usbip: Fix use-after-free in event_handler workqueue

Heitor Alves de Siqueira posted 1 patch 1 week, 2 days ago
drivers/usb/usbip/usbip_event.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
[PATCH] usbip: Fix use-after-free in event_handler workqueue
Posted by Heitor Alves de Siqueira 1 week, 2 days ago
In vhci_stop(), the driver calls usbip_stop_eh() and waits until event
flags are cleared before proceeding with cleanup. The event_handler thread
clears event flags before calling wake_up(&ud->eh_waitq), opening a race
window where wait_event_interruptible() can return before the event_handler
thread finishes. This causes the teardown path to free usbip structures,
leading to a use-after-free when accessing ud->eh_waitq.

Fix by flushing usbip_work in usbip_stop_eh(). This ensures the work item
has finished before the driver cleans up the usbip_device struct.

Fixes: bb7871ad99ea ("usbip: event handler as one thread")
Reported-by: syzbot+62c1aa73226b3ac3b107@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=62c1aa73226b3ac3b107
Cc: stable@kernel.org
Signed-off-by: Heitor Alves de Siqueira <halves@igalia.com>
---
 drivers/usb/usbip/usbip_event.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/usbip/usbip_event.c b/drivers/usb/usbip/usbip_event.c
index 0e00c2d000f8..2d041b7ee7cf 100644
--- a/drivers/usb/usbip/usbip_event.c
+++ b/drivers/usb/usbip/usbip_event.c
@@ -97,6 +97,11 @@ static void event_handler(struct work_struct *work)
 	}
 }
 
+#define WORK_QUEUE_NAME "usbip_event"
+
+static struct workqueue_struct *usbip_queue;
+static DECLARE_WORK(usbip_work, event_handler);
+
 int usbip_start_eh(struct usbip_device *ud)
 {
 	init_waitqueue_head(&ud->eh_waitq);
@@ -116,15 +121,12 @@ void usbip_stop_eh(struct usbip_device *ud)
 		usbip_dbg_eh("usbip_eh waiting completion %lx\n", pending);
 
 	wait_event_interruptible(ud->eh_waitq, !(ud->event & ~USBIP_EH_BYE));
+	flush_work(&usbip_work);
+
 	usbip_dbg_eh("usbip_eh has stopped\n");
 }
 EXPORT_SYMBOL_GPL(usbip_stop_eh);
 
-#define WORK_QUEUE_NAME "usbip_event"
-
-static struct workqueue_struct *usbip_queue;
-static DECLARE_WORK(usbip_work, event_handler);
-
 int usbip_init_eh(void)
 {
 	usbip_queue = create_singlethread_workqueue(WORK_QUEUE_NAME);

---
base-commit: 8fde5d1d47f69db6082dfa34500c27f8485389a5
change-id: 20260529-b4-usbip_eh-9f21939c8b5a

Best regards,
--  
Heitor Alves de Siqueira <halves@igalia.com>