From: Igor Putko <igorpetindev@gmail.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Alan Stern <stern@rowland.harvard.edu>, Tejun Heo <tj@kernel.org>,
Oliver Neukum <oneukum@suse.com>,
linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org,
syzbot+a5b220cacb0618384d5a@syzkaller.appspotmail.com,
Igor Putko <igorpetindev@gmail.com>
Subject: [PATCH v3] usb: core: hcd: flush giveback work on stop
Date: Sat, 24 Oct 2026 18:56:14 +0300 [thread overview]
Message-ID: <20261024155614.2732-1-igorpetindev@gmail.com> (raw)
In-Reply-To: <20261023174015.54793-1-igorpetindev@gmail.com>
When an HCD is stopped/removed (either during module unload, driver
unbind, or an error path in probe), pending URBs are unlinked and
completed. However, for root hubs or HCDs with giveback done in BH
context, the work function usb_giveback_urb_bh() may still be executing
on another CPU after __usb_hcd_giveback_urb() drops the URB use_count
and wakes up waiters in usb_kill_urb().
Since the caller may immediately free the struct usb_hcd via usb_put_hcd()
after usb_stop_hcd() or usb_remove_hcd(), the running worker accesses
the embedded giveback_urb_bh structure in its epilogue (e.g. clearing
completing_ep or clearing the running flag) after the memory has been
freed, triggering a slab-use-after-free write detected by KASAN.
Ensure all giveback work has fully completed in usb_stop_hcd() by calling
flush_work() on both high and low priority BHs before deallocating.
Also remove the misleading comment in usb_remove_hcd() claiming
flush_work() is unneeded, and document the queue emptiness in the
usb_stop_hcd() kerneldoc.
Fixes: 8fea0c8fda30 ("usb: core: hcd: Convert from tasklet to BH workqueue")
Reported-by: syzbot+a5b220cacb0618384d5a@syzkaller.appspotmail.com
Closes: https://syzkaller.appspotmail.com/bug?extid=a5b220cacb0618384d5a
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Igor Putko <igorpetindev@gmail.com>
---
v2 -> v3:
- Remove obsolete comment in usb_remove_hcd() regarding flush_work().
- Add comment in usb_stop_hcd() explaining why flush_work() is needed.
- Update kerneldoc for usb_stop_hcd() to state giveback queues are empty.
v1 -> v2:
- Use flush_work() instead of cancel_work_sync() as suggested by Alan Stern.
drivers/usb/core/hcd.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8e8a5f59b319..f403795b17ba 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2773,6 +2773,8 @@ static void usb_put_invalidate_rhdev(struct usb_hcd *hcd)
* usb_stop_hcd - Halt the HCD
* @hcd: the usb_hcd that has to be halted
*
+ * The two giveback queues should be entirely empty when this runs.
+ *
* Stop the root-hub polling timer and invoke the HCD's ->stop callback.
*/
static void usb_stop_hcd(struct usb_hcd *hcd)
@@ -2787,6 +2789,13 @@ static void usb_stop_hcd(struct usb_hcd *hcd)
/* In case the HCD restarted the timer, stop it again. */
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
timer_delete_sync(&hcd->rh_timer);
+
+ /*
+ * Even though all URBs have been given back, the work routine itself
+ * may still be finishing up and accessing the usb_hcd structure.
+ */
+ flush_work(&hcd->high_prio_bh.bh);
+ flush_work(&hcd->low_prio_bh.bh);
}
/**
@@ -3059,16 +3068,6 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_idr_lock);
- /*
- * flush_work() isn't needed here because:
- * - driver's disconnect() called from usb_disconnect() should
- * make sure its URBs are completed during the disconnect()
- * callback
- *
- * - it is too late to run complete() here since driver may have
- * been removed already now
- */
-
/* Prevent any more root-hub status calls from the timer.
* The HCD might still restart the timer (if a port status change
* interrupt occurs), but usb_hcd_poll_rh_status() won't invoke
--
2.47.3
prev parent reply other threads:[~2026-10-24 15:56 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 17:40 [PATCH] usb: core: hcd: cancel giveback work synchronously " Igor Putko
2026-10-23 19:15 ` Alan Stern
2026-10-23 19:31 ` IgorpetinDev
2026-10-24 1:53 ` Alan Stern
2026-10-24 8:36 ` [PATCH v2] usb: core: hcd: flush giveback work " Igor Putko
2026-10-24 15:56 ` Igor Putko [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261024155614.2732-1-igorpetindev@gmail.com \
--to=igorpetindev@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=oneukum@suse.com \
--cc=stable@vger.kernel.org \
--cc=stern@rowland.harvard.edu \
--cc=syzbot+a5b220cacb0618384d5a@syzkaller.appspotmail.com \
--cc=tj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®