* [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move
@ 2026-06-10 18:08 Carlos Llamas
2026-06-10 18:08 ` [PATCH 6.1.y 2/2] usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo Carlos Llamas
2026-06-11 15:26 ` [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move Sasha Levin
0 siblings, 2 replies; 3+ messages in thread
From: Carlos Llamas @ 2026-06-10 18:08 UTC (permalink / raw)
To: stable
Cc: Jianqiang kang, Neill Kapron, kernel-team, Kuen-Han Tsai, stable,
Greg Kroah-Hartman, Carlos Llamas, Sasha Levin, raub camaioni,
Kyungmin Park, Felipe Balbi, Andrzej Pietrasiewicz,
open list:USB SUBSYSTEM, open list
From: Kuen-Han Tsai <khtsai@google.com>
[ Upstream commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 ]
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@crapouillou.net/
[2] https://lore.kernel.org/linux-usb/795ea759-7eaf-4f78-81f4-01ffbf2d7961@ixit.cz/
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>
[ Use no_free_ptr() since retain_and_null_ptr() is unavailable in Linux 6.1. ]
Signed-off-by: Jianqiang kang <jianqkang@sina.cn>
Signed-off-by: Carlos Llamas <cmllamas@google.com>
---
drivers/usb/gadget/function/f_ncm.c | 35 ++++++++++++++++++---------
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, 73 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index addd016ffbb3..5e240cafbe9e 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1440,6 +1440,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))
@@ -1453,16 +1454,18 @@ 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)
- 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)) {
+ 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;
@@ -1562,6 +1565,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
}
ncm->notify_req = no_free_ptr(request);
+ ncm_opts->bind_count++;
+ no_free_ptr(net);
+
DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
@@ -1610,7 +1616,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);
@@ -1672,9 +1678,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);
@@ -1690,6 +1699,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 e84178bffe78..e972de236be5 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -910,6 +910,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 40144546d1b0..3e12d60053c1 100644
--- a/drivers/usb/gadget/function/u_ether.h
+++ b/drivers/usb/gadget/function/u_ether.h
@@ -149,6 +149,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 5408854d8407..297e5087872f 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.54.0.1136.gdb2ca164c4-goog
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 6.1.y 2/2] usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo
2026-06-10 18:08 [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move Carlos Llamas
@ 2026-06-10 18:08 ` Carlos Llamas
2026-06-11 15:26 ` [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move Sasha Levin
1 sibling, 0 replies; 3+ messages in thread
From: Carlos Llamas @ 2026-06-10 18:08 UTC (permalink / raw)
To: stable
Cc: Jianqiang kang, Neill Kapron, kernel-team, Kuen-Han Tsai,
Val Packett, stable, Greg Kroah-Hartman, Carlos Llamas,
Sasha Levin, open list:USB SUBSYSTEM, open list
From: Kuen-Han Tsai <khtsai@google.com>
[ Upstream commit e002e92e88e12457373ed096b18716d97e7bbb20 ]
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@packett.cool/
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.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Carlos Llamas <cmllamas@google.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 e972de236be5..83dfc5008b68 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -147,8 +147,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.54.0.1136.gdb2ca164c4-goog
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move
2026-06-10 18:08 [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move Carlos Llamas
2026-06-10 18:08 ` [PATCH 6.1.y 2/2] usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo Carlos Llamas
@ 2026-06-11 15:26 ` Sasha Levin
1 sibling, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2026-06-11 15:26 UTC (permalink / raw)
To: stable
Cc: Sasha Levin, Jianqiang kang, Neill Kapron, kernel-team,
Kuen-Han Tsai, stable, Greg Kroah-Hartman, Carlos Llamas,
raub camaioni, Kyungmin Park, Felipe Balbi, Andrzej Pietrasiewicz,
open list:USB SUBSYSTEM, open list
On Wed, Jun 10, 2026 at 06:08:36PM +0000, Carlos Llamas wrote:
> From: Kuen-Han Tsai <khtsai@google.com>
>
> [ Upstream commit ec35c1969650e7cb6c8a91020e568ed46e3551b0 ]
>
> The network device outlived its parent gadget device during
> disconnection, resulting in dangling sysfs links and null pointer
> dereference problems.
Both queued for 6.1 together as the series, thanks.
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-11 15:26 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-10 18:08 [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move Carlos Llamas
2026-06-10 18:08 ` [PATCH 6.1.y 2/2] usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo Carlos Llamas
2026-06-11 15:26 ` [PATCH 6.1.y 1/2] usb: gadget: f_ncm: Fix net_device lifecycle with device_move Sasha Levin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.