All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] usb: gadget: u_ether: refuse to re-register a failed net_device
@ 2026-10-14 11:06 ` Nicholas Velten
  0 siblings, 0 replies; 3+ messages in thread
From: Nicholas Velten via B4 Relay @ 2026-10-14 11:06 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-usb, linux-kernel, syzbot+85ede281798faf736677,
	Nicholas Velten

From: Nicholas Velten <nicholasfvelten@gmail.com>

When register_netdevice() fails in or after netdev_register_kobject(),
it returns an error but leaves the net_device in NETREG_UNREGISTERED.
Such a device can never be registered again; the only valid thing to do
with it is free_netdev().

The configfs Ethernet functions (ECM, EEM, NCM, RNDIS and subset)
allocate their net_device once per function instance and register it
from the bind callback, retrying on every bind for as long as the device
is not registered (formerly tracked by a "bound" flag, now by
device_is_registered()). After a failed registration the next bind
therefore calls register_netdev() on an NETREG_UNREGISTERED device and
hits the BUG_ON() at the top of register_netdevice():

  kernel BUG at net/core/dev.c:11440!
  Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
  RIP: 0010:register_netdevice+0xc21/0x1d00
  Call Trace:
   register_netdev
   gether_register_netdev
   ncm_bind
   usb_add_function
   configfs_composite_bind
   gadget_bind_driver
   ...
   gadget_dev_desc_UDC_store

syzbot hits this by binding a gadget from a memory cgroup with a tiny
limit, which makes the memcg-accounted allocations in
netdev_register_kobject() fail. That is why its bisection lands on
commit 425b9c7f51c9 ("memcg: accounting for objects allocated for new
netdevice"): that commit made the failure reachable that way, while the
retry itself is much older.

Refuse to register a net_device that is not NETREG_UNINITIALIZED in
gether_register_netdev(), which all of these functions use, so that the
bind fails with -EINVAL instead of crashing. The function instance has
to be recreated to get a usable net_device again.

Reproduced with fail-nth fault injection on the allocations of the
write() to the gadget's UDC attribute, binding again without injection
after each failed bind, using a fresh function instance per iteration:
without this change NCM, ECM and RNDIS hit the BUG_ON() at the 16th
injected allocation; with it, 400 iterations for NCM and 300 each for
ECM, EEM, RNDIS and subset complete with no BUG or KASAN report.

Fixes: 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface with backward compatibility")
Reported-by: syzbot+85ede281798faf736677@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=85ede281798faf736677
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Nicholas Velten <nicholasfvelten@gmail.com>
---
The syzbot C reproducer did not reach the gadget bind in my virtme-ng
guest (its sandbox setup appears to fail there), so I reproduced with a
small fail-nth program instead. I can post it if useful.

Not tested: architectures other than x86_64, and the legacy (non-configfs)
gadgets that also call gether_register_netdev() (g_ether, g_multi,
g_ffs); they register once from their bind path and should be unaffected.

f_phonet has the same retry pattern but a different outcome:
gphonet_register_netdev() calls free_netdev() on failure while
phonet_opts->net still points at the device and phonet_opts->bound stays
false, so the next bind uses a freed net_device. I left it out of this
patch to keep it to one change and because f_phonet is being changed by
"usb: gadget: f_phonet: fix use-after-free in pn_bind" (v3, not yet
applied); I can send a separate fix on top of that if wanted.

Also touching gether_register_netdev(), without conflict:
"usb: gadget: u_ether: Fix NULL pointer deref in debug logging".
---
 drivers/usb/gadget/function/u_ether.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 59d85d6a8..1f4ac7078 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -865,6 +865,17 @@ int gether_register_netdev(struct net_device *net)
 
 	if (!net->dev.parent)
 		return -EINVAL;
+
+	/*
+	 * A register_netdev() that failed after netdev_register_kobject()
+	 * leaves the device NETREG_UNREGISTERED, and it can never be
+	 * registered again. The function drivers retry on every bind while
+	 * the device is not registered, so refuse instead of hitting the
+	 * BUG_ON() in register_netdevice().
+	 */
+	if (net->reg_state != NETREG_UNINITIALIZED)
+		return -EINVAL;
+
 	dev = netdev_priv(net);
 	g = dev->gadget;
 

---
base-commit: a90ee4305c4a5df72c11b31dacfdc76e00fcf78a
change-id: 20261014-fix-gadget-netdev-reregister-75cf4090afeb

Best regards,
--  
Nicholas Velten <nicholasfvelten@gmail.com>



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-14 11:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14 11:06 [PATCH] usb: gadget: u_ether: refuse to re-register a failed net_device Nicholas Velten via B4 Relay
2026-10-14 11:06 ` Nicholas Velten
2026-10-14 11:23 ` sashiko-bot

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.