Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: gadget: f_ncm: Fix atomic context locking issue

The ncm_set_alt function was holding a mutex to protect against races
with configfs, which invokes the might-sleep function inside an atomic
context.

Remove the struct net_device pointer from the f_ncm_opts structure to
eliminate the contention. The connection state is now managed by a new
boolean flag to preserve the use-after-free fix from
commit 6334b8e4553c ("usb: gadget: f_ncm: Fix UAF ncm object at re-bind
after usb ep transport error").

BUG: sleeping function called from invalid context
Call Trace:
dump_stack_lvl+0x83/0xc0
dump_stack+0x14/0x16
__might_resched+0x389/0x4c0
__might_sleep+0x8e/0x100
...
__mutex_lock+0x6f/0x1740
...
ncm_set_alt+0x209/0xa40
set_config+0x6b6/0xb40
composite_setup+0x734/0x2b40
...

Fixes: 56a512a9b410 ("usb: gadget: f_ncm: align net_device lifecycle with bind/unbind")
Cc: stable@kernel.org
Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
Link: https://patch.msgid.link/20260221-legacy-ncm-v2-2-dfb891d76507@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Kuen-Han Tsai and committed by
Greg Kroah-Hartman
0d6c8144 fde0634a

+13 -28
+12 -17
drivers/usb/gadget/function/f_ncm.c
··· 58 58 u8 notify_state; 59 59 atomic_t notify_count; 60 60 bool is_open; 61 + bool is_connected; 61 62 62 63 const struct ndp_parser_opts *parser_opts; 63 64 bool is_crc; ··· 865 864 static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) 866 865 { 867 866 struct f_ncm *ncm = func_to_ncm(f); 868 - struct f_ncm_opts *opts = func_to_ncm_opts(f); 869 867 struct usb_composite_dev *cdev = f->config->cdev; 870 868 871 869 /* Control interface has only altsetting 0 */ ··· 887 887 if (alt > 1) 888 888 goto fail; 889 889 890 - scoped_guard(mutex, &opts->lock) 891 - if (opts->net) { 892 - DBG(cdev, "reset ncm\n"); 893 - opts->net = NULL; 894 - gether_disconnect(&ncm->port); 895 - ncm_reset_values(ncm); 896 - } 890 + if (ncm->is_connected) { 891 + DBG(cdev, "reset ncm\n"); 892 + ncm->is_connected = false; 893 + gether_disconnect(&ncm->port); 894 + ncm_reset_values(ncm); 895 + } 897 896 898 897 /* 899 898 * CDC Network only sends data in non-default altsettings. ··· 925 926 net = gether_connect(&ncm->port); 926 927 if (IS_ERR(net)) 927 928 return PTR_ERR(net); 928 - scoped_guard(mutex, &opts->lock) 929 - opts->net = net; 929 + ncm->is_connected = true; 930 930 } 931 931 932 932 spin_lock(&ncm->lock); ··· 1372 1374 static void ncm_disable(struct usb_function *f) 1373 1375 { 1374 1376 struct f_ncm *ncm = func_to_ncm(f); 1375 - struct f_ncm_opts *opts = func_to_ncm_opts(f); 1376 1377 struct usb_composite_dev *cdev = f->config->cdev; 1377 1378 1378 1379 DBG(cdev, "ncm deactivated\n"); 1379 1380 1380 - scoped_guard(mutex, &opts->lock) 1381 - if (opts->net) { 1382 - opts->net = NULL; 1383 - gether_disconnect(&ncm->port); 1384 - } 1381 + if (ncm->is_connected) { 1382 + ncm->is_connected = false; 1383 + gether_disconnect(&ncm->port); 1384 + } 1385 1385 1386 1386 if (ncm->notify->enabled) { 1387 1387 usb_ep_disable(ncm->notify); ··· 1683 1687 if (!opts) 1684 1688 return ERR_PTR(-ENOMEM); 1685 1689 1686 - opts->net = NULL; 1687 1690 opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; 1688 1691 gether_setup_opts_default(&opts->net_opts, "usb"); 1689 1692
+1 -10
drivers/usb/gadget/function/u_ether_configfs.h
··· 327 327 char *page) \ 328 328 { \ 329 329 struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ 330 - const char *name; \ 331 330 \ 332 331 guard(mutex)(&opts->lock); \ 333 - rtnl_lock(); \ 334 - if (opts->net_opts.ifname_set) \ 335 - name = opts->net_opts.name; \ 336 - else if (opts->net) \ 337 - name = netdev_name(opts->net); \ 338 - else \ 339 - name = "(inactive net_device)"; \ 340 - rtnl_unlock(); \ 341 - return sysfs_emit(page, "%s\n", name); \ 332 + return sysfs_emit(page, "%s\n", opts->net_opts.name); \ 342 333 } \ 343 334 \ 344 335 static ssize_t _f_##_opts_ifname_store(struct config_item *item, \
-1
drivers/usb/gadget/function/u_ncm.h
··· 19 19 20 20 struct f_ncm_opts { 21 21 struct usb_function_instance func_inst; 22 - struct net_device *net; 23 22 24 23 struct gether_opts net_opts; 25 24 struct config_group *ncm_interf_group;