Linux USB
 help / color / mirror / Atom feed
* [PATCH] net: hso: fix tx skb leak when the device stops
@ 2026-11-14  9:31 Aibing Chen
  2026-11-15  9:31 ` sashiko-bot
  2026-11-15 10:16 ` [PATCH v2] net: hso: fix tx skb leak and a race on the stashed skb Aibing Chen
  0 siblings, 2 replies; 3+ messages in thread
From: Aibing Chen @ 2026-11-14  9:31 UTC (permalink / raw)
  To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: linux-usb, netdev, linux-kernel

hso_net_start_xmit() stashes the skb in odev->skb_tx_buf and stops the
queue when hso_get_activity() reports -EAGAIN, which happens when the
USB device is suspended or no longer configured.  If the interface is
then brought down, or the device is disconnected, that skb is simply
left behind: hso_net_close() and hso_free_net_device() never release
it, and hso_net_open() clears the pointer, so the skb and its data
buffer are leaked.

Free the pending skb in hso_net_close(), which is also reached from
unregister_netdev() on disconnect.

hso_resume() loses a frame in the same way when the device is still not
ready: it passes skb_tx_buf to hso_net_start_xmit() and then clears the
pointer unconditionally, so a frame stashed again by that call is never
freed.  Clear the pointer before the call instead and let
hso_net_start_xmit() stash it again if it has to.

Reported-by: syzbot+bf62ca9997f43d2fa521@syzkaller.appspotmail.com
Link: https://lore.kernel.org/all/6af74e31.fe96acdb.12252b.0009.GAE@google.com/
Signed-off-by: Aibing Chen <chenaibing@cmss.chinamobile.com>
---
 drivers/net/usb/hso.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 71caa3764..03956fa8e 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -728,6 +728,13 @@ static int hso_net_close(struct net_device *net)
 
 	hso_stop_net_device(odev->parent);
 
+	/*
+	 * A frame stashed by hso_net_start_xmit() will never be transmitted now,
+	 * so drop it instead of leaking it.
+	 */
+	dev_kfree_skb(odev->skb_tx_buf);
+	odev->skb_tx_buf = NULL;
+
 	/* done */
 	return 0;
 }
@@ -3055,12 +3062,13 @@ static int hso_resume(struct usb_interface *iface)
 				/* First transmit any lingering data,
 				   then restart the device. */
 				if (hso_net->skb_tx_buf) {
+					struct sk_buff *skb = hso_net->skb_tx_buf;
+
 					dev_dbg(&iface->dev,
 						"Transmitting"
 						" lingering data\n");
-					hso_net_start_xmit(hso_net->skb_tx_buf,
-							   hso_net->net);
 					hso_net->skb_tx_buf = NULL;
+					hso_net_start_xmit(skb, hso_net->net);
 				}
 				result = hso_start_net_device(network_table[i]);
 				if (result)



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

* Re: [PATCH] net: hso: fix tx skb leak when the device stops
  2026-11-14  9:31 [PATCH] net: hso: fix tx skb leak when the device stops Aibing Chen
@ 2026-11-15  9:31 ` sashiko-bot
  2026-11-15 10:16 ` [PATCH v2] net: hso: fix tx skb leak and a race on the stashed skb Aibing Chen
  1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-11-15  9:31 UTC (permalink / raw)
  To: Aibing Chen; +Cc: linux-usb

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] net: hso: race on skb_tx_buf between hso_net_close() and
  hso_resume()
- [Low] net: hso: missing Fixes trailer in commit message
--

commit 759e4b053ce61e8448ad5b49402e8bd576be78fd
Author: Aibing Chen <chenaibing@cmss.chinamobile.com>

