Skip to content

Commit d1a0787

Browse files
AlanSterngregkh
authored andcommitted
USB: dummy-hcd: fix infinite-loop resubmission bug
commit 0173a68bfb0ad1c72a6ee39cc485aa2c97540b98 upstream. The dummy-hcd HCD/UDC emulator tries not to do too much work during each timer interrupt. But it doesn't try very hard; currently all it does is limit the total amount of bulk data transferred. Other transfer types aren't limited, and URBs that transfer no data (because of an error, perhaps) don't count toward the limit, even though on a real USB bus they would consume at least a minimum overhead. This means it's possible to get the driver stuck in an infinite loop, for example, if the host class driver resubmits an URB every time it completes (which is common for interrupt URBs). Each time the URB is resubmitted it gets added to the end of the pending-URBs list, and dummy-hcd doesn't stop until that list is empty. Andrey Konovalov was able to trigger this failure mode using the syzkaller fuzzer. This patch fixes the infinite-loop problem by restricting the URBs handled during each timer interrupt to those that were already on the pending list when the interrupt routine started. Newly added URBs won't be processed until the next timer interrupt. The problem of properly accounting for non-bulk bandwidth (as well as packet and transaction overhead) is not addressed here. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Andrey Konovalov <andreyknvl@google.com> Tested-by: Andrey Konovalov <andreyknvl@google.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d25a65e commit d1a0787

1 file changed

Lines changed: 9 additions & 0 deletions

File tree

drivers/usb/gadget/udc/dummy_hcd.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ struct dummy_hcd {
237237

238238
struct usb_device *udev;
239239
struct list_head urbp_list;
240+
struct urbp *next_frame_urbp;
241+
240242
u32 stream_en_ep;
241243
u8 num_stream[30 / 2];
242244

@@ -1246,6 +1248,8 @@ static int dummy_urb_enqueue(
12461248

12471249
list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
12481250
urb->hcpriv = urbp;
1251+
if (!dum_hcd->next_frame_urbp)
1252+
dum_hcd->next_frame_urbp = urbp;
12491253
if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
12501254
urb->error_count = 1; /* mark as a new urb */
12511255

@@ -1763,6 +1767,7 @@ static void dummy_timer(unsigned long _dum_hcd)
17631767
spin_unlock_irqrestore(&dum->lock, flags);
17641768
return;
17651769
}
1770+
dum_hcd->next_frame_urbp = NULL;
17661771

17671772
for (i = 0; i < DUMMY_ENDPOINTS; i++) {
17681773
if (!ep_info[i].name)
@@ -1779,6 +1784,10 @@ static void dummy_timer(unsigned long _dum_hcd)
17791784
int type;
17801785
int status = -EINPROGRESS;
17811786

1787+
/* stop when we reach URBs queued after the timer interrupt */
1788+
if (urbp == dum_hcd->next_frame_urbp)
1789+
break;
1790+
17821791
urb = urbp->urb;
17831792
if (urb->unlinked)
17841793
goto return_urb;

0 commit comments

Comments
 (0)