[PATCH OLK-6.6 0/6] CVE-2026-43421
Krishna Kurapati (2): usb: gadget: ncm: Add support to update wMaxSegmentSize via configfs usb: gadget: ncm: Fix endianness of wMaxSegmentSize variable in ecm_desc Kuen-Han Tsai (2): usb: gadget: f_ncm: Fix net_device lifecycle with device_move usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo Thomas Gleixner (1): cleanup: Provide retain_and_null_ptr() Udipto Goswami (1): usb: gadget: ncm: Fix indentations in documentation of NCM section Documentation/usb/gadget-testing.rst | 20 ++--- drivers/usb/gadget/function/f_ncm.c | 101 ++++++++++++++++++++++---- drivers/usb/gadget/function/u_ether.c | 28 ++++++- drivers/usb/gadget/function/u_ether.h | 26 +++++++ drivers/usb/gadget/function/u_ncm.h | 4 +- include/linux/cleanup.h | 19 +++++ 6 files changed, 173 insertions(+), 25 deletions(-) -- 2.34.1
From: Krishna Kurapati <quic_kriskura@quicinc.com> mainline inclusion from mainline-v6.8-rc1 commit 1900daeefd3ebde61199649143085a2dfdebf55c category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14979 CVE: CVE-2026-43421 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- The max segment size is currently limited to the ethernet frame length of the kernel which happens to be 1514 at this point in time. However the NCM specification limits it to 64K for sixtenn bit NTB's. For peer to peer connections, increasing the segment size gives better throughput. Add support to configure this value before configfs symlink is created. Also since the NTB Out/In buffer sizes are fixed at 16384 bytes, limit the segment size to an upper cap of 8000 to allow at least a minimum of 2 MTU sized datagrams to be aggregated. Set the default MTU size for the ncm interface during function bind before network interface is registered allowing MTU to be set in parity with wMaxSegmentSize. Update gadget documentation describing the new configfs property. Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com> Link: https://lore.kernel.org/r/20231221153216.18657-1-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Conflicts: drivers/usb/gadget/function/f_ncm.c [ zxy: fix context conflict ] Signed-off-by: Xinyu Zheng <zhengxinyu6@huawei.com> --- Documentation/usb/gadget-testing.rst | 20 ++++---- drivers/usb/gadget/function/f_ncm.c | 69 ++++++++++++++++++++++++++-- drivers/usb/gadget/function/u_ncm.h | 2 + 3 files changed, 79 insertions(+), 12 deletions(-) diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index 394cd226bfae..3b9ecdaf18d5 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -448,15 +448,17 @@ Function-specific configfs interface The function name to use when creating the function directory is "ncm". The NCM function provides these attributes in its function directory: - =============== ================================================== - ifname network device interface name associated with this - function instance - qmult queue length multiplier for high and super speed - host_addr MAC address of host's end of this - Ethernet over USB link - dev_addr MAC address of device's end of this - Ethernet over USB link - =============== ================================================== + =============== ================================================== + ifname network device interface name associated with this + function instance + qmult queue length multiplier for high and super speed + host_addr MAC address of host's end of this + Ethernet over USB link + dev_addr MAC address of device's end of this + Ethernet over USB link + max_segment_size Segment size required for P2P connections. This + will set MTU to (max_segment_size - 14 bytes) + =============== ================================================== and after creating the functions/ncm.<instance name> they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 1da4e59338c5..c7cfd639334c 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -105,6 +105,16 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) /* Delay for the transmit to wait before sending an unfilled NTB frame. */ #define TX_TIMEOUT_NSECS 300000 +/* + * Although max mtu as dictated by u_ether is 15412 bytes, setting + * max_segment_sizeto 15426 would not be efficient. If user chooses segment + * size to be (>= 8192), then we can't aggregate more than one buffer in each + * NTB (assuming each packet coming from network layer is >= 8192 bytes) as ep + * maxpacket limit is 16384. So let max_segment_size be limited to 8000 to allow + * at least 2 packets to be aggregated reducing wastage of NTB buffer space + */ +#define MAX_DATAGRAM_SIZE 8000 + #define FORMATS_SUPPORTED (USB_CDC_NCM_NTB16_SUPPORTED | \ USB_CDC_NCM_NTB32_SUPPORTED) @@ -181,7 +191,6 @@ static struct usb_cdc_ether_desc ecm_desc = { /* this descriptor actually adds value, surprise! */ /* .iMACAddress = DYNAMIC */ .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */ - .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN), .wNumberMCFilters = cpu_to_le16(0), .bNumberPowerFilters = 0, }; @@ -1168,11 +1177,15 @@ static int ncm_unwrap_ntb(struct gether *port, struct sk_buff *skb2; int ret = -EINVAL; unsigned ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize); - unsigned frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize); + unsigned frame_max; const struct ndp_parser_opts *opts = ncm->parser_opts; unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; int dgram_counter; int to_process = skb->len; + struct f_ncm_opts *ncm_opts; + + ncm_opts = container_of(port->func.fi, struct f_ncm_opts, func_inst); + frame_max = ncm_opts->max_segment_size; parse_ntb: tmp = (__le16 *)ntb_ptr; @@ -1440,8 +1453,10 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) mutex_lock(&ncm_opts->lock); gether_set_gadget(ncm_opts->net, cdev->gadget); - if (!ncm_opts->bound) + if (!ncm_opts->bound) { + ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); status = gether_register_netdev(ncm_opts->net); + } mutex_unlock(&ncm_opts->lock); if (status) @@ -1481,6 +1496,8 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm_data_intf.bInterfaceNumber = status; ncm_union_desc.bSlaveInterface0 = status; + ecm_desc.wMaxSegmentSize = ncm_opts->max_segment_size; + /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_in_desc); if (!ep) @@ -1574,11 +1591,56 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm); /* f_ncm_opts_ifname */ USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm); +static ssize_t ncm_opts_max_segment_size_show(struct config_item *item, + char *page) +{ + struct f_ncm_opts *opts = to_f_ncm_opts(item); + u16 segment_size; + + mutex_lock(&opts->lock); + segment_size = opts->max_segment_size; + mutex_unlock(&opts->lock); + + return sysfs_emit(page, "%u\n", segment_size); +} + +static ssize_t ncm_opts_max_segment_size_store(struct config_item *item, + const char *page, size_t len) +{ + struct f_ncm_opts *opts = to_f_ncm_opts(item); + u16 segment_size; + int ret; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto out; + } + + ret = kstrtou16(page, 0, &segment_size); + if (ret) + goto out; + + if (segment_size > MAX_DATAGRAM_SIZE) { + ret = -EINVAL; + goto out; + } + + opts->max_segment_size = segment_size; + ret = len; +out: + mutex_unlock(&opts->lock); + return ret; +} + +CONFIGFS_ATTR(ncm_opts_, max_segment_size); + static struct configfs_attribute *ncm_attrs[] = { &ncm_opts_attr_dev_addr, &ncm_opts_attr_host_addr, &ncm_opts_attr_qmult, &ncm_opts_attr_ifname, + &ncm_opts_attr_max_segment_size, NULL, }; @@ -1621,6 +1683,7 @@ static struct usb_function_instance *ncm_alloc_inst(void) kfree(opts); return ERR_CAST(net); } + opts->max_segment_size = cpu_to_le16(ETH_FRAME_LEN); INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); descs[0] = &opts->ncm_os_desc; diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index 5408854d8407..49ec095cdb4b 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -31,6 +31,8 @@ struct f_ncm_opts { */ struct mutex lock; int refcnt; + + u16 max_segment_size; }; #endif /* U_NCM_H */ -- 2.34.1
From: Krishna Kurapati <quic_kriskura@quicinc.com> mainline inclusion from mainline-v6.8-rc3 commit 9dc292413c56a2d01e34787d3fc4a76635e4a498 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14979 CVE: CVE-2026-43421 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Recent commit [1] added support for changing max segment size of the NCM interface via configfs. But the value of segment size value stored in ncm_opts need to be converted to little endian before saving it in ecm_desc. Also while initialising the value of segment size in opts during instance allocation, the value ETH_FRAME_LEN needs to be assigned directly without any conversion as ETH_FRAME_LEN and the variable max_segment_size are native endian. The current implementaion modifies it into little endian thus breaking things for big endian targets. Fix endianness while assigning these variables. While at it, fix up some stray spaces in comments added in code. Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com> Reviewed-by: Maciej Żenczykowski <maze@google.com> Link: https://lore.kernel.org/r/20240118154910.8765-1-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Conflicts: drivers/usb/gadget/function/f_ncm.c [ zxy: fix context conflict ] Signed-off-by: Xinyu Zheng <zhengxinyu6@huawei.com> --- drivers/usb/gadget/function/f_ncm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index c7cfd639334c..77f418cc3ed8 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -107,8 +107,8 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) /* * Although max mtu as dictated by u_ether is 15412 bytes, setting - * max_segment_sizeto 15426 would not be efficient. If user chooses segment - * size to be (>= 8192), then we can't aggregate more than one buffer in each + * max_segment_size to 15426 would not be efficient. If user chooses segment + * size to be (>= 8192), then we can't aggregate more than one buffer in each * NTB (assuming each packet coming from network layer is >= 8192 bytes) as ep * maxpacket limit is 16384. So let max_segment_size be limited to 8000 to allow * at least 2 packets to be aggregated reducing wastage of NTB buffer space @@ -1496,7 +1496,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm_data_intf.bInterfaceNumber = status; ncm_union_desc.bSlaveInterface0 = status; - ecm_desc.wMaxSegmentSize = ncm_opts->max_segment_size; + ecm_desc.wMaxSegmentSize = cpu_to_le16(ncm_opts->max_segment_size); /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_in_desc); @@ -1683,7 +1683,7 @@ static struct usb_function_instance *ncm_alloc_inst(void) kfree(opts); return ERR_CAST(net); } - opts->max_segment_size = cpu_to_le16(ETH_FRAME_LEN); + opts->max_segment_size = ETH_FRAME_LEN; INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); descs[0] = &opts->ncm_os_desc; -- 2.34.1
From: Udipto Goswami <quic_ugoswami@quicinc.com> mainline inclusion from mainline-v6.8-rc3 commit 20d03ae36ec010aa97a97495d9dd9202cb93cb87 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14979 CVE: CVE-2026-43421 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Currently, the section of NCM which describes attributes are having wrong indentation. Fix this by following the correct format recommended. Fixes: 1900daeefd3e ("usb: gadget: ncm: Add support to update wMaxSegmentSize via configfs") Reported-by: Stephen Rothwell <sfr@canb.auug.org.au> Closes: https://lore.kernel.org/all/20240108160221.743649b5@canb.auug.org.au/ Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Link: https://lore.kernel.org/r/20240108132720.7786-1-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Xinyu Zheng <zhengxinyu6@huawei.com> --- Documentation/usb/gadget-testing.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index 3b9ecdaf18d5..cc8025e55d4c 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -448,17 +448,17 @@ Function-specific configfs interface The function name to use when creating the function directory is "ncm". The NCM function provides these attributes in its function directory: - =============== ================================================== - ifname network device interface name associated with this - function instance - qmult queue length multiplier for high and super speed - host_addr MAC address of host's end of this - Ethernet over USB link - dev_addr MAC address of device's end of this - Ethernet over USB link - max_segment_size Segment size required for P2P connections. This - will set MTU to (max_segment_size - 14 bytes) - =============== ================================================== + ======================= ================================================== + ifname network device interface name associated with this + function instance + qmult queue length multiplier for high and super speed + host_addr MAC address of host's end of this + Ethernet over USB link + dev_addr MAC address of device's end of this + Ethernet over USB link + max_segment_size Segment size required for P2P connections. This + will set MTU to 14 bytes + ======================= ================================================== and after creating the functions/ncm.<instance name> they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. -- 2.34.1
From: Thomas Gleixner <tglx@linutronix.de> mainline inclusion from mainline-v6.16-rc1 commit 092d00ead733563f6d278295e0b5c5f97558b726 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14979 CVE: CVE-2026-43421 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- In cases where an allocation is consumed by another function, the allocation needs to be retained on success or freed on failure. The code pattern is usually: struct foo *f = kzalloc(sizeof(*f), GFP_KERNEL); struct bar *b; ,,, // Initialize f ... if (ret) goto free; ... bar = bar_create(f); if (!bar) { ret = -ENOMEM; goto free; } ... return 0; free: kfree(f); return ret; This prevents using __free(kfree) on @f because there is no canonical way to tell the cleanup code that the allocation should not be freed. Abusing no_free_ptr() by force ignoring the return value is not really a sensible option either. Provide an explicit macro retain_and_null_ptr(), which NULLs the cleanup pointer. That makes it easy to analyze and reason about. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: James Bottomley <James.Bottomley@HansenPartnership.com> Link: https://lore.kernel.org/all/20250319105506.083538907@linutronix.de Signed-off-by: Xinyu Zheng <zhengxinyu6@huawei.com> --- include/linux/cleanup.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h index 69cb6f739bea..df0e3bad0e20 100644 --- a/include/linux/cleanup.h +++ b/include/linux/cleanup.h @@ -80,6 +80,25 @@ const volatile void * __must_check_fn(const volatile void *val) #define return_ptr(p) return no_free_ptr(p) +/* + * Only for situations where an allocation is handed in to another function + * and consumed by that function on success. + * + * struct foo *f __free(kfree) = kzalloc(sizeof(*f), GFP_KERNEL); + * + * setup(f); + * if (some_condition) + * return -EINVAL; + * .... + * ret = bar(f); + * if (!ret) + * retain_and_null_ptr(f); + * return ret; + * + * After retain_and_null_ptr(f) the variable f is NULL and cannot be + * dereferenced anymore. + */ +#define retain_and_null_ptr(p) ((void)__get_and_null(p, NULL)) /* * DEFINE_CLASS(name, type, exit, init, init_args...): -- 2.34.1
From: Kuen-Han Tsai <khtsai@google.com> mainline inclusion from mainline-v7.0-rc4 commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14979 CVE: CVE-2026-43421 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 upstream. The network device outlived its parent gadget device during disconnection, resulting in dangling sysfs links and null pointer dereference problems. A prior attempt to solve this by removing SET_NETDEV_DEV entirely [1] was reverted due to power management ordering concerns and a NO-CARRIER regression. A subsequent attempt to defer net_device allocation to bind [2] broke 1:1 mapping between function instance and network device, making it impossible for configfs to report the resolved interface name. This results in a regression where the DHCP server fails on pmOS. Use device_move to reparent the net_device between the gadget device and /sys/devices/virtual/ across bind/unbind cycles. This preserves the network interface across USB reconnection, allowing the DHCP server to retain their binding. Introduce gether_attach_gadget()/gether_detach_gadget() helpers and use __free(detach_gadget) macro to undo attachment on bind failure. The bind_count ensures device_move executes only on the first bind. [1] https://lore.kernel.org/lkml/f2a4f9847617a0929d62025748384092e5f35cce.camel@... [2] https://lore.kernel.org/linux-usb/795ea759-7eaf-4f78-81f4-01ffbf2d7961@ixit.... Fixes: 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface with backward compatibility") Cc: stable <stable@kernel.org> Signed-off-by: Kuen-Han Tsai <khtsai@google.com> Link: https://patch.msgid.link/20260309-f-ncm-revert-v2-7-ea2afbc7d9b2@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Xinyu Zheng <zhengxinyu6@huawei.com> --- drivers/usb/gadget/function/f_ncm.c | 38 ++++++++++++++++++--------- drivers/usb/gadget/function/u_ether.c | 22 ++++++++++++++++ drivers/usb/gadget/function/u_ether.h | 26 ++++++++++++++++++ drivers/usb/gadget/function/u_ncm.h | 2 +- 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 77f418cc3ed8..b032a41882b9 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1438,6 +1438,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) struct f_ncm_opts *ncm_opts; struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct net_device *net __free(detach_gadget) = NULL; struct usb_request *request __free(free_usb_request) = NULL; if (!can_support_ecm(cdev->gadget)) @@ -1451,18 +1452,19 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) return -ENOMEM; } - mutex_lock(&ncm_opts->lock); - gether_set_gadget(ncm_opts->net, cdev->gadget); - if (!ncm_opts->bound) { - ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); - status = gether_register_netdev(ncm_opts->net); - } - mutex_unlock(&ncm_opts->lock); - - if (status) - return status; - - ncm_opts->bound = true; + scoped_guard(mutex, &ncm_opts->lock) + if (ncm_opts->bind_count == 0) { + if (!device_is_registered(&ncm_opts->net->dev)) { + ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); + gether_set_gadget(ncm_opts->net, cdev->gadget); + status = gether_register_netdev(ncm_opts->net); + } else + status = gether_attach_gadget(ncm_opts->net, cdev->gadget); + + if (status) + return status; + net = ncm_opts->net; + } ncm_string_defs[1].s = ncm->ethaddr; @@ -1564,6 +1566,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) } ncm->notify_req = no_free_ptr(request); + ncm_opts->bind_count++; + retain_and_null_ptr(net); + DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n", ncm->port.in_ep->name, ncm->port.out_ep->name, ncm->notify->name); @@ -1655,7 +1660,7 @@ static void ncm_free_inst(struct usb_function_instance *f) struct f_ncm_opts *opts; opts = container_of(f, struct f_ncm_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -1718,9 +1723,12 @@ static void ncm_free(struct usb_function *f) static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_ncm *ncm = func_to_ncm(f); + struct f_ncm_opts *ncm_opts; DBG(c->cdev, "ncm unbind\n"); + ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); + hrtimer_cancel(&ncm->task_timer); kfree(f->os_desc_table); @@ -1736,6 +1744,10 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); + + ncm_opts->bind_count--; + if (ncm_opts->bind_count == 0) + gether_detach_gadget(ncm_opts->net); } static struct usb_function *ncm_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 2da2db5e15a3..fae3cd49e0f8 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -896,6 +896,28 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g) } EXPORT_SYMBOL_GPL(gether_set_gadget); +int gether_attach_gadget(struct net_device *net, struct usb_gadget *g) +{ + int ret; + + ret = device_move(&net->dev, &g->dev, DPM_ORDER_DEV_AFTER_PARENT); + if (ret) + return ret; + + gether_set_gadget(net, g); + return 0; +} +EXPORT_SYMBOL_GPL(gether_attach_gadget); + +void gether_detach_gadget(struct net_device *net) +{ + struct eth_dev *dev = netdev_priv(net); + + device_move(&net->dev, NULL, DPM_ORDER_NONE); + dev->gadget = NULL; +} +EXPORT_SYMBOL_GPL(gether_detach_gadget); + int gether_set_dev_addr(struct net_device *net, const char *dev_addr) { struct eth_dev *dev; diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 34be220cef77..c85a1cf3c115 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -150,6 +150,32 @@ static inline struct net_device *gether_setup_default(void) */ void gether_set_gadget(struct net_device *net, struct usb_gadget *g); +/** + * gether_attach_gadget - Reparent net_device to the gadget device. + * @net: The network device to reparent. + * @g: The target USB gadget device to parent to. + * + * This function moves the network device to be a child of the USB gadget + * device in the device hierarchy. This is typically done when the function + * is bound to a configuration. + * + * Returns 0 on success, or a negative error code on failure. + */ +int gether_attach_gadget(struct net_device *net, struct usb_gadget *g); + +/** + * gether_detach_gadget - Detach net_device from its gadget parent. + * @net: The network device to detach. + * + * This function moves the network device to be a child of the virtual + * devices parent, effectively detaching it from the USB gadget device + * hierarchy. This is typically done when the function is unbound + * from a configuration but the instance is not yet freed. + */ +void gether_detach_gadget(struct net_device *net); + +DEFINE_FREE(detach_gadget, struct net_device *, if (_T) gether_detach_gadget(_T)) + /** * gether_set_dev_addr - initialize an ethernet-over-usb link with eth address * @net: device representing this link diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index 49ec095cdb4b..b1f3db8b68c1 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -18,7 +18,7 @@ struct f_ncm_opts { struct usb_function_instance func_inst; struct net_device *net; - bool bound; + int bind_count; struct config_group *ncm_interf_group; struct usb_os_desc ncm_os_desc; -- 2.34.1
From: Kuen-Han Tsai <khtsai@google.com> mainline inclusion from mainline-v7.0-rc4 commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/14979 CVE: CVE-2026-43421 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Commit ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with device_move") reparents the gadget device to /sys/devices/virtual during unbind, clearing the gadget pointer. If the userspace tool queries on the surviving interface during this detached window, this leads to a NULL pointer dereference. Unable to handle kernel NULL pointer dereference Call trace: eth_get_drvinfo+0x50/0x90 ethtool_get_drvinfo+0x5c/0x1f0 __dev_ethtool+0xaec/0x1fe0 dev_ethtool+0x134/0x2e0 dev_ioctl+0x338/0x560 Add a NULL check for dev->gadget in eth_get_drvinfo(). When detached, skip copying the fw_version and bus_info strings, which is natively handled by ethtool_get_drvinfo for empty strings. Suggested-by: Val Packett <val@packett.cool> Reported-by: Val Packett <val@packett.cool> Closes: https://lore.kernel.org/linux-usb/10890524-cf83-4a71-b879-93e2b2cc1fcc@packe... Fixes: ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with device_move") Cc: stable <stable@kernel.org> Signed-off-by: Kuen-Han Tsai <khtsai@google.com> Link: https://patch.msgid.link/20260316-eth-null-deref-v1-1-07005f33be85@google.co... Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Conflicts: drivers/usb/gadget/function/f_ncm.c drivers/usb/gadget/function/u_ether.h drivers/usb/gadget/function/u_ncm.h drivers/usb/gadget/function/u_ether.c [ zxy: fix context conflict ] Signed-off-by: Xinyu Zheng <zhengxinyu6@huawei.com> --- drivers/usb/gadget/function/u_ether.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index fae3cd49e0f8..b952962a27ad 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -112,8 +112,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) strscpy(p->driver, "g_ether", sizeof(p->driver)); strscpy(p->version, UETH__VERSION, sizeof(p->version)); - strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); - strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); + if (dev->gadget) { + strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); + strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); + } } /* REVISIT can also support: -- 2.34.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/23207 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/2JL... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/23207 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/2JL...
participants (2)
-
patchwork bot -
Xinyu Zheng