All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Oliver Neukum" <oneukum@suse.com>, linux-usb@vger.kernel.org
Subject: Re: [PATCH net 1/1] net: usb: rtl8150: break cycle between tasklet and URB
Date: Fri, 13 Nov 2026 10:46:05 +0000	[thread overview]
Message-ID: <sashiko-outbox-212634@kernel.org> (raw)
In-Reply-To: <20261112104548.693456-1-oneukum@suse.com>

Thank you for your contribution! Sashiko AI review found 4 potential
issues to consider:
- [High] net: usb: rtl8150: infinite tasklet loop on -EPERM in
  rx_fixup()
- [High] net: usb: rtl8150: double free of dev->rx_skb on unplug in
  read_bulk_callback()
- [Medium] net: usb: rtl8150: false dev_err() on res == 0 in
  intr_callback()
- [Medium] net: usb: rtl8150: unbalanced URB reject count on error in
  rtl8150_open()
It also noticed 1 related pre-existing issue this patch does not
introduce:
- [High] net: usb: rtl8150: dangling rx_skb pointer in
  read_bulk_callback() [1]
--

commit bed5b8274af4c5f050a94925def40d4d88f1a
Author: Oliver Neukum <oneukum@suse.com>

net: usb: rtl8150: break cycle between tasklet and URB

This commit replaces usb_kill_urb() with usb_poison_urb() in
unlink_all_urbs(), blocks URBs at allocation time and unpoisons them on
open, and checks RTL8150_UNPLUG in read_bulk_callback() to break the
resubmission cycle between dev->rx_urb and dev->tl on disconnect.

> diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
> index d51e43170e033..846e6329d571c 100644
> --- a/drivers/net/usb/rtl8150.c
> +++ b/drivers/net/usb/rtl8150.c
> @@ -343,6 +343,13 @@ static int alloc_all_urbs(rtl8150_t * dev)
>  		return 0;
>  	}
>  
> +	/*
> +	 * They need to be blocked so that open()
> +	 * can unblock them
> +	 */
> +	usb_block_urb(dev->rx_urb);
> +	usb_block_urb(dev->tx_urb);
> +	usb_block_urb(dev->intr_urb);
>  	return 1;
>  }
>  
> @@ -353,11 +360,18 @@ static void free_all_urbs(rtl8150_t * dev)
>  	usb_free_urb(dev->intr_urb);
>  }
>  
> +static void reenable_all_urbs(rtl8150_t *dev)
> +{
> +	usb_unpoison_urb(dev->rx_urb);
> +	usb_unpoison_urb(dev->tx_urb);
> +	usb_unpoison_urb(dev->intr_urb);
> +}
> +
>  static void unlink_all_urbs(rtl8150_t * dev)
>  {
> -	usb_kill_urb(dev->rx_urb);
> -	usb_kill_urb(dev->tx_urb);
> -	usb_kill_urb(dev->intr_urb);
> +	usb_poison_urb(dev->rx_urb);
> +	usb_poison_urb(dev->tx_urb);
> +	usb_poison_urb(dev->intr_urb);
>  }

[Severity: High]
Can poisoning dev->rx_urb cause rx_fixup() to spin in an infinite tasklet
loop on -EPERM?

Once unlink_all_urbs() poisons dev->rx_urb in rtl8150_close() or
rtl8150_disconnect(), usb_submit_urb(dev->rx_urb, GFP_ATOMIC) returns -EPERM.
Neither read_bulk_callback() nor rx_fixup() ignores -EPERM, and rx_fixup()
never checks RTL8150_UNPLUG:

drivers/net/usb/rtl8150.c:rx_fixup() {
    ...
	if (test_bit(RX_URB_FAIL, &dev->flags))
		if (dev->rx_skb)
			goto try_again;
    ...
try_again:
	status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
	if (status == -ENODEV) {
		netif_device_detach(dev->netdev);
	} else if (status) {
		set_bit(RX_URB_FAIL, &dev->flags);
		goto tlsched;
	}
    ...
tlsched:
	tasklet_schedule(&dev->tl);
}

If dev->tl is scheduled when unlink_all_urbs() poisons dev->rx_urb (or if
read_bulk_callback() hits -EPERM at goon: during rtl8150_close() where
RTL8150_UNPLUG is not set), rx_fixup() sets RX_URB_FAIL and reschedules
dev->tl in a tight softirq loop, locking up softirq processing on Close and
hanging tasklet_kill(&dev->tl) in rtl8150_disconnect().

