Linux USB
 help / color / mirror / Atom feed
* [PATCH] usb: cdns2: fix use-after-free in cdns2_gadget_giveback
@ 2026-01-14 20:32 齐柯宇
  2026-01-15  6:35 ` Greg KH
  2026-01-15  6:36 ` Greg KH
  0 siblings, 2 replies; 3+ messages in thread
From: 齐柯宇 @ 2026-01-14 20:32 UTC (permalink / raw)
  To: pawell, gregkh; +Cc: linux-usb, linux-kernel

This fix addresses a use-after-free vulnerability discovered through
static code analysis of the cdns2_gadget_giveback() function.

The vulnerability exists because after usb_gadget_giveback_request()
is called, the code continues to access request->buf. However,
usb_gadget_giveback_request() invokes the request's complete callback,
and certain gadget function drivers (such as FunctionFS with DMABUF)
may directly free the request within this callback.

Call flow leading to use-after-free:

  cdns2_gadget_giveback()
    -> usb_gadget_giveback_request()
       -> request->complete()  [e.g., ffs_epfile_dmabuf_io_complete]
          -> usb_ep_free_request()  // request is freed here
    -> if (request->buf == pdev->zlp_buf)  // UAF: accessing freed memory
       -> cdns2_gadget_ep_free_request()   // potential double-free

Data flow analysis shows that this vulnerability can be triggered when:
1. A user application uses FunctionFS with DMABUF transfer capability
2. The user attaches a DMABUF via FUNCTIONFS_DMABUF_ATTACH ioctl
3. The user initiates a transfer via FUNCTIONFS_DMABUF_TRANSFER ioctl
4. Upon transfer completion, ffs_epfile_dmabuf_io_complete() is called
   as the complete callback, which frees the request
5. cdns2_gadget_giveback() then accesses the freed request->buf field

Evidence that complete callback can free the request (f_fs.c):

  static void ffs_epfile_dmabuf_io_complete(struct usb_ep *ep,
                                            struct usb_request *req)
  {
      ffs_dmabuf_signal_done(req->context, req->status);
      usb_ep_free_request(ep, req);  // frees the request directly
  }

The fix saves the ZLP check result before calling the complete callback
and uses mutually exclusive logic: requests with complete callbacks are
owned by the gadget function driver, while only ZLP requests without
complete callbacks are freed by the UDC driver.

Fixes: 3eb1f1efe204 ("usb: cdns2: Add main part of Cadence USBHS driver")
Signed-off-by: Kery Qi <qikeyu2017@gmail.com>
---
 drivers/usb/gadget/udc/cdns2/cdns2-gadget.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c
b/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c
index 9b53daf76583..8997623cca5a 100644
--- a/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c
+++ b/drivers/usb/gadget/udc/cdns2/cdns2-gadget.c
@@ -240,6 +240,7 @@ void cdns2_gadget_giveback(struct cdns2_endpoint *pep,
 {
   struct usb_request *request = &preq->request;
   struct cdns2_device *pdev = pep->pdev;
+  bool is_zlp = (request->buf == pdev->zlp_buf);

   list_del_init(&preq->list);

@@ -257,10 +258,14 @@ void cdns2_gadget_giveback(struct cdns2_endpoint *pep,
      spin_unlock(&pdev->lock);
      usb_gadget_giveback_request(&pep->endpoint, request);
      spin_lock(&pdev->lock);
-  }
-
-  if (request->buf == pdev->zlp_buf)
+  } else if (is_zlp) {
+     /*
+      * Only ZLP requests without a complete callback are freed
+      * by the driver. Requests with complete callbacks are
+      * owned by the gadget function driver.
+      */
      cdns2_gadget_ep_free_request(&pep->endpoint, request);
+  }
 }

 static void cdns2_wa1_restore_cycle_bit(struct cdns2_endpoint *pep)
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-01-15  6:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-14 20:32 [PATCH] usb: cdns2: fix use-after-free in cdns2_gadget_giveback 齐柯宇
2026-01-15  6:35 ` Greg KH
2026-01-15  6:36 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox