smsusb_onresponse() re-runs INIT_WORK() on surb->wq every time an URB completes, right before scheduling it. INIT_WORK() resets work->data, which is where the workqueue keeps the work's state, including the "being cancelled" mark that cancel_work_sync() sets while it waits. smsusb_stop_streaming() kills the URB and then cancels the work. If do_submit_urb() is running at that point it can resubmit the URB, and if that URB completes during the cancel, smsusb_onresponse() re-initialises the work, wiping the cancel mark, and queues it again. __flush_work() then finds a queued work where it expects an idle one: smsusb:smsusb_init_device: smscore_start_device(...) failed data & WORK_STRUCT_PWQ WARNING: kernel/workqueue.c:4425 at __flush_work+0xc8f/0xd70 kernel/workqueue.c:4425 __cancel_work_sync+0xbf/0x110 kernel/workqueue.c:4568 smsusb_stop_streaming drivers/media/usb/siano/smsusb.c:183 [inline] smsusb_term_device+0xdd/0x3d0 drivers/media/usb/siano/smsusb.c:345 smsusb_init_device drivers/media/usb/siano/smsusb.c:497 [inline] smsusb_probe+0x1aba/0x2280 drivers/media/usb/siano/smsusb.c:575 Initialise each work item once, next to the URB it resubmits, and only schedule it from the completion handler. smsusb_stop_streaming() keeps its wq.func check, which still skips the URBs that were never set up when smsusb_init_device() fails early. Fixes: ebad8e731c1c ("media: usb: siano: Fix use after free bugs caused by do_submit_urb") Reported-by: syzbot+d627b1495de0e851be32@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Yogesh Gaur --- Built with W=1 only; not runtime-tested. drivers/media/usb/siano/smsusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 0fdc2e0950b7..210c323c8232 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -143,7 +143,6 @@ static void smsusb_onresponse(struct urb *urb) exit_and_resubmit: - INIT_WORK(&surb->wq, do_submit_urb); schedule_work(&surb->wq); } @@ -468,6 +467,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) /* initialize urbs */ for (i = 0; i < MAX_URBS; i++) { dev->surbs[i].dev = dev; + INIT_WORK(&dev->surbs[i].wq, do_submit_urb); dev->surbs[i].urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->surbs[i].urb) goto err_unregister_device; -- 2.55.0.windows.5