Linux USB
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Faisal Hassan" <faisal.hassan@oss.qualcomm.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH v2] usb: dwc3: gadget: linearize SG requests that exceed the TRB cache
Date: Tue, 06 Oct 2026 17:41:36 +0000	[thread overview]
Message-ID: <sashiko-outbox-162302@kernel.org> (raw)
In-Reply-To: <20261006172254.1058992-1-faisal.hassan@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] usb: dwc3: UAF and memory leak on ISOC transfer start failure
- [High] usb: dwc3: gadget: DMA mapping leak for requests without TRBs
- [High] usb: dwc3: Double DMA mapping leak in dwc3_prepare_trbs() on TRB exhaustion
--

commit 4e03749f5dcd711bf2541cb720afd9cd91d48fb2
Author: Faisal Hassan <faisal.hassan@oss.qualcomm.com>

usb: dwc3: gadget: linearize SG requests that exceed the TRB cache

The controller prefetches the TRBs of a transfer into an internal cache
that holds DWC_USB3_CACHE_TRBS_PER_TRANSFER entries. Databook 4.2.3.3
requires that the number of chained TRBs needed to construct a single
packet never exceeds (DWC_USB3_CACHE_TRBS_PER_TRANSFER - 1). This patch
walks the scatter-gather list and linearizes requests when a packet
would exceed the budget.

Link: https://lore.kernel.org/all/20261004031445.1450196-1-faisal.hassan@oss.qualcomm.com/

> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
> index f245e66cd13d0..7417d3c32dbf2 100644
> --- a/drivers/usb/dwc3/gadget.c
> +++ b/drivers/usb/dwc3/gadget.c
[ ... ]
> @@ -202,10 +218,16 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
>  	if (req->request.status == -EINPROGRESS)
>  		req->request.status = status;
>  
> -	if (req->trb)
> +	/*
> +	 * A linearized request may have been mapped without getting a TRB, so
> +	 * unmap it before its buffer is freed.
> +	 */
> +	if (req->trb || req->sg_trb_cache_bounced)
>  		usb_gadget_unmap_request_by_dev(dwc->sysdev,
>  				&req->request, req->direction);
>  

[Severity: High]
This condition incorrectly relies on req->trb to determine if a non-bounced
request was mapped. Will this bypass unmapping for requests that were
mapped but failed to acquire a TRB?

In dwc3_prepare_trbs(), requests in the pending_list are unconditionally
mapped prior to TRB allocation:

drivers/usb/dwc3/gadget.c:dwc3_prepare_trbs() {
	...
	list_for_each_entry_safe(req, n, &dep->pending_list, list) {
		ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request,
						    dep->direction);
		if (ret)
			return ret;
		...
		if (!ret || !dwc3_calc_trbs_left(dep))
			return ret;
}

If dwc3_calc_trbs_left() indicates insufficient TRBs, the function returns
early. The mapped request remains on pending_list with req->trb == NULL.

If the request is dequeued (canceled) in this state, it bypasses the unmapping
logic here, leaking the mapping.

Furthermore, every time a single TRB completes, dwc3_prepare_trbs() is
triggered again. It iterates over the same request on pending_list and
maps it again, overwriting the req->dma pointer and leaking the previous
mapping, because usb_gadget_map_request_by_dev() lacks checks for
preexisting mappings (like req->dma_mapped).

[ ... ]
> @@ -1985,6 +2111,7 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
>  static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
>  {
>  	struct dwc3		*dwc = dep->dwc;
> +	int			ret;
>  
>  	if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) {
>  		dev_dbg(dwc->dev, "%s: can't queue to disabled endpoint\n",
> @@ -2001,6 +2128,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
>  				dep->name, &req->request))
>  		return -EINVAL;
>  
> +	ret = dwc3_gadget_linearize_sg_request(dep, req);
> +	if (ret)
> +		return ret;
> +
>  	pm_runtime_get(dwc->dev);
>  
>  	req->request.actual	= 0;
>  	req->request.status	= -EINPROGRESS;
>  
>  	trace_dwc3_ep_queue(req);
>  
>  	list_add_tail(&req->list, &dep->pending_list);
>  	req->status = DWC3_REQUEST_STATUS_QUEUED;
>  
>  	if (dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE)
>  		return 0;
>  
>  	/*
>  	 * Start the transfer only after the END_TRANSFER is completed
>  	 * and endpoint STALL is cleared.
>  	 */
>  	if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
>  	    (dep->flags & DWC3_EP_WEDGE) ||
>  	    (dep->flags & DWC3_EP_DELAY_STOP) ||
>  	    (dep->flags & DWC3_EP_STALL)) {
>  		dep->flags |= DWC3_EP_DELAY_START;
>  		return 0;
>  	}
>  
>  	/*
>  	 * NOTICE: Isochronous endpoints should NEVER be prestarted. We must
>  	 * wait for a XferNotReady event so we will know what's the current
>  	 * (micro-)frame number.
>  	 *
>  	 * Without this trick, we are very, very likely gonna get Bus Expiry
>  	 * errors which will force us issue EndTransfer command.
>  	 */
>  	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
>  		if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) {
>  			if ((dep->flags & DWC3_EP_PENDING_REQUEST))
>  				return __dwc3_gadget_start_isoc(dep);

[Severity: High]
If __dwc3_gadget_start_isoc() fails here (for example, if
usb_gadget_map_request_by_dev() fails in dwc3_prepare_trbs()), the error code
is returned directly from __dwc3_gadget_ep_queue().

Since the request was already appended to dep->pending_list, the error
propagates back to the gadget driver, which assumes the request was not queued
and frees it. Will this lead to a Use-After-Free list corruption the next time
DWC3 processes pending_list?

Additionally, does this leak the newly allocated sg_trb_cache_buf bounce buffer
and the PM usage count because dwc3_gadget_restore_sg_trb_cache_buf() and
pm_runtime_put() are skipped when returning the error directly?

>  
>  			return 0;
>  		}
>  	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261006172254.1058992-1-faisal.hassan@oss.qualcomm.com?part=1

      reply	other threads:[~2026-10-06 17:41 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-04  3:14 [PATCH] usb: dwc3: gadget: linearize SG requests that exceed the TRB cache Faisal Hassan
2026-10-06 17:22 ` [PATCH v2] " Faisal Hassan
2026-10-06 17:41   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-162302@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=faisal.hassan@oss.qualcomm.com \
    --cc=linux-usb@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox