In the Linux kernel, the following vulnerability has been resolved:
usb: musb: Fix hardware lockup on first Rx endpoint request
There is a possibility that a request's callback could be invoked from usbepqueue() (call trace below, supplemented with missing calls):
req->complete from usbgadgetgivebackrequest (drivers/usb/gadget/udc/core.c:999) usbgadgetgivebackrequest from musbggiveback (drivers/usb/musb/musbgadget.c:147) musbggiveback from rxstate (drivers/usb/musb/musbgadget.c:784) rxstate from musbeprestart (drivers/usb/musb/musbgadget.c:1169) musbeprestart from musbeprestartresumework (drivers/usb/musb/musbgadget.c:1176) musbeprestartresumework from musbqueueresumework (drivers/usb/musb/musbcore.c:2279) musbqueueresumework from musbgadgetqueue (drivers/usb/musb/musbgadget.c:1241) musbgadgetqueue from usbepqueue (drivers/usb/gadget/udc/core.c:300)
According to the docstring of usbepqueue(), this should not happen:
"Note that @req's ->complete() callback must never be called from within usbepqueue() as that can create deadlock situations."
In fact, a hardware lockup might occur in the following sequence:
For this scenario to occur, it is only necessary for IRQs to be enabled at some point during the complete callback. This happens with the USB Ethernet gadget, whose rxcomplete() callback calls netifrx(). If called in the task context, netifrx() disables the bottom halves (BHs). When the BHs are re-enabled, IRQs are also enabled to allow soft IRQs to be processed. The gadget itself is initialized at module load (or at boot if built-in), but the first request is enqueued when the network interface is brought up, triggering rxcomplete() in the task context via ioctl(). If a packet arrives while the interface is down, it can prevent the interface from receiving any further packets from the USB host.
The situation is quite complicated with many parties involved. This particular issue can be resolved in several possible ways: