FAILED: patch "[PATCH] usb: gadget: f_rndis: Refactor bind path to use __free()" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.12-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-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 08228941436047bdcd35a612c1aec0912a29d8cd
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025101631-macaroni-reabsorb-72e7@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 08228941436047bdcd35a612c1aec0912a29d8cd Mon Sep 17 00:00:00 2001
From: Kuen-Han Tsai <[email protected]>
Date: Tue, 16 Sep 2025 16:21:37 +0800
Subject: [PATCH] usb: gadget: f_rndis: Refactor bind path to use __free()
After an bind/unbind cycle, the rndis->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.
drivers/usb/gadget/function/f_rndis.c +35 -50
@@ -19,6 +19,8 @@#include <linux/atomic.h> +#include <linux/usb/gadget.h> +#include "u_ether.h" #include "u_ether_configfs.h" #include "u_rndis.h"
@@ -662,6 +664,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)struct usb_ep *ep;struct f_rndis_opts *rndis_opts; + struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_rndis (c))return -EINVAL ;
@@ -669,12 +673,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);if (cdev->use_os_string) { - f->os_desc_table =kzalloc (sizeof (*f->os_desc_table), -GFP_KERNEL ); -if (!f->os_desc_table) + os_desc_table =kzalloc (sizeof (*os_desc_table),GFP_KERNEL ); +if (!os_desc_table)return -ENOMEM ; - f->os_desc_n =1 ; - f->os_desc_table[0 ].os_desc = &rndis_opts->rndis_os_desc; } rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
@@ -692,16 +693,14 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)gether_set_gadget (rndis_opts->net, cdev->gadget); status =gether_register_netdev (rndis_opts->net);if (status) - goto fail; +return status; rndis_opts->bound = true; } us =usb_gstrings_attach (cdev, rndis_strings,ARRAY_SIZE (rndis_string_defs)); -if (IS_ERR (us)) { - status =PTR_ERR (us); - goto fail; - } +if (IS_ERR (us)) +return PTR_ERR (us); rndis_control_intf.iInterface = us[0 ].id; rndis_data_intf.iInterface = us[1 ].id; rndis_iad_descriptor.iFunction = us[2 ].id;
@@ -709,36 +708,30 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)/* allocate instance-specific interface IDs */ status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; rndis->ctrl_id = status; rndis_iad_descriptor.bFirstInterface = status; rndis_control_intf.bInterfaceNumber = status; rndis_union_desc.bMasterInterface0 = status; -if (cdev->use_os_string) - f->os_desc_table[0 ].if_id = - rndis_iad_descriptor.bFirstInterface; - status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; rndis->data_id = status; rndis_data_intf.bInterfaceNumber = status; rndis_union_desc.bSlaveInterface0 = status; - status = -ENODEV ; -/* allocate instance-specific endpoints */ ep =usb_ep_autoconfig (cdev->gadget, &fs_in_desc);if (!ep) - goto fail; +return -ENODEV ; rndis->port.in_ep = ep; ep =usb_ep_autoconfig (cdev->gadget, &fs_out_desc);if (!ep) - goto fail; +return -ENODEV ; rndis->port.out_ep = ep;/* NOTE: a status/notification endpoint is, strictly speaking,
@@ -747,21 +740,19 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)*/ ep =usb_ep_autoconfig (cdev->gadget, &fs_notify_desc);if (!ep) - goto fail; +return -ENODEV ; rndis->notify = ep; - status = -ENOMEM ; -/* allocate notification request and buffer */ - rndis->notify_req =usb_ep_alloc_request (ep,GFP_KERNEL ); -if (!rndis->notify_req) - goto fail; - rndis->notify_req->buf =kmalloc (STATUS_BYTECOUNT ,GFP_KERNEL ); -if (!rndis->notify_req->buf) - goto fail; - rndis->notify_req->length =STATUS_BYTECOUNT ; - rndis->notify_req->context = rndis; - rndis->notify_req->complete = rndis_response_complete; + request =usb_ep_alloc_request (ep,GFP_KERNEL ); +if (!request) +return -ENOMEM ; + request->buf =kmalloc (STATUS_BYTECOUNT ,GFP_KERNEL ); +if (!request->buf) +return -ENOMEM ; + request->length =STATUS_BYTECOUNT ; + request->context = rndis; + request->complete = rndis_response_complete;/* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at
@@ -778,7 +769,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) status =usb_assign_descriptors (f, eth_fs_function, eth_hs_function, eth_ss_function, eth_ss_function);if (status) - goto fail; +return status; rndis->port.open = rndis_open; rndis->port.close = rndis_close;
@@ -789,10 +780,19 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)if (rndis->manufacturer && rndis->vendorID &&rndis_set_param_vendor (rndis->params, rndis->vendorID, rndis->manufacturer)) { - status = -EINVAL ; - goto fail_free_descs; +usb_free_all_descriptors (f); +return -EINVAL ; } +if (cdev->use_os_string) { + os_desc_table[0 ].os_desc = &rndis_opts->rndis_os_desc; + os_desc_table[0 ].if_id = rndis_iad_descriptor.bFirstInterface; + f->os_desc_table =no_free_ptr (os_desc_table); + f->os_desc_n =1 ; + + } + rndis->notify_req =no_free_ptr (request); +/* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt().
@@ -802,21 +802,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis->port.in_ep->name, rndis->port.out_ep->name, rndis->notify->name);return 0 ; - -fail_free_descs: -usb_free_all_descriptors (f); -fail: -kfree (f->os_desc_table); - f->os_desc_n =0 ; - -if (rndis->notify_req) { -kfree (rndis->notify_req->buf); -usb_ep_free_request (rndis->notify, rndis->notify_req); - } - -ERROR (cdev,"%s: can't bind, err %d\n" , f->name, status); - -return status; }void rndis_borrow_net (struct usb_function_instance *f,struct net_device *net)
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: 082289414360 ("usb: gadget: f_rndis: 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
@@ -194,6 +194,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
@@ -32,6 +32,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: 082289414360 ("usb: gadget: f_rndis: Refactor bind path to use __free()")
--- include/linux/usb/gadget.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
include/linux/usb/gadget.h +23 -0
@@ -15,6 +15,7 @@#ifndef __LINUX_USB_GADGET_H#define __LINUX_USB_GADGET_H +#include <linux/cleanup.h> #include <linux/configfs.h> #include <linux/device.h> #include <linux/errno.h>
@@ -293,6 +294,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_rndis: Refactor bind path to use __free()
In reply to Sasha LevinFrom: Kuen-Han Tsai <[email protected]>
[ Upstream commit 08228941436047bdcd35a612c1aec0912a29d8cd ]
After an bind/unbind cycle, the rndis->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.
--- drivers/usb/gadget/function/f_rndis.c | 85 +++++++++++---------------- 1 file changed, 35 insertions(+), 50 deletions(-)
drivers/usb/gadget/function/f_rndis.c +35 -50
@@ -19,6 +19,8 @@#include <linux/atomic.h> +#include <linux/usb/gadget.h> +#include "u_ether.h" #include "u_ether_configfs.h" #include "u_rndis.h"
@@ -662,6 +664,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)struct usb_ep *ep;struct f_rndis_opts *rndis_opts; + struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct usb_request *request __free(free_usb_request) = NULL;if (!can_support_rndis (c))return -EINVAL ;
@@ -669,12 +673,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst);if (cdev->use_os_string) { - f->os_desc_table =kzalloc (sizeof (*f->os_desc_table), -GFP_KERNEL ); -if (!f->os_desc_table) + os_desc_table =kzalloc (sizeof (*os_desc_table),GFP_KERNEL ); +if (!os_desc_table)return -ENOMEM ; - f->os_desc_n =1 ; - f->os_desc_table[0 ].os_desc = &rndis_opts->rndis_os_desc; } rndis_iad_descriptor.bFunctionClass = rndis_opts->class;
@@ -692,16 +693,14 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)gether_set_gadget (rndis_opts->net, cdev->gadget); status =gether_register_netdev (rndis_opts->net);if (status) - goto fail; +return status; rndis_opts->bound = true; } us =usb_gstrings_attach (cdev, rndis_strings,ARRAY_SIZE (rndis_string_defs)); -if (IS_ERR (us)) { - status =PTR_ERR (us); - goto fail; - } +if (IS_ERR (us)) +return PTR_ERR (us); rndis_control_intf.iInterface = us[0 ].id; rndis_data_intf.iInterface = us[1 ].id; rndis_iad_descriptor.iFunction = us[2 ].id;
@@ -709,36 +708,30 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)/* allocate instance-specific interface IDs */ status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; rndis->ctrl_id = status; rndis_iad_descriptor.bFirstInterface = status; rndis_control_intf.bInterfaceNumber = status; rndis_union_desc.bMasterInterface0 = status; -if (cdev->use_os_string) - f->os_desc_table[0 ].if_id = - rndis_iad_descriptor.bFirstInterface; - status =usb_interface_id (c, f);if (status <0 ) - goto fail; +return status; rndis->data_id = status; rndis_data_intf.bInterfaceNumber = status; rndis_union_desc.bSlaveInterface0 = status; - status = -ENODEV ; -/* allocate instance-specific endpoints */ ep =usb_ep_autoconfig (cdev->gadget, &fs_in_desc);if (!ep) - goto fail; +return -ENODEV ; rndis->port.in_ep = ep; ep =usb_ep_autoconfig (cdev->gadget, &fs_out_desc);if (!ep) - goto fail; +return -ENODEV ; rndis->port.out_ep = ep;/* NOTE: a status/notification endpoint is, strictly speaking,
@@ -747,21 +740,19 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)*/ ep =usb_ep_autoconfig (cdev->gadget, &fs_notify_desc);if (!ep) - goto fail; +return -ENODEV ; rndis->notify = ep; - status = -ENOMEM ; -/* allocate notification request and buffer */ - rndis->notify_req =usb_ep_alloc_request (ep,GFP_KERNEL ); -if (!rndis->notify_req) - goto fail; - rndis->notify_req->buf =kmalloc (STATUS_BYTECOUNT ,GFP_KERNEL ); -if (!rndis->notify_req->buf) - goto fail; - rndis->notify_req->length =STATUS_BYTECOUNT ; - rndis->notify_req->context = rndis; - rndis->notify_req->complete = rndis_response_complete; + request =usb_ep_alloc_request (ep,GFP_KERNEL ); +if (!request) +return -ENOMEM ; + request->buf =kmalloc (STATUS_BYTECOUNT ,GFP_KERNEL ); +if (!request->buf) +return -ENOMEM ; + request->length =STATUS_BYTECOUNT ; + request->context = rndis; + request->complete = rndis_response_complete;/* support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at
@@ -778,7 +769,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) status =usb_assign_descriptors (f, eth_fs_function, eth_hs_function, eth_ss_function, eth_ss_function);if (status) - goto fail; +return status; rndis->port.open = rndis_open; rndis->port.close = rndis_close;
@@ -789,9 +780,18 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)if (rndis->manufacturer && rndis->vendorID &&rndis_set_param_vendor (rndis->params, rndis->vendorID, rndis->manufacturer)) { - status = -EINVAL ; - goto fail_free_descs; +usb_free_all_descriptors (f); +return -EINVAL ; + } + +if (cdev->use_os_string) { + os_desc_table[0 ].os_desc = &rndis_opts->rndis_os_desc; + os_desc_table[0 ].if_id = rndis_iad_descriptor.bFirstInterface; + f->os_desc_table =no_free_ptr (os_desc_table); + f->os_desc_n =1 ; + } + rndis->notify_req =no_free_ptr (request);/* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code
@@ -802,21 +802,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis->port.in_ep->name, rndis->port.out_ep->name, rndis->notify->name);return 0 ; - -fail_free_descs: -usb_free_all_descriptors (f); -fail: -kfree (f->os_desc_table); - f->os_desc_n =0 ; - -if (rndis->notify_req) { -kfree (rndis->notify_req->buf); -usb_ep_free_request (rndis->notify, rndis->notify_req); - } - -ERROR (cdev,"%s: can't bind, err %d\n" , f->name, status); - -return status; }void rndis_borrow_net (struct usb_function_instance *f,struct net_device *net)
Signature · 1 line
2.51.0