> net: hso: fix tx skb leak when the device stops
> 
> hso_net_start_xmit() stashes the skb in odev->skb_tx_buf and stops the
> queue when hso_get_activity() reports -EAGAIN, which happens when the
> USB device is suspended or no longer configured.  If the interface is
> then brought down, or the device is disconnected, that skb is simply
> left behind: hso_net_close() and hso_free_net_device() never release
> it, and hso_net_open() clears the pointer, so the skb and its data
> buffer are leaked.
> 
> Free the pending skb in hso_net_close(), which is also reached from
> unregister_netdev() on disconnect.
> 
> hso_resume() loses a frame in the same way when the device is still not
> ready: it passes skb_tx_buf to hso_net_start_xmit() and then clears the
> pointer unconditionally, so a frame stashed again by that call is never
> freed.  Clear the pointer before the call instead and let
> hso_net_start_xmit() stash it again if it has to.
> 
> Reported-by: syzbot+bf62ca9997f43d2fa521@syzkaller.appspotmail.com
> Link: https://lore.kernel.org/all/6af74e31.fe96acdb.12252b.0009.GAE@google.com/
> Signed-off-by: Aibing Chen <chenaibing@cmss.chinamobile.com>

[Severity: Low]
Should this commit include Fixes tags for the two commits that introduced
these skb_tx_buf leaks?

  Fixes: 72dc1c096c70 ("HSO: add option hso driver")
  Fixes: c213f286f2cf ("[netdrvr] hso: dev_kfree_skb crash fix")

> diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
> index 71caa3764b239..03956fa8ee537 100644
> --- a/drivers/net/usb/hso.c
> +++ b/drivers/net/usb/hso.c
> @@ -728,6 +728,13 @@ static int hso_net_close(struct net_device *net)
>  
>  	hso_stop_net_device(odev->parent);
>  
> +	/*
> +	 * A frame stashed by hso_net_start_xmit() will never be transmitted now,
> +	 * so drop it instead of leaking it.
> +	 */
> +	dev_kfree_skb(odev->skb_tx_buf);
> +	odev->skb_tx_buf = NULL;
> +
>  	/* done */
>  	return 0;
>  }
> @@ -3055,12 +3062,13 @@ static int hso_resume(struct usb_interface *iface)
>  				/* First transmit any lingering data,
>  				   then restart the device. */
>  				if (hso_net->skb_tx_buf) {
> +					struct sk_buff *skb = hso_net->skb_tx_buf;
> +
>  					dev_dbg(&iface->dev,
>  						"Transmitting"
>  						" lingering data\n");
> -					hso_net_start_xmit(hso_net->skb_tx_buf,
> -							   hso_net->net);
>  					hso_net->skb_tx_buf = NULL;
> +					hso_net_start_xmit(skb, hso_net->net);
>  				}
>  				result = hso_start_net_device(network_table[i]);
>  				if (result)

[Severity: High]
Can hso_net_close() and hso_resume() race on skb_tx_buf and cause a
use-after-free and double free?

When hso_net_start_xmit() stashes a frame while the USB device is
suspended, hso_get_activity() schedules async_get_intf to resume the
interface.  hso_net_close() runs under rtnl_lock without holding the USB
device lock, cancelling async_get_intf, or synchronizing with hso_resume():

CPU0                              CPU1
hso_resume()                      hso_net_close()
  if (hso_net->flags & IFF_UP)
    skb = hso_net->skb_tx_buf;
                                    clear_bit(HSO_NET_RUNNING, &odev->flags);
                                    hso_stop_net_device(odev->parent);
                                    dev_kfree_skb(odev->skb_tx_buf);
                                    odev->skb_tx_buf = NULL;
    hso_net->skb_tx_buf = NULL;
    hso_net_start_xmit(skb, ...)
      memcpy(..., skb->data, ...) <-- use-after-free
      dev_kfree_skb(skb)          <-- double free

If CPU0 clears hso_net->skb_tx_buf just before CPU1 calls dev_kfree_skb(),
CPU1 frees NULL and finishes closing the device, after which CPU0 calls
hso_net_start_xmit() and hso_start_net_device() on the stopped device,
either submitting URBs after close or re-stashing and leaking skb in
skb_tx_buf.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261114093133.465-1-chenaibing@cmss.chinamobile.com?part=1

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

* [PATCH v2] net: hso: fix tx skb leak and a race on the stashed skb
  2026-11-14  9:31 [PATCH] net: hso: fix tx skb leak when the device stops Aibing Chen
  2026-11-15  9:31 ` sashiko-bot
@ 2026-11-15 10:16 ` Aibing Chen
  1 sibling, 0 replies; 3+ messages in thread
