printer_soft_reset() has three loops that drain different lists back to rx_reqs / tx_reqs. The second loop's condition tests rx_reqs_active but its body was copy-pasted from the first loop and still reads from rx_buffers: while (!list_empty(&dev->rx_reqs_active)) { req = container_of(dev->rx_buffers.next, ...); /* BUG */ The first loop already empties rx_buffers, so by the time the second loop runs, dev->rx_buffers.next points back to the list head itself. Consequently: - list_del_init() treats the list head as an entry and poisons it - list_add() splices the rx_buffers head into rx_reqs - rx_reqs_active is never drained, so the loop condition stays true indefinitely This results in linked-list corruption and a hang that is trivially triggered by a USB host sending a SOFT_RESET class request. Fix by reading from rx_reqs_active.next, matching the loop condition. Fixes: 856c5e59aa0d ("usb: gadget: f_printer: copy Data Interface instead of using a singleton") Cc: stable@vger.kernel.org Reviewed-by: Weibin Liu Signed-off-by: Liu Chao --- drivers/usb/gadget/function/f_printer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 1857d7861..2305733fe 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -940,7 +940,7 @@ static void printer_soft_reset(struct printer_dev *dev) } while (likely(!(list_empty(&dev->rx_reqs_active)))) { - req = container_of(dev->rx_buffers.next, struct usb_request, + req = container_of(dev->rx_reqs_active.next, struct usb_request, list); list_del_init(&req->list); list_add(&req->list, &dev->rx_reqs); -- 2.50.1