> @@ -425,6 +439,11 @@ static void read_bulk_callback(struct urb *urb)
>  	netdev->stats.rx_bytes += pkt_len;
>  
>  	spin_lock_irqsave(&dev->rx_pool_lock, flags);
> +	/* prevent an eteral loop */
> +	if (test_bit(RTL8150_UNPLUG, &dev->flags)) {
> +		spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
> +		return;
> +	}
>  	skb = pull_skb(dev);
>  	spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
>  	if (!skb)

[Severity: High]
Does returning here when RTL8150_UNPLUG is set cause a double free of
dev->rx_skb?

Just before taking dev->rx_pool_lock, read_bulk_callback() passes
dev->rx_skb to netif_rx().  Returning without clearing dev->rx_skb to NULL
leaves the consumed skb pointer in dev->rx_skb, which rtl8150_disconnect()
then frees a second time via dev_kfree_skb(dev->rx_skb).

[Severity: High]
This problem wasn't introduced by this patch, but read_bulk_callback() also
leaves [1] dev->rx_skb holding a dangling pointer to the skb handed to
netif_rx() whenever pull_skb() returns NULL and jumps to resched:.  If the
device is disconnected before rx_fixup() replaces dev->rx_skb,
rtl8150_disconnect() double frees dev->rx_skb, and if the device is closed
and reopened or suspended and resumed in that state, rtl8150_open() or
rtl8150_resume() resubmits dev->rx_urb using the freed skb buffer.

> @@ -518,7 +537,7 @@ static void intr_callback(struct urb *urb)
>  	res = usb_submit_urb (urb, GFP_ATOMIC);
>  	if (res == -ENODEV)
>  		netif_device_detach(dev->netdev);
> -	else if (res)
> +	else if (res != -EPERM)
>  		dev_err(&dev->udev->dev,
>  			"can't resubmit intr, %s-%s/input0, status %d\n",
>  			dev->udev->bus->bus_name, dev->udev->devpath, res);

[Severity: Medium]
Doesn't "else if (res != -EPERM)" evaluate to true when usb_submit_urb()
succeeds with res == 0?  That logs a false dev_err() on every interrupt URB
completion unless the check is "else if (res && res != -EPERM)".

> @@ -751,6 +770,7 @@ static int rtl8150_open(struct net_device *netdev)
>  	if (!dev->rx_skb)
>  		return -ENOMEM;
>  
> +	reenable_all_urbs(dev);
>  	set_registers(dev, IDR, 6, netdev->dev_addr);
>  
>  	usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),

[Severity: Medium]
What happens to the URB reject count if usb_submit_urb() fails in
rtl8150_open()?

reenable_all_urbs() decrements urb->reject from 1 to 0 on all three URBs,
and the error paths in rtl8150_open() return without calling
unlink_all_urbs() to re-poison them (only calling usb_kill_urb(dev->rx_urb)
when dev->intr_urb submission fails):

drivers/net/usb/rtl8150.c:rtl8150_open() {
    ...
	if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
		if (res == -ENODEV)
			netif_device_detach(dev->netdev);
		dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", res);
		return res;
	}
    ...
	if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
		if (res == -ENODEV)
			netif_device_detach(dev->netdev);
		dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", res);
		usb_kill_urb(dev->rx_urb);
		return res;
	}
    ...
}

Because rtl8150_close() is not called when rtl8150_open() fails, the next
rtl8150_open() call decrements urb->reject from 0 to -1, causing all
subsequent usb_submit_urb() calls to fail with -EPERM and causing a later
unlink_all_urbs() to increment urb->reject back to 0 instead of poisoning
the URBs.

[1] https://sashiko.dev/#/bug/linux-361a8ebc-4be5-4126-a2d9-b88d108064a9

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261112104548.693456-1-oneukum@suse.com?part=1

      parent reply	other threads:[~2026-11-13 10:46 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-12 10:45 [PATCH net 1/1] net: usb: rtl8150: break cycle between tasklet and URB Oliver Neukum
2026-11-12 10:52 ` netdev-bot+sinfo
2026-11-12 11:09   ` Oliver Neukum
2026-11-13 10:46 ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-212634@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=oneukum@suse.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.