From: Aibing Chen @ 2026-11-15 10:16 UTC (permalink / raw)
  To: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni
  Cc: linux-usb, netdev, linux-kernel

hso_net_start_xmit() stashes the skb in odev->skb_tx_buf and stops the
queue when hso_get_activity() reports -EAGAIN, which happens when the
USB device is suspended or no longer configured.  If the interface is
then brought down, or the device is disconnected, that skb is simply
left behind: hso_net_close() and hso_free_net_device() never release
it, and hso_net_open() clears the pointer, so the skb and its data
buffer are leaked.

hso_resume() loses a frame in the same way when the device is still not
ready: it passes skb_tx_buf to hso_net_start_xmit() and then clears the
pointer unconditionally, so a frame stashed again by that call is never
freed.

Free the pending skb in hso_net_close() and take ownership of the
pointer with xchg() in both places, so that only one of the close and
resume paths can obtain it.  hso_resume() also drops the frame instead
of transmitting it when the interface has already been stopped.

Reported-by: syzbot+bf62ca9997f43d2fa521@syzkaller.appspotmail.com
Link: https://lore.kernel.org/all/6af74e31.fe96acdb.12252b.0009.GAE@google.com/
Fixes: 72dc1c096c70 ("HSO: add option hso driver")
Fixes: c213f286f2cf ("[netdrvr] hso: dev_kfree_skb crash fix")
Signed-off-by: Aibing Chen <chenaibing@cmss.chinamobile.com>
---
v2:
- take the stashed skb with xchg() in hso_net_close() and hso_resume(),
  so that only one path can free it (race reported by sashiko).
- drop the frame in hso_resume() instead of transmitting it after the
  interface was stopped.
- add the two Fixes tags.

 drivers/net/usb/hso.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 71caa3764..ba59bdefd 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -720,6 +720,7 @@ static int hso_net_open(struct net_device *net)
 static int hso_net_close(struct net_device *net)
 {
 	struct hso_net *odev = netdev_priv(net);
+	struct sk_buff *skb;
 
 	/* we don't need the queue anymore */
 	netif_stop_queue(net);
@@ -728,6 +729,14 @@ static int hso_net_close(struct net_device *net)
 
 	hso_stop_net_device(odev->parent);
 
+	/*
+	 * Take ownership of a frame stashed by hso_net_start_xmit() and drop it.
+	 * hso_resume() takes it the same way, so only one of the two paths frees
+	 * it.
+	 */
+	skb = xchg(&odev->skb_tx_buf, NULL);
+	dev_kfree_skb(skb);
+
 	/* done */
 	return 0;
 }
@@ -3032,6 +3041,7 @@ static int hso_resume(struct usb_interface *iface)
 {
 	int i, result = 0;
 	struct hso_net *hso_net;
+	struct sk_buff *skb;
 
 	/* Start all serial ports */
 	for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
@@ -3054,13 +3064,17 @@ static int hso_resume(struct usb_interface *iface)
 			if (hso_net->flags & IFF_UP) {
 				/* First transmit any lingering data,
 				   then restart the device. */
-				if (hso_net->skb_tx_buf) {
+				skb = xchg(&hso_net->skb_tx_buf, NULL);
+				if (skb) {
 					dev_dbg(&iface->dev,
 						"Transmitting"
 						" lingering data\n");
-					hso_net_start_xmit(hso_net->skb_tx_buf,
-							   hso_net->net);
-					hso_net->skb_tx_buf = NULL;
+					if (test_bit(HSO_NET_RUNNING,
+						     &hso_net->flags))
+						hso_net_start_xmit(skb,
+								   hso_net->net);
+					else
+						dev_kfree_skb(skb);
 				}
 				result = hso_start_net_device(network_table[i]);
 				if (result)



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

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

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-14  9:31 [PATCH] net: hso: fix tx skb leak when the device stops Aibing Chen
2026-11-15  9:31 ` sashiko-bot
2026-11-15 10:16 ` [PATCH v2] net: hso: fix tx skb leak and a race on the stashed skb Aibing Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox