Skip to content

Commit 41f71de

Browse files
committed
Merge patch series "usb: gadget: Refactor function drivers to use __free() cleanup"
Kuen-Han Tsai <khtsai@google.com> says: This patch series refactors the error-handling paths in the bind() function for f_ncm, f_acm, f_ecm, and f_rndis drivers. The current, unified goto logic in these drivers is vulnerable to a null pointer dereference. This is caused by the cleanup logic incorrectly handling the stale usb_request pointer after a bind/unbind cycle. This series fixes this issue by converting the drivers to use the modern __free() scope-based cleanup mechanism. Patches 1-2 are preparatory, adding the endpoint pointer to struct usb_request and defining helpers for the __free() cleanup. The remaining four patches use this new plumbing to refactor each driver. Future work ----------- 1. Refactor usb_ep_free_request(), usb_ep_queue(), and usb_ep_dequeue() functions as the ep parameter becomes redudant. 2. Convert the remaining gadget function drivers to use the new __free() cleanup mechanism. Link: https://lore.kernel.org/r/20250916-ready-v1-0-4997bf277548@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2 parents 5db5025 + 0822894 commit 41f71de

6 files changed

Lines changed: 135 additions & 146 deletions

File tree

drivers/usb/gadget/function/f_acm.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111

1212
/* #define VERBOSE_DEBUG */
1313

14+
#include <linux/cleanup.h>
1415
#include <linux/slab.h>
1516
#include <linux/kernel.h>
1617
#include <linux/module.h>
1718
#include <linux/device.h>
1819
#include <linux/err.h>
1920

21+
#include <linux/usb/gadget.h>
22+
2023
#include "u_serial.h"
2124

2225

@@ -613,6 +616,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
613616
struct usb_string *us;
614617
int status;
615618
struct usb_ep *ep;
619+
struct usb_request *request __free(free_usb_request) = NULL;
616620

617621
/* REVISIT might want instance-specific strings to help
618622
* distinguish instances ...
@@ -630,7 +634,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
630634
/* allocate instance-specific interface IDs, and patch descriptors */
631635
status = usb_interface_id(c, f);
632636
if (status < 0)
633-
goto fail;
637+
return status;
634638
acm->ctrl_id = status;
635639
acm_iad_descriptor.bFirstInterface = status;
636640

@@ -639,43 +643,41 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
639643

640644
status = usb_interface_id(c, f);
641645
if (status < 0)
642-
goto fail;
646+
return status;
643647
acm->data_id = status;
644648

645649
acm_data_interface_desc.bInterfaceNumber = status;
646650
acm_union_desc.bSlaveInterface0 = status;
647651
acm_call_mgmt_descriptor.bDataInterface = status;
648652

649-
status = -ENODEV;
650-
651653
/* allocate instance-specific endpoints */
652654
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
653655
if (!ep)
654-
goto fail;
656+
return -ENODEV;
655657
acm->port.in = ep;
656658

657659
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
658660
if (!ep)
659-
goto fail;
661+
return -ENODEV;
660662
acm->port.out = ep;
661663

662664
ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
663665
if (!ep)
664-
goto fail;
666+
return -ENODEV;
665667
acm->notify = ep;
666668

667669
acm_iad_descriptor.bFunctionProtocol = acm->bInterfaceProtocol;
668670
acm_control_interface_desc.bInterfaceProtocol = acm->bInterfaceProtocol;
669671

670672
/* allocate notification */
671-
acm->notify_req = gs_alloc_req(ep,
672-
sizeof(struct usb_cdc_notification) + 2,
673-
GFP_KERNEL);
674-
if (!acm->notify_req)
675-
goto fail;
673+
request = gs_alloc_req(ep,
674+
sizeof(struct usb_cdc_notification) + 2,
675+
GFP_KERNEL);
676+
if (!request)
677+
return -ENODEV;
676678

677-
acm->notify_req->complete = acm_cdc_notify_complete;
678-
acm->notify_req->context = acm;
679+
request->complete = acm_cdc_notify_complete;
680+
request->context = acm;
679681

