All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free
@ 2026-11-09  4:49 hyunjungg
  2026-11-10  4:49 ` sashiko-bot
  2026-11-10 17:51 ` netdev-bot+sashiko
  0 siblings, 2 replies; 5+ messages in thread
From: hyunjungg @ 2026-11-09  4:49 UTC (permalink / raw)
  To: Marc Kleine-Budde, linux-can
  Cc: Vincent Mailhol, Jakub Kicinski, netdev, linux-kernel,
	Hyunjung Ko, stable

From: Hyunjung Ko <hj351016@gmail.com>

pcan_usb arms pdev->restart_timer from pcan_usb_restart_pending(), the
completion of the restart-command URB submitted by pcan_usb_restart_async()
on bus-off auto-restart or a manual CAN_MODE_START. That URB is not
anchored to dev->tx_submitted/rx_submitted, so peak_usb_unlink_all_urbs()
does not kill it, and the completion can run -- re-arming the timer via
mod_timer() -- after the interface has been stopped.

pcan_usb provides no teardown for the timer, so on disconnect (or a probe
error path reaching the adap_dev_free label) peak_usb_disconnect() calls
free_candev() with the timer still live. A pending or late-armed timer
then runs pcan_usb_restart() against the freed struct pcan_usb ->
use-after-free.

Add a pcan_usb dev_free callback that calls timer_shutdown_sync() on
restart_timer. peak_usb_disconnect() invokes dev_free() after
unregister_candev() and before free_candev(), by which point the
endpoint URBs have been flushed by usb_disable_interface(). Unlike
timer_delete_sync(), timer_shutdown_sync() also prevents a late URB
completion from re-arming the timer, closing the window a plain delete
would leave open.

Not reproduced on hardware (no PEAK PCAN-USB adapter); found by review of
the restart-timer teardown path.

Fixes: 46be265d3388 ("can: usb: PEAK-System Technik PCAN-USB specific part")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunjung Ko <hj351016@gmail.com>
---
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 8fd058c32856..113b2e745331 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -882,6 +882,19 @@ static int pcan_usb_start(struct peak_usb_device *dev)
 	return pcan_usb_set_ext_vcc(dev, 0);
 }
 
