FAILED: patch "[PATCH] usb: gadget: f_acm: Refactor bind path to use __free()" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 47b2116e54b4a854600341487e8b55249e926324
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025101616-unhappily-flatware-0bd2@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 47b2116e54b4a854600341487e8b55249e926324 Mon Sep 17 00:00:00 2001
From: Kuen-Han Tsai <[email protected]>
Date: Tue, 16 Sep 2025 16:21:35 +0800
Subject: [PATCH] usb: gadget: f_acm: Refactor bind path to use __free()
After an bind/unbind cycle, the acm->notify_req is left stale. If a subsequent bind fails, the unified error label attempts to free this stale request, leading to a NULL pointer dereference when accessing ep->ops->free_request.
Refactor the error handling in the bind path to use the __free() automatic cleanup mechanism.
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 Call trace: usb_ep_free_request+0x2c/0xec gs_free_req+0x30/0x44 acm_bind+0x1b8/0x1f4 usb_add_function+0xcc/0x1f0 configfs_composite_bind+0x468/0x588 gadget_bind_driver+0x104/0x270 really_probe+0x190/0x374 __driver_probe_device+0xa0/0x12c driver_probe_device+0x3c/0x218 __device_attach_driver+0x14c/0x188 bus_for_each_drv+0x10c/0x168 __device_attach+0xfc/0x198 device_initial_probe+0x14/0x24 bus_probe_device+0x94/0x11c device_add+0x268/0x48c usb_add_gadget+0x198/0x28c dwc3_gadget_init+0x700/0x858 __dwc3_set_mode+0x3cc/0x664 process_scheduled_works+0x1d8/0x488 worker_thread+0x244/0x334 kthread+0x114/0x1bc ret_from_fork+0x10/0x20
drivers/usb/gadget/function/f_acm.c +19 -23
@@ -11,12 +11,15 @@/* #define VERBOSE_DEBUG */ +#include <linux/cleanup.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/usb/gadget.h> +#include "u_serial.h"
@@ -613,6 +616,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)struct usb_string *us;int status;struct usb_ep *ep; + struct usb_request *request __free(free_usb_request) = NULL;/* REVISIT might want instance-specific strings to help * distinguish instances ...
@@ -630,7 +634,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)/* allocate instance-specific interface IDs, and patch descriptors */ status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; acm->ctrl_id = status; acm_iad_descriptor.bFirstInterface = status;
@@ -639,43 +643,41 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; acm->data_id = status; acm_data_interface_desc.bInterfaceNumber = status; acm_union_desc.bSlaveInterface0 = status; acm_call_mgmt_descriptor.bDataInterface = status; - status = -ENODEV ; -/* allocate instance-specific endpoints */ ep =usb_ep_autoconfig (cdev->gadget, &acm_fs_in_desc);if (!ep) - goto fail; +return -ENODEV ; acm->port.in = ep; ep =usb_ep_autoconfig (cdev->gadget, &acm_fs_out_desc);if (!ep) - goto fail; +return -ENODEV ; acm->port.out = ep; ep =usb_ep_autoconfig (cdev->gadget, &acm_fs_notify_desc);if (!ep) - goto fail; +return -ENODEV ; acm->notify = ep; acm_iad_descriptor.bFunctionProtocol = acm->bInterfaceProtocol; acm_control_interface_desc.bInterfaceProtocol = acm->bInterfaceProtocol;/* allocate notification */ - acm->notify_req =gs_alloc_req (ep, -sizeof (struct usb_cdc_notification ) +2 , -GFP_KERNEL ); -if (!acm->notify_req) - goto fail; + request =gs_alloc_req (ep, +sizeof (struct usb_cdc_notification ) +2 , +GFP_KERNEL ); +if (!request) +return -ENODEV ; - acm->notify_req->complete = acm_cdc_notify_complete; - acm->notify_req->context = acm; + request->complete = acm_cdc_notify_complete; + request->context = acm;/* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at
@@ -692,7 +694,9 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) status =usb_assign_descriptors (f, acm_fs_function, acm_hs_function, acm_ss_function, acm_ss_function);if (status) - goto fail; +return status; + + acm->notify_req =no_free_ptr (request); dev_dbg(&cdev->gadget->dev, "acm ttyGS%d: IN/%s OUT/%s NOTIFY/%s\n",
@@ -700,14 +704,6 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm->port.in->name, acm->port.out->name, acm->notify->name);return 0 ; - -fail: -if (acm->notify_req) -gs_free_req (acm->notify, acm->notify_req); - -ERROR (cdev,"%s/%p: can't bind, err %d\n" , f->name, f, status); - -return status; }static void acm_unbind (struct usb_configuration *c,struct usb_function *f)
Sasha Levin
maintainerPATCH 1/3 usb: gadget: Store endpoint pointer in usb_request
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit bfb1d99d969fe3b892db30848aeebfa19d21f57f ]
Gadget function drivers often have goto-based error handling in their bind paths, which can be bug-prone. Refactoring these paths to use __free() scope-based cleanup is desirable, but currently blocked.
The blocker is that usb_ep_free_request(ep, req) requires two parameters, while the __free() mechanism can only pass a pointer to the request itself.
Store an endpoint pointer in the struct usb_request. The pointer is populated centrally in usb_ep_alloc_request() on every successful allocation, making the request object self-contained.
Stable-dep-of: 47b2116e54b4 ("usb: gadget: f_acm: Refactor bind path to use __free()")
--- drivers/usb/gadget/udc/core.c | 3 +++ include/linux/usb/gadget.h | 2 ++ 2 files changed, 5 insertions(+)
drivers/usb/gadget/udc/core.c +3 -0
@@ -177,6 +177,9 @@ struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, req = ep->ops->alloc_request (ep, gfp_flags); +if (req) + req->ep = ep; +trace_usb_ep_alloc_request (ep, req, req ?0 : -ENOMEM );return req;
include/linux/usb/gadget.h +2 -0
@@ -33,6 +33,7 @@ struct usb_ep;/** * struct usb_request - describes one i/o request +* @ep: The associated endpoint set by usb_ep_alloc_request(). * @buf: Buffer used for data. Always provide this; some controllers * only use PIO, or don't use DMA for some endpoints. * @dma: DMA address corresponding to 'buf'. If you don't set this
@@ -98,6 +99,7 @@ struct usb_ep;*/ struct usb_request { +struct usb_ep *ep;void *buf;unsigned length;dma_addr_t dma;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/3 usb: gadget: Introduce free_usb_request helper
From: Kuen-Han Tsai <[email protected]>
[ Upstream commit 201c53c687f2b55a7cc6d9f4000af4797860174b ]
Introduce the free_usb_request() function that frees both the request's buffer and the request itself.
This function serves as the cleanup callback for DEFINE_FREE() to enable automatic, scope-based cleanup for usb_request pointers.
Stable-dep-of: 47b2116e54b4 ("usb: gadget: f_acm: Refactor bind path to use __free()")
--- include/linux/usb/gadget.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
include/linux/usb/gadget.h +23 -0
@@ -17,6 +17,7 @@#ifndef __LINUX_USB_GADGET_H#define __LINUX_USB_GADGET_H +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h>
@@ -292,6 +293,28 @@ static inline void usb_ep_fifo_flush(struct usb_ep *ep)/*-------------------------------------------------------------------------*/ +/** +* free_usb_request - frees a usb_request object and its buffer +* @req: the request being freed +* +* This helper function frees both the request's buffer and the request object +* itself by calling usb_ep_free_request(). Its signature is designed to be used +* with DEFINE_FREE() to enable automatic, scope-based cleanup for usb_request +* pointers. +*/ +static inline void free_usb_request (struct usb_request *req) +{ +if (!req) +return ; + +kfree (req->buf); +usb_ep_free_request (req->ep, req); +} + +DEFINE_FREE(free_usb_request, struct usb_request *, free_usb_request(_T)) + +/*-------------------------------------------------------------------------*/ +struct usb_dcd_config_params {__u8 bU1devExitLat;/* U1 Device exit Latency */ #define USB_DEFAULT_U1_DEV_EXIT_LAT 0x01/* Less then 1 microsec */
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 3/3 usb: gadget: f_acm: Refactor bind path to use __free()
In reply to Sasha LevinFrom: Kuen-Han Tsai <[email protected]>
[ Upstream commit 47b2116e54b4a854600341487e8b55249e926324 ]
After an bind/unbind cycle, the acm->notify_req is left stale. If a subsequent bind fails, the unified error label attempts to free this stale request, leading to a NULL pointer dereference when accessing ep->ops->free_request.
Refactor the error handling in the bind path to use the __free() automatic cleanup mechanism.
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 Call trace: usb_ep_free_request+0x2c/0xec gs_free_req+0x30/0x44 acm_bind+0x1b8/0x1f4 usb_add_function+0xcc/0x1f0 configfs_composite_bind+0x468/0x588 gadget_bind_driver+0x104/0x270 really_probe+0x190/0x374 __driver_probe_device+0xa0/0x12c driver_probe_device+0x3c/0x218 __device_attach_driver+0x14c/0x188 bus_for_each_drv+0x10c/0x168 __device_attach+0xfc/0x198 device_initial_probe+0x14/0x24 bus_probe_device+0x94/0x11c device_add+0x268/0x48c usb_add_gadget+0x198/0x28c dwc3_gadget_init+0x700/0x858 __dwc3_set_mode+0x3cc/0x664 process_scheduled_works+0x1d8/0x488 worker_thread+0x244/0x334 kthread+0x114/0x1bc ret_from_fork+0x10/0x20
--- drivers/usb/gadget/function/f_acm.c | 42 +++++++++++++---------------- 1 file changed, 19 insertions(+), 23 deletions(-)
drivers/usb/gadget/function/f_acm.c +19 -23
@@ -11,12 +11,15 @@/* #define VERBOSE_DEBUG */ +#include <linux/cleanup.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/usb/gadget.h> +#include "u_serial.h"
@@ -612,6 +615,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)struct usb_string *us;int status;struct usb_ep *ep; + struct usb_request *request __free(free_usb_request) = NULL;/* REVISIT might want instance-specific strings to help * distinguish instances ...
@@ -629,7 +633,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)/* allocate instance-specific interface IDs, and patch descriptors */ status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; acm->ctrl_id = status; acm_iad_descriptor.bFirstInterface = status;
@@ -638,40 +642,38 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; acm->data_id = status; acm_data_interface_desc.bInterfaceNumber = status; acm_union_desc.bSlaveInterface0 = status; acm_call_mgmt_descriptor.bDataInterface = status; - status = -ENODEV ; -/* allocate instance-specific endpoints */ ep =usb_ep_autoconfig (cdev->gadget, &acm_fs_in_desc);if (!ep) - goto fail; +return -ENODEV ; acm->port.in = ep; ep =usb_ep_autoconfig (cdev->gadget, &acm_fs_out_desc);if (!ep) - goto fail; +return -ENODEV ; acm->port.out = ep; ep =usb_ep_autoconfig (cdev->gadget, &acm_fs_notify_desc);if (!ep) - goto fail; +return -ENODEV ; acm->notify = ep;/* allocate notification */ - acm->notify_req =gs_alloc_req (ep, -sizeof (struct usb_cdc_notification ) +2 , -GFP_KERNEL ); -if (!acm->notify_req) - goto fail; + request =gs_alloc_req (ep, +sizeof (struct usb_cdc_notification ) +2 , +GFP_KERNEL ); +if (!request) +return -ENODEV ; - acm->notify_req->complete = acm_cdc_notify_complete; - acm->notify_req->context = acm; + request->complete = acm_cdc_notify_complete; + request->context = acm;/* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at
@@ -688,7 +690,9 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) status =usb_assign_descriptors (f, acm_fs_function, acm_hs_function, acm_ss_function, acm_ss_function);if (status) - goto fail; +return status; + + acm->notify_req =no_free_ptr (request); dev_dbg(&cdev->gadget->dev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
@@ -698,14 +702,6 @@ acm_bind(struct usb_configuration *c, struct usb_function *f) acm->port.in->name, acm->port.out->name, acm->notify->name);return 0 ; - -fail: -if (acm->notify_req) -gs_free_req (acm->notify, acm->notify_req); - -ERROR (cdev,"%s/%p: can't bind, err %d\n" , f->name, f, status); - -return status; }static void acm_unbind (struct usb_configuration *c,struct usb_function *f)
Signature · 1 line
2.51.0