All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.