mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
USB: gadget: dummy-hcd: Fix locking bug in RT-enabled kernels
commit8d63c83d8eupstream. Yunseong Kim and the syzbot fuzzer both reported a problem in RT-enabled kernels caused by the way dummy-hcd mixes interrupt management and spin-locking. The pattern was: local_irq_save(flags); spin_lock(&dum->lock); ... spin_unlock(&dum->lock); ... // calls usb_gadget_giveback_request() local_irq_restore(flags); The code was written this way because usb_gadget_giveback_request() needs to be called with interrupts disabled and the private lock not held. While this pattern works fine in non-RT kernels, it's not good when RT is enabled. RT kernels handle spinlocks much like mutexes; in particular, spin_lock() may sleep. But sleeping is not allowed while local interrupts are disabled. To fix the problem, rewrite the code to conform to the pattern used elsewhere in dummy-hcd and other UDC drivers: spin_lock_irqsave(&dum->lock, flags); ... spin_unlock(&dum->lock); usb_gadget_giveback_request(...); spin_lock(&dum->lock); ... spin_unlock_irqrestore(&dum->lock, flags); This approach satisfies the RT requirements. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@kernel.org> Fixes:b4dbda1a22("USB: dummy-hcd: disable interrupts during req->complete") Reported-by: Yunseong Kim <ysk@kzalloc.com> Closes: <https://lore.kernel.org/linux-usb/5b337389-73b9-4ee4-a83e-7e82bf5af87a@kzalloc.com/> Reported-by: syzbot+8baacc4139f12fa77909@syzkaller.appspotmail.com Closes: <https://lore.kernel.org/linux-usb/68ac2411.050a0220.37038e.0087.GAE@google.com/> Tested-by: syzbot+8baacc4139f12fa77909@syzkaller.appspotmail.com CC: Sebastian Andrzej Siewior <bigeasy@linutronix.de> CC: stable@vger.kernel.org Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Link: https://lore.kernel.org/r/bb192ae2-4eee-48ee-981f-3efdbbd0d8f0@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
e64b2ff864
commit
2d10b29a7e
@@ -764,8 +764,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
|||||||
if (!dum->driver)
|
if (!dum->driver)
|
||||||
return -ESHUTDOWN;
|
return -ESHUTDOWN;
|
||||||
|
|
||||||
local_irq_save(flags);
|
spin_lock_irqsave(&dum->lock, flags);
|
||||||
spin_lock(&dum->lock);
|
|
||||||
list_for_each_entry(iter, &ep->queue, queue) {
|
list_for_each_entry(iter, &ep->queue, queue) {
|
||||||
if (&iter->req != _req)
|
if (&iter->req != _req)
|
||||||
continue;
|
continue;
|
||||||
@@ -775,15 +774,16 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
|
|||||||
retval = 0;
|
retval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
spin_unlock(&dum->lock);
|
|
||||||
|
|
||||||
if (retval == 0) {
|
if (retval == 0) {
|
||||||
dev_dbg(udc_dev(dum),
|
dev_dbg(udc_dev(dum),
|
||||||
"dequeued req %p from %s, len %d buf %p\n",
|
"dequeued req %p from %s, len %d buf %p\n",
|
||||||
req, _ep->name, _req->length, _req->buf);
|
req, _ep->name, _req->length, _req->buf);
|
||||||
|
spin_unlock(&dum->lock);
|
||||||
usb_gadget_giveback_request(_ep, _req);
|
usb_gadget_giveback_request(_ep, _req);
|
||||||
|
spin_lock(&dum->lock);
|
||||||
}
|
}
|
||||||
local_irq_restore(flags);
|
spin_unlock_irqrestore(&dum->lock, flags);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user