patch "USB: Gadget: core: Help prevent panic during UVC unconfigure" added to usb-linus
Subsystems (2)
This is a note to let you know that I've just added the patch titled
USB: Gadget: core: Help prevent panic during UVC unconfigure
to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-linus branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will hopefully also be merged in Linus's tree for the next -rc kernel release.
If you have any questions about this process, please let me know.
From 65dadb2beeb7360232b09ebc4585b54475dfee06 Mon Sep 17 00:00:00 2001
From: Alan Stern <[email protected]>
Date: Sat, 29 Jul 2023 10:59:38 -0400
Subject: USB: Gadget: core: Help prevent panic during UVC unconfigure
Avichal Rakesh reported a kernel panic that occurred when the UVC gadget driver was removed from a gadget's configuration. The panic involves a somewhat complicated interaction between the kernel driver and a userspace component (as described in the Link tag below), but the analysis did make one thing clear: The Gadget core should accomodate gadget drivers calling usb_gadget_deactivate() as part of their unbind procedure.
Currently this doesn't work. gadget_unbind_driver() calls driver->unbind() while holding the udc->connect_lock mutex, and usb_gadget_deactivate() attempts to acquire that mutex, which will result in a deadlock.
The simple fix is for gadget_unbind_driver() to release the mutex when invoking the ->unbind() callback. There is no particular reason for it to be holding the mutex at that time, and the mutex isn't held while the ->bind() callback is invoked. So we'll drop the mutex before performing the unbind callback and reacquire it afterward.
We'll also add a couple of comments to usb_gadget_activate() and usb_gadget_deactivate(). Because they run in process context they must not be called from a gadget driver's ->disconnect() callback, which (according to the kerneldoc for struct usb_gadget_driver in include/linux/usb/gadget.h) may run in interrupt context. This may help prevent similar bugs from arising in the future.
--- drivers/usb/gadget/udc/core.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/usb/gadget/udc/core.c +9 -0
@@ -822,6 +822,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_disconnect);* usb_gadget_activate() is called. For example, user mode components may * need to be activated before the system can talk to hosts. * +* This routine may sleep; it must not be called in interrupt context +* (such as from within a gadget driver's disconnect() callback). +* * Returns zero on success, else negative errno. */ int usb_gadget_deactivate (struct usb_gadget *gadget)
@@ -860,6 +863,8 @@ EXPORT_SYMBOL_GPL(usb_gadget_deactivate);* This routine activates gadget which was previously deactivated with * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed. * +* This routine may sleep; it must not be called in interrupt context. +* * Returns zero on success, else negative errno. */ int usb_gadget_activate (struct usb_gadget *gadget)
@@ -1638,7 +1643,11 @@ static void gadget_unbind_driver(struct device *dev)usb_gadget_disable_async_callbacks (udc);if (gadget->irq)synchronize_irq (gadget->irq); +mutex_unlock (&udc->connect_lock); + udc->driver->unbind (gadget); + +mutex_lock (&udc->connect_lock);usb_gadget_udc_stop_locked (udc);mutex_unlock (&udc->connect_lock);
Signature · 1 line
2.41.0