Skip to content

Commit f50200d

Browse files
surbangregkh
authored andcommitted
usb: gadget: dummy_hcd: fix premature URB completion when ZLP follows partial transfer
When a gadget request is only partially transferred in transfer() because the per-frame bandwidth budget is exhausted, the loop advances to the next queued request. If that next request is a zero-length packet (ZLP), len evaluates to zero and the code takes the unlikely(len == 0) path, which sets is_short = 1. This bypasses the bandwidth guard ("limit < ep->ep.maxpacket && limit < len") that lives in the else branch and would otherwise break out of the loop for non-zero requests. The is_short path then completes the URB before all data from the first request has been transferred. Reproducer (bulk IN, high speed): Device side (FunctionFS with Linux AIO): 1. Queue a 65024-byte write via io_submit (127 * 512, i.e. a multiple of the HS bulk max packet size). 2. Immediately queue a zero-length write (ZLP) via io_submit. Host side: 3. Submit a 65536-byte bulk IN URB. Expected: URB completes with actual_length = 65024. Actual: URB completes with actual_length = 53248, losing 11776 bytes that leak into subsequent URBs. At high speed the per-frame budget is 53248 bytes (512 * 13 * 8). The 65024-byte request exhausts this budget after 53248 bytes, leaving the request incomplete (req->req.actual < req->req.length). Neither the request nor the URB is finished, and rescan is 0, so the loop advances to the ZLP. For the ZLP, dev_len = 0, so len = min(12288, 0) = 0, taking the unlikely(len == 0) path and setting is_short = 1. The is_short handler then sets *status = 0, completing the URB with only 53248 of the expected 65024 bytes. Fix this by breaking out of the loop when the current request has remaining data (req->req.actual < req->req.length). The request resumes on the next timer tick, preserving correct data ordering. Signed-off-by: Sebastian Urban <surban@surban.net> Cc: stable <stable@kernel.org> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Link: https://patch.msgid.link/20260315151045.1155850-1-surban@surban.net Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1a12219 commit f50200d

1 file changed

Lines changed: 6 additions & 0 deletions

File tree

drivers/usb/gadget/udc/dummy_hcd.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,12 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
15381538
/* rescan to continue with any other queued i/o */
15391539
if (rescan)
15401540
goto top;
1541+
1542+
/* request not fully transferred; stop iterating to
1543+
* preserve data ordering across queued requests.
1544+
*/
1545+
if (req->req.actual < req->req.length)
1546+
break;
15411547
}
15421548
return sent;
15431549
}

0 commit comments

Comments
 (0)