Skip to content

Commit dfe634b

Browse files
AlanSterngregkh
authored andcommitted
USB: gadget: dummy-hcd: Fix locking bug in RT-enabled kernels
commit 8d63c83 upstream. 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: b4dbda1 ("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>
1 parent 4a19dac commit dfe634b

File tree

1 file changed

+4
-4
lines changed

1 file changed

+4
-4
lines changed

drivers/usb/gadget/udc/dummy_hcd.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -764,8 +764,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
764764
if (!dum->driver)
765765
return -ESHUTDOWN;
766766

767-
local_irq_save(flags);
768-
spin_lock(&dum->lock);
767+
spin_lock_irqsave(&dum->lock, flags);
769768
list_for_each_entry(iter, &ep->queue, queue) {
770769
if (&iter->req != _req)
771770
continue;
@@ -775,15 +774,16 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
775774
retval = 0;
776775
break;
777776
}
778-
spin_unlock(&dum->lock);
779777

780778
if (retval == 0) {
781779
dev_dbg(udc_dev(dum),
782780
"dequeued req %p from %s, len %d buf %p\n",
783781
req, _ep->name, _req->length, _req->buf);
782+
spin_unlock(&dum->lock);
784783
usb_gadget_giveback_request(_ep, _req);
784+
spin_lock(&dum->lock);
785785
}
786-
local_irq_restore(flags);
786+
spin_unlock_irqrestore(&dum->lock, flags);
787787
return retval;
788788
}
789789

0 commit comments

Comments
 (0)