680682
/* support all relevant hardware speeds... we expect that when
681683
* hardware is dual speed, all bulk-capable endpoints work at
@@ -692,22 +694,16 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
692694
status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
693695
acm_ss_function, acm_ss_function);
694696
if (status)
695-
goto fail;
697+
return status;
698+
699+
acm->notify_req = no_free_ptr(request);
696700

697701
dev_dbg(&cdev->gadget->dev,
698702
"acm ttyGS%d: IN/%s OUT/%s NOTIFY/%s\n",
699703
acm->port_num,
700704
acm->port.in->name, acm->port.out->name,
701705
acm->notify->name);
702706
return 0;
703-
704-
fail:
705-
if (acm->notify_req)
706-
gs_free_req(acm->notify, acm->notify_req);
707-
708-
ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
709-
710-
return status;
711707
}
712708

713709
static void acm_unbind(struct usb_configuration *c, struct usb_function *f)

drivers/usb/gadget/function/f_ecm.c

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88

99
/* #define VERBOSE_DEBUG */
1010

11+
#include <linux/cleanup.h>
1112
#include <linux/slab.h>
1213
#include <linux/kernel.h>
1314
#include <linux/module.h>
1415
#include <linux/device.h>
1516
#include <linux/etherdevice.h>
1617
#include <linux/string_choices.h>
1718

19+
#include <linux/usb/gadget.h>
20+
1821
#include "u_ether.h"
1922
#include "u_ether_configfs.h"
2023
#include "u_ecm.h"
@@ -678,6 +681,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
678681
struct usb_ep *ep;
679682

680683
struct f_ecm_opts *ecm_opts;
684+
struct usb_request *request __free(free_usb_request) = NULL;
681685

682686
if (!can_support_ecm(cdev->gadget))
683687
return -EINVAL;
@@ -711,7 +715,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
711715
/* allocate instance-specific interface IDs */
712716
status = usb_interface_id(c, f);
713717
if (status < 0)
714-
goto fail;
718+
return status;
715719
ecm->ctrl_id = status;
716720
ecm_iad_descriptor.bFirstInterface = status;
717721

@@ -720,24 +724,22 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
720724

721725
status = usb_interface_id(c, f);
722726
if (status < 0)
723-
goto fail;
727+
return status;
724728
ecm->data_id = status;
725729

726730
ecm_data_nop_intf.bInterfaceNumber = status;
727731
ecm_data_intf.bInterfaceNumber = status;
728732
ecm_union_desc.bSlaveInterface0 = status;
729733

730-
status = -ENODEV;
731-
732734
/* allocate instance-specific endpoints */
733735
ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_in_desc);
734736
if (!ep)
735-
goto fail;
737+
return -ENODEV;
736738
ecm->port.in_ep = ep;
737739

738740
ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc);
739741
if (!ep)
740-
goto fail;
742+
return -ENODEV;
741743
ecm->port.out_ep = ep;
742744

743745
/* NOTE: a status/notification endpoint is *OPTIONAL* but we
@@ -746,20 +748,18 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
746748
*/
747749
ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_notify_desc);
748750
if (!ep)
749-
goto fail;
751+
return -ENODEV;
750752
ecm->notify = ep;
751753

752-
status = -ENOMEM;
753-
754754
/* allocate notification request and buffer */
755-
ecm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
756-
if (!ecm->notify_req)
757-
goto fail;
758-
ecm->notify_req->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL);
759-
if (!ecm->notify_req->buf)
760-
goto fail;
761-
ecm->notify_req->context = ecm;
762-
ecm->notify_req->complete = ecm_notify_complete;
755+
request = usb_ep_alloc_request(ep, GFP_KERNEL);
756+
if (!request)
757+
return -ENOMEM;
758+
request->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL);
759+
if (!request->buf)
760+
return -ENOMEM;
761+
request->context = ecm;
762+
request->complete = ecm_notify_complete;
763763

764764
/* support all relevant hardware speeds... we expect that when
765765
* hardware is dual speed, all bulk-capable endpoints work at
@@ -778,7 +778,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
778778
status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
779779
ecm_ss_function, ecm_ss_function);
780780
if (status)
781-
goto fail;
781+
return status;
782782

783783
/* NOTE: all that is done without knowing or caring about
784784
* the network link ... which is unavailable to this code
@@ -788,20 +788,12 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
788788
ecm->port.open = ecm_open;
789789
ecm->port.close = ecm_close;
790790

791+
ecm->notify_req = no_free_ptr(request);
792+
791793
DBG(cdev, "CDC Ethernet: IN/%s OUT/%s NOTIFY/%s\n",
792794
ecm->port.in_ep->name, ecm->port.out_ep->name,
793795
ecm->notify->name);
794796
return 0;
795-
796-
fail:
797-
if (ecm->notify_req) {
798-
kfree(ecm->notify_req->buf);
799-
usb_ep_free_request(ecm->notify, ecm->notify_req);
800-
}
801-
802-
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
803-
804-
return status;
805797
}
806798

807799
static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item)

0 commit comments

Comments
 (0)