+static void pcan_usb_free(struct peak_usb_device *dev)
+{
+	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
+
+	/*
+	 * The restart timer is armed from the restart-command URB completion
+	 * (pcan_usb_restart_pending()), which is not anchored and so outlives
+	 * ndo_stop/unlink_all_urbs. Shut it down -- not just delete it -- so a
+	 * late completion cannot re-arm it after free_candev().
+	 */
+	timer_shutdown_sync(&pdev->restart_timer);
+}
+
 static int pcan_usb_init(struct peak_usb_device *dev)
 {
 	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
@@ -1051,6 +1064,7 @@ const struct peak_usb_adapter pcan_usb = {
 	.dev_decode_buf = pcan_usb_decode_buf,
 	.dev_encode_msg = pcan_usb_encode_msg,
 	.dev_start = pcan_usb_start,
+	.dev_free = pcan_usb_free,
 	.dev_restart_async = pcan_usb_restart_async,
 	.do_get_berr_counter = pcan_usb_get_berr_counter,
 };
-- 
2.43.0


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

* Re: [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free
  2026-11-09  4:49 [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free hyunjungg
@ 2026-11-10  4:49 ` sashiko-bot
  2026-11-10  5:04   ` khj
  2026-11-10 17:51 ` netdev-bot+sashiko
  1 sibling, 1 reply; 5+ messages in thread
From: sashiko-bot @ 2026-11-10  4:49 UTC (permalink / raw)
  To: hyunjungg, linux-can
  Cc: Marc Kleine-Budde, Oliver Hartkopp, Vincent Mailhol,
	Oleksij Rempel

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] can: peak_usb: unanchored restart URB and timer mishandled in
  pcan_usb_free()
--

commit 5d0ce26d62347660cb47c1b9c3037c160879b961
Author: Hyunjung Ko <hj351016@gmail.com>

can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free

This commit adds a dev_free callback to pcan_usb that calls
timer_shutdown_sync() on pdev->restart_timer before freeing the device.

> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
> index 8fd058c328564..113b2e7453310 100644
> --- a/drivers/net/can/usb/peak_usb/pcan_usb.c
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
> @@ -882,6 +882,19 @@ static int pcan_usb_start(struct peak_usb_device *dev)
>  	return pcan_usb_set_ext_vcc(dev, 0);
>  }
>  
> +static void pcan_usb_free(struct peak_usb_device *dev)
> +{
> +	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
> +
> +	/*
> +	 * The restart timer is armed from the restart-command URB completion
> +	 * (pcan_usb_restart_pending()), which is not anchored and so outlives
> +	 * ndo_stop/unlink_all_urbs. Shut it down -- not just delete it -- so a
> +	 * late completion cannot re-arm it after free_candev().
> +	 */
> +	timer_shutdown_sync(&pdev->restart_timer);
> +}

[Severity: Medium]
Can timer_shutdown_sync(&pdev->restart_timer) prevent a use-after-free if
pcan_usb_restart_pending() runs after free_candev()?

pdev->restart_timer is embedded in struct pcan_usb (allocated inside
netdev_priv()), so a late pcan_usb_restart_pending() calling
mod_timer(&pdev->restart_timer, ...) after free_candev() still
dereferences freed memory.

Also, in peak_usb_create_dev(), register_candev() is called before
dev_init() and dev_set_bus():

drivers/net/can/usb/peak_usb/pcan_usb_core.c:peak_usb_create_dev() {
    ...
	err = register_candev(netdev);
    ...
	if (dev->adapter->dev_init) {
		err = dev->adapter->dev_init(dev);
		if (err)
			goto lbl_unregister_candev;
	}

	/* set bus off */
	if (dev->adapter->dev_set_bus) {
		err = dev->adapter->dev_set_bus(dev, 0);
		if (err)
			goto adap_dev_free;
	}
    ...
adap_dev_free:
	if (dev->adapter->dev_free)
		dev->adapter->dev_free(dev);

lbl_unregister_candev:
	unregister_candev(netdev);
    ...
}

If the registered interface is brought up and triggers a restart while
probe is still running, a failure in pcan_usb_get_serial() inside
pcan_usb_init() jumps to lbl_unregister_candev and skips pcan_usb_free()
completely.  A failure in dev_set_bus() runs pcan_usb_free() before
unregister_candev(), and because probe failure does not call
usb_disable_interface() and peak_usb_unlink_all_urbs() does not kill the
unanchored restart URB, that URB can remain in flight across
free_candev().

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261109044911.1163505-1-hj351016@gmail.com?part=1

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

* Re: [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free
  2026-11-10  4:49 ` sashiko-bot
@ 2026-11-10  5:04   ` khj
  2026-11-10 18:35     ` Marc Kleine-Budde
  0 siblings, 1 reply; 5+ messages in thread
From: khj @ 2026-11-10  5:04 UTC (permalink / raw)
  To: sashiko-reviews
  Cc: linux-can, Marc Kleine-Budde, Oliver Hartkopp, Vincent Mailhol,
	Oleksij Rempel

Thanks for the review.

You're right that timer_shutdown_sync() alone is not sufficient. The
restart URB submitted in pcan_usb_restart() is not anchored, so
peak_usb_unlink_all_urbs() does not kill it, and its completion handler
pcan_usb_restart_pending() can still run after free_candev() and
dereference the freed pcan_usb via mod_timer(&pdev->restart_timer, ...).
Shutting the timer down does not help once the object backing it is gone.

So the complete fix has to stop that URB as well, not just the timer --
e.g. anchor the restart URB so peak_usb_unlink_all_urbs() kills it, and
also cover the probe-error paths you point out (dev_free() being skipped
on a pcan_usb_get_serial() failure, and running before unregister_candev()
on a dev_set_bus() failure, with the restart URB potentially still in
flight because probe failure does not unlink it).

Since that becomes a teardown reorganization in your driver, I'd rather
not guess at the shape. Marc, how would you prefer this handled -- anchor
the restart URB into one of the existing anchors (tx_submitted) or a
dedicated one, and should the register_candev()-before-dev_init() ordering
be part of the same change? I'm happy to send a v3 once the preferred
direction is clear.

Thanks,
Hyunjung

2026년 11월 10일 (화) 오후 1:49, <sashiko-bot@kernel.org>님이 작성:
>
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue to consider:
> - [Medium] can: peak_usb: unanchored restart URB and timer mishandled in
>   pcan_usb_free()
> --
>
> commit 5d0ce26d62347660cb47c1b9c3037c160879b961
> Author: Hyunjung Ko <hj351016@gmail.com>
>
> can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free
>
> This commit adds a dev_free callback to pcan_usb that calls
> timer_shutdown_sync() on pdev->restart_timer before freeing the device.
>
> > diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
> > index 8fd058c328564..113b2e7453310 100644
> > --- a/drivers/net/can/usb/peak_usb/pcan_usb.c
> > +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
> > @@ -882,6 +882,19 @@ static int pcan_usb_start(struct peak_usb_device *dev)
> >       return pcan_usb_set_ext_vcc(dev, 0);
> >  }
> >
> > +static void pcan_usb_free(struct peak_usb_device *dev)
> > +{
> > +     struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
> > +
> > +     /*
> > +      * The restart timer is armed from the restart-command URB completion
> > +      * (pcan_usb_restart_pending()), which is not anchored and so outlives
> > +      * ndo_stop/unlink_all_urbs. Shut it down -- not just delete it -- so a
> > +      * late completion cannot re-arm it after free_candev().
> > +      */
> > +     timer_shutdown_sync(&pdev->restart_timer);
> > +}
>
> [Severity: Medium]
> Can timer_shutdown_sync(&pdev->restart_timer) prevent a use-after-free if
> pcan_usb_restart_pending() runs after free_candev()?
>
> pdev->restart_timer is embedded in struct pcan_usb (allocated inside
> netdev_priv()), so a late pcan_usb_restart_pending() calling
> mod_timer(&pdev->restart_timer, ...) after free_candev() still
> dereferences freed memory.
>
> Also, in peak_usb_create_dev(), register_candev() is called before
> dev_init() and dev_set_bus():
>
> drivers/net/can/usb/peak_usb/pcan_usb_core.c:peak_usb_create_dev() {
>     ...
>         err = register_candev(netdev);
>     ...
>         if (dev->adapter->dev_init) {
>                 err = dev->adapter->dev_init(dev);
>                 if (err)
>                         goto lbl_unregister_candev;
>         }
>
>         /* set bus off */
>         if (dev->adapter->dev_set_bus) {
>                 err = dev->adapter->dev_set_bus(dev, 0);
>                 if (err)
>                         goto adap_dev_free;
>         }
>     ...
> adap_dev_free:
>         if (dev->adapter->dev_free)
>                 dev->adapter->dev_free(dev);
>
> lbl_unregister_candev:
>         unregister_candev(netdev);
>     ...
> }
>
> If the registered interface is brought up and triggers a restart while
> probe is still running, a failure in pcan_usb_get_serial() inside
> pcan_usb_init() jumps to lbl_unregister_candev and skips pcan_usb_free()
> completely.  A failure in dev_set_bus() runs pcan_usb_free() before
> unregister_candev(), and because probe failure does not call
> usb_disable_interface() and peak_usb_unlink_all_urbs() does not kill the
> unanchored restart URB, that URB can remain in flight across
> free_candev().
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20261109044911.1163505-1-hj351016@gmail.com?part=1

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

* Re: [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free
  2026-11-09  4:49 [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free hyunjungg
  2026-11-10  4:49 ` sashiko-bot
@ 2026-11-10 17:51 ` netdev-bot+sashiko
  1 sibling, 0 replies; 5+ messages in thread
From: netdev-bot+sashiko @ 2026-11-10 17:51 UTC (permalink / raw)
  To: hj351016
  Cc: mkl, linux-can, mailhol.vincent, kuba, netdev, linux-kernel,
	stable

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.

Critical: 0 · High: 2 · Medium: 0 · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [High] The fix is incomplete on the probe error path it claims to cover
  (the adap_dev_free label in peak_usb_create_dev()).
- [High] The dev_init() failure path in peak_usb_create_dev() skips the
  new dev_free() callback completely, so the restart timer is still…

--

can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free

This adds a pcan_usb dev_free callback that calls timer_shutdown_sync() on
pdev->restart_timer. The goal is to keep the restart timer from running
against a freed struct pcan_usb once free_candev() has run. The commit
message says this covers disconnect and the probe error path that reaches
the adap_dev_free label.

> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
> index 8fd058c328564..113b2e7453310 100644
> --- a/drivers/net/can/usb/peak_usb/pcan_usb.c
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
> @@ -882,6 +882,19 @@ static int pcan_usb_start(struct peak_usb_device *dev)
>  	return pcan_usb_set_ext_vcc(dev, 0);
>  }
>  
> +static void pcan_usb_free(struct peak_usb_device *dev)
> +{
> +	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
> +
> +	/*
> +	 * The restart timer is armed from the restart-command URB completion
> +	 * (pcan_usb_restart_pending()), which is not anchored and so outlives
> +	 * ndo_stop/unlink_all_urbs. Shut it down -- not just delete it -- so a
> +	 * late completion cannot re-arm it after free_candev().
> +	 */
> +	timer_shutdown_sync(&pdev->restart_timer);

[Severity: High]
Does this cover the adap_dev_free probe error path in peak_usb_create_dev()?
The commit message says it does.

On disconnect, usb_unbind_interface() calls usb_disable_interface() before
->disconnect(). That flushes the unanchored restart URB before dev_free()
and free_candev() run.

On probe failure, usb_probe_interface() takes its err: path, which does not
disable the interface endpoints. Nothing in peak_usb_create_dev() kills the
restart URB either:

drivers/net/can/usb/peak_usb/pcan_usb_core.c:peak_usb_create_dev() {
    ...
	if (dev->adapter->dev_set_bus) {
		err = dev->adapter->dev_set_bus(dev, 0);
		if (err)
			goto adap_dev_free;
	}
    ...
adap_dev_free:
	if (dev->adapter->dev_free)
		dev->adapter->dev_free(dev);

lbl_unregister_candev:
	unregister_candev(netdev);
    ...
lbl_free_candev:
	free_candev(netdev);
}

register_candev() has already run at this point, so can0 can be brought up.
A bus-off followed by auto-restart or a manual restart then reaches
peak_usb_restart()->pcan_usb_restart_async(). That submits the bus-on
command on EP_CMDOUT with urb->context = pdev. The URB is not anchored, so
peak_usb_unlink_all_urbs() never touches it.

If the device delays EP_CMDOUT, the synchronous dev_set_bus(dev, 0) queued
behind it can time out, and probe goes to adap_dev_free. When the restart
URB completes later (the device finally ACKs, or an unplug flushes it with
-ESHUTDOWN), we get:

pcan_usb_restart_pending()
    struct pcan_usb *pdev = urb->context;
    mod_timer(&pdev->restart_timer, ...);

and pdev has already been freed by free_candev().

timer_shutdown_sync() only makes mod_timer() a no-op while the timer_list
memory is still valid. Can it stop this write to freed memory? If not, the
comment above ("so a late completion cannot re-arm it after free_candev()")
does not hold on this path.

The commit message says "by which point the endpoint URBs have been flushed
by usb_disable_interface()". That also seems to apply to disconnect only.

There is also a smaller window on this path. dev_free() runs before
unregister_candev(), so the interface can stay up with a timer that has
been shut down. The only guard against a new submission is this check:

pcan_usb_restart_async()
	if (timer_pending(&pdev->restart_timer))
		return -EBUSY;

After shutdown that check is always false. Can new restart URBs be
submitted in that window that never reach peak_usb_restart_complete()?

Would anchoring the restart URB and killing that anchor before
free_candev() on every path be a better fix than relying on the timer
shutdown alone?

> +}
> +
>  static int pcan_usb_init(struct peak_usb_device *dev)
>  {
>  	struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
> @@ -1051,6 +1064,7 @@ const struct peak_usb_adapter pcan_usb = {
>  	.dev_decode_buf = pcan_usb_decode_buf,
>  	.dev_encode_msg = pcan_usb_encode_msg,
>  	.dev_start = pcan_usb_start,
> +	.dev_free = pcan_usb_free,

[Severity: High]
Does a dev_init() failure still leave the restart timer live at
free_candev()? In peak_usb_create_dev(), this path jumps past the
adap_dev_free label, so pcan_usb_free() is never called:

drivers/net/can/usb/peak_usb/pcan_usb_core.c:peak_usb_create_dev() {
    ...
	if (dev->adapter->dev_init) {
		err = dev->adapter->dev_init(dev);
		if (err)
			goto lbl_unregister_candev;
	}
    ...
}

pcan_usb_init() calls timer_setup() on restart_timer and then calls the
synchronous pcan_usb_get_serial(). That call can block for up to
PCAN_USB_COMMAND_TIMEOUT and then fail:

drivers/net/can/usb/peak_usb/pcan_usb.c:pcan_usb_init() {
    ...
	timer_setup(&pdev->restart_timer, pcan_usb_restart, 0);
    ...
	err = pcan_usb_get_serial(dev, &serial_number);
	if (err) {
		...
		return err;
	}
    ...
}

register_candev() has already run, so can0 can be brought up during that
window. A bus-off and restart can then submit the restart URB, and its
completion arms restart_timer.

When pcan_usb_get_serial() fails, unregister_candev() and free_candev() run
with no timer teardown. The timer may still be pending, or the restart URB
may still be in flight. If the timer fires,
pcan_usb_restart()->peak_usb_restart_complete() writes dev->can.state and
calls netif_wake_queue() on freed memory.

Should pcan_usb_init() shut down the timer (and kill the restart URB) on its
own error return? Alternatively, the core could call dev_free() on this path
too.

>  	.dev_restart_async = pcan_usb_restart_async,
>  	.do_get_berr_counter = pcan_usb_get_berr_counter,
>  };

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261109044911.1163505-1-hj351016%40gmail.com

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

* Re: [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free
  2026-11-10  5:04   ` khj
@ 2026-11-10 18:35     ` Marc Kleine-Budde
  0 siblings, 0 replies; 5+ messages in thread
From: Marc Kleine-Budde @ 2026-11-10 18:35 UTC (permalink / raw)
  To: khj
  Cc: sashiko-reviews, linux-can, Oliver Hartkopp, Vincent Mailhol,
	Oleksij Rempel, Stéphane Grosjean

[-- Attachment #1: Type: text/plain, Size: 1796 bytes --]

On 10.11.2026 14:04:08, khj wrote:
> You're right that timer_shutdown_sync() alone is not sufficient. The
> restart URB submitted in pcan_usb_restart() is not anchored, so
> peak_usb_unlink_all_urbs() does not kill it, and its completion handler
> pcan_usb_restart_pending() can still run after free_candev() and
> dereference the freed pcan_usb via mod_timer(&pdev->restart_timer, ...).
> Shutting the timer down does not help once the object backing it is gone.
>
> So the complete fix has to stop that URB as well, not just the timer --
> e.g. anchor the restart URB so peak_usb_unlink_all_urbs() kills it, and
> also cover the probe-error paths you point out (dev_free() being skipped
> on a pcan_usb_get_serial() failure, and running before unregister_candev()
> on a dev_set_bus() failure, with the restart URB potentially still in
> flight because probe failure does not unlink it).
>
> Since that becomes a teardown reorganization in your driver, I'd rather
> not guess at the shape. Marc, how would you prefer this handled -- anchor
> the restart URB into one of the existing anchors (tx_submitted) or a
> dedicated one, and should the register_candev()-before-dev_init() ordering
> be part of the same change? I'm happy to send a v3 once the preferred
> direction is clear.

Please discuss driver design with Stéphane Grosjean (Cc'ed). Your
patch/series should probably based on
https://lore.kernel.org/all/20261103-canfd_check_channel_idx-v8-0-4e8b2c0a8806@peak-system.fr/

regards,
Marc

-- 
Pengutronix e.K.                 | Marc Kleine-Budde          |
Embedded Linux                   | https://www.pengutronix.de |
Vertretung Nürnberg              | Phone: +49-5121-206917-129 |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-9   |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

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

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09  4:49 [PATCH v2] can: peak_usb: pcan_usb: shut down restart timer on free to avoid use-after-free hyunjungg
2026-11-10  4:49 ` sashiko-bot
2026-11-10  5:04   ` khj
2026-11-10 18:35     ` Marc Kleine-Budde
2026-11-10 17:51 ` netdev-bot+sashiko

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.