[PATCH] usb: gadget: u_ether: avoid NULL port in TX wakeup path
From: Guangshuo Li
Date: Wed Jul 08 2026 - 09:47:09 EST
The change referenced by the Fixes tag clears dev->port_usb at the
beginning of gether_disconnect() while holding dev->lock. This lets
eth_stop() see a disconnected port immediately and avoid using endpoint
state that is being torn down.
However, eth_start_xmit() still checks dev->port_usb under dev->lock and
then drops the lock before calling ether_wakeup_host(). The wakeup call
passes dev->port_usb again, so a concurrent gether_disconnect() can clear
the pointer after the suspended-port check and before the unlocked
wakeup call.
If that happens, eth_start_xmit() calls ether_wakeup_host(NULL), and the
wakeup helper dereferences the NULL port while deriving the USB function
and gadget pointers.
Snapshot dev->port_usb while holding dev->lock and use that snapshot for
the suspended-port check and the later wakeup call. This avoids
re-reading the shared pointer after it can be cleared by disconnect.
Fixes: e1eabb072c75 ("usb: gadget: u_ether: Fix race between gether_disconnect and eth_stop")
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
drivers/usb/gadget/function/u_ether.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 59d85d6a84a8..ff3ed7e3467d 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -463,22 +463,24 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
struct usb_request *req = NULL;
unsigned long flags;
struct usb_ep *in;
+ struct gether *port;
u16 cdc_filter;
spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb) {
- in = dev->port_usb->in_ep;
- cdc_filter = dev->port_usb->cdc_filter;
+ port = dev->port_usb;
+ if (port) {
+ in = port->in_ep;
+ cdc_filter = port->cdc_filter;
} else {
in = NULL;
cdc_filter = 0;
}
- if (dev->port_usb && dev->port_usb->is_suspend) {
+ if (port && port->is_suspend) {
DBG(dev, "Port suspended. Triggering wakeup\n");
netif_stop_queue(net);
spin_unlock_irqrestore(&dev->lock, flags);
- ether_wakeup_host(dev->port_usb);
+ ether_wakeup_host(port);
return NETDEV_TX_BUSY;
}
--
2.43.0