All of lore.kernel.org
 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 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.