[PATCH 17/19] usb: renesas_usbhs: unlink the URB if it is not queued

From: Greg Kroah-Hartman

Date: Tue Oct 27 2026 - 11:09:17 EST


From: Josef Bacik <josef@xxxxxxxxxxxxxx>

If usbhsh_urb_enqueue() fails after it has linked the URB to the
endpoint, it returns without unlinking it. usb_hcd_submit_urb() then
reinitializes urb->urb_list, and the owner may free the URB, while the
list of the endpoint still points to it. The next walk of that list, at
the latest when the endpoint is flushed, uses freed memory or does not
end.

No memory shortage is needed for that: each isochronous URB is refused
with -EIO, after it has been linked.

If the failure comes after the pipe was attached, that is not undone
either, and the use count of the pipe never gets back to zero.

Fixes: 034d7c13a79c ("usb: gadget: renesas_usbhs: add mod_host support")
Cc: stable <stable@xxxxxxxxxx>
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/usb/renesas_usbhs/mod_host.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 0652525d06fe..bdec4eaf3402 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -987,7 +987,7 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
if (!new_udev) {
ret = -EIO;
dev_err(dev, "device attach failed\n");
- goto usbhsh_urb_enqueue_error_not_linked;
+ goto usbhsh_urb_enqueue_error_unlink;
}
}

@@ -1020,14 +1020,22 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags);
else
ret = usbhsh_queue_push(hcd, urb, mem_flags);
+ if (ret < 0) {
+ usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(ep));
+ goto usbhsh_urb_enqueue_error_unlink;
+ }

- return ret;
+ return 0;

usbhsh_urb_enqueue_error_free_endpoint:
usbhsh_endpoint_detach(hpriv, ep);
usbhsh_urb_enqueue_error_free_device:
if (new_udev)
usbhsh_device_detach(hpriv, new_udev);
+usbhsh_urb_enqueue_error_unlink:
+ usbhs_lock(priv, flags);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ usbhs_unlock(priv, flags);
usbhsh_urb_enqueue_error_not_linked:

dev_dbg(dev, "%s error\n", __func__);

--
2.56.0