* [PATCH 0/4] gs_usb: fixes
@ 2026-10-25 18:35 Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 1/4] can: gs_usb: gs_can_start_xmit(): don't leak uninitialized memory over USB Marc Kleine-Budde
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-10-25 18:35 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick,
Maximilian Schneider, Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
Hello,
this series contains fixes for issues found by sashiko.
regards,
Marc
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
Marc Kleine-Budde (4):
can: gs_usb: gs_can_start_xmit(): don't leak uninitialized memory over USB
can: gs_usb: gs_usb_probe(): init netdev completely before register_candev()
can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails
can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish
drivers/net/can/usb/gs_usb.c | 67 +++++++++++++++++++++++++++++---------------
1 file changed, 45 insertions(+), 22 deletions(-)
---
base-commit: 734bef548a96e8774d6eef5dfa2026c6edc4e80b
base-tree: git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git main
change-id: 20261025-gs_usb-fixes-250f38833107
Best regards,
--
Marc Kleine-Budde <mkl@pengutronix.de>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/4] can: gs_usb: gs_can_start_xmit(): don't leak uninitialized memory over USB
2026-10-25 18:35 [PATCH 0/4] gs_usb: fixes Marc Kleine-Budde
@ 2026-10-25 18:35 ` Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 2/4] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev() Marc Kleine-Budde
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-10-25 18:35 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick,
Maximilian Schneider, Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
The driver allocates the transmission buffer using kmalloc(), which means
the memory remains uninitialized. Then various headers are filled and, but
only the actual CAN frame data payload (of length cfd->len or cf->len) is
copied into the buffer, leaving the remaining buffer uninitialized.
Fix this information leak, allocate the buffer with kzalloc().
Closes: https://sashiko.dev/#/bug/linux-0a8c0e8a-c623-426a-8db3-f55111f6cd84
Fixes: 26949ac935e3 ("can: gs_usb: add CAN-FD support")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 3b9b2f104d86..15f28833f2de 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -861,7 +861,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
if (!urb)
goto nomem_urb;
- hf = kmalloc(dev->hf_size_tx, GFP_ATOMIC);
+ hf = kzalloc(dev->hf_size_tx, GFP_ATOMIC);
if (!hf)
goto nomem_hf;
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev()
2026-10-25 18:35 [PATCH 0/4] gs_usb: fixes Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 1/4] can: gs_usb: gs_can_start_xmit(): don't leak uninitialized memory over USB Marc Kleine-Budde
@ 2026-10-25 18:35 ` Marc Kleine-Budde
2026-10-27 7:37 ` netdev-bot+sashiko
2026-10-25 18:35 ` [PATCH 3/4] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 4/4] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish Marc Kleine-Budde
3 siblings, 1 reply; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-10-25 18:35 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick,
Maximilian Schneider, Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
In gs_usb_probe(), gs_make_candev() is called to allocate and set up the
CAN channel, as well as to call register_candev(). However, gs_usb_probe()
defers the assignment of dev->parent and parent->hf_size_rx until after
gs_make_candev() returns. This opens a race window for the user space to
bring up the CAN interface, while it's not completely setup.
To close the race window, initialize all CAN interfaces in a first loop and
then register them in a second loop.
Closes: https://sashiko.dev/#/bug/linux-be54de7d-0b75-408c-b3ee-dd90c9756857
Closes: https://sashiko.dev/#/bug/linux-71076d59-0843-4749-a5ab-fdd98a08582f
Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 45 ++++++++++++++++++++++++++++----------------
1 file changed, 29 insertions(+), 16 deletions(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 15f28833f2de..985d6a9113d9 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -1490,18 +1490,8 @@ static struct gs_can *gs_make_candev(unsigned int channel,
can_rx_offload_add_manual(netdev, &dev->offload, GS_NAPI_WEIGHT);
SET_NETDEV_DEV(netdev, &intf->dev);
- rc = register_candev(dev->netdev);
- if (rc) {
- dev_err(&intf->dev,
- "Couldn't register candev for channel %d (%pe)\n",
- channel, ERR_PTR(rc));
- goto out_can_rx_offload_del;
- }
-
return dev;
-out_can_rx_offload_del:
- can_rx_offload_del(&dev->offload);
out_free_candev:
free_candev(dev->netdev);
return ERR_PTR(rc);
@@ -1593,14 +1583,14 @@ static int gs_usb_probe(struct usb_interface *intf,
/* save error code to return later */
rc = PTR_ERR(parent->canch[i]);
- /* on failure destroy previously created candevs */
+ /* on failure clean up previously created candevs */
icount = i;
- for (i = 0; i < icount; i++)
- gs_destroy_candev(parent->canch[i]);
+ for (i = 0; i < icount; i++) {
+ can_rx_offload_del(&parent->canch[i]->offload);
+ free_candev(parent->canch[i]->netdev);
+ }
- usb_kill_anchored_urbs(&parent->rx_submitted);
- kfree(parent);
- return rc;
+ goto out_usb_kill_anchored_urbs;
}
parent->canch[i]->parent = parent;
@@ -1621,7 +1611,30 @@ static int gs_usb_probe(struct usb_interface *intf,
parent->hf_size_rx = max(parent->hf_size_rx, hf_size_rx);
}
+ for (i = 0; i < icount; i++) {
+ struct gs_can *dev = parent->canch[i];
+
+ rc = register_candev(dev->netdev);
+ if (rc) {
+ dev_err(&intf->dev,
+ "Couldn't register candev for channel %d (%pe)\n",
+ i, ERR_PTR(rc));
+
+ icount = i;
+ for (i = 0; i < icount; i++)
+ gs_destroy_candev(parent->canch[i]);
+
+ goto out_usb_kill_anchored_urbs;
+ }
+ }
+
return 0;
+
+out_usb_kill_anchored_urbs:
+ usb_kill_anchored_urbs(&parent->rx_submitted);
+ kfree(parent);
+
+ return rc;
}
static void gs_usb_disconnect(struct usb_interface *intf)
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/4] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails
2026-10-25 18:35 [PATCH 0/4] gs_usb: fixes Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 1/4] can: gs_usb: gs_can_start_xmit(): don't leak uninitialized memory over USB Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 2/4] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev() Marc Kleine-Budde
@ 2026-10-25 18:35 ` Marc Kleine-Budde
2026-10-27 7:37 ` netdev-bot+sashiko
2026-10-25 18:35 ` [PATCH 4/4] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish Marc Kleine-Budde
3 siblings, 1 reply; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-10-25 18:35 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick,
Maximilian Schneider, Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
If the allocation of an SKB fails in gs_usb_receive_bulk_callback(), the
function neither updates the statistics nor checks whether an overflow flag
is set in the host frame.
Instead of directly resubmitting the URB, first update the dropped RX
statistics then check if an overflow flag is set.
Closes: https://sashiko.dev/#/bug/linux-7b3fe6a0-4628-4d0e-aec0-69f4bf8ad5d4
Fixes: 68c5724ecd15 ("can: gs_usb: gs_usb_receive_bulk_callback(): resubmit URB on skb allocation failure")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 985d6a9113d9..5687544af99c 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -673,8 +673,12 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX) { /* normal rx */
if (hf->flags & GS_CAN_FLAG_FD) {
skb = alloc_canfd_skb(netdev, &cfd);
- if (!skb)
- goto resubmit_urb;
+ if (!skb) {
+ netdev->stats.rx_dropped++;
+ netdev->stats.rx_errors++;
+
+ goto check_overflow;
+ }
cfd->can_id = le32_to_cpu(hf->can_id);
cfd->len = data_length;
@@ -686,8 +690,12 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
memcpy(cfd->data, hf->canfd->data, data_length);
} else {
skb = alloc_can_skb(netdev, &cf);
- if (!skb)
- goto resubmit_urb;
+ if (!skb) {
+ netdev->stats.rx_dropped++;
+ netdev->stats.rx_errors++;
+
+ goto check_overflow;
+ }
cf->can_id = le32_to_cpu(hf->can_id);
can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
@@ -728,6 +736,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
netif_wake_queue(netdev);
}
+check_overflow:
if (hf->flags & GS_CAN_FLAG_OVERFLOW) {
stats->rx_over_errors++;
stats->rx_errors++;
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 4/4] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish
2026-10-25 18:35 [PATCH 0/4] gs_usb: fixes Marc Kleine-Budde
` (2 preceding siblings ...)
2026-10-25 18:35 ` [PATCH 3/4] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails Marc Kleine-Budde
@ 2026-10-25 18:35 ` Marc Kleine-Budde
3 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-10-25 18:35 UTC (permalink / raw)
To: Vincent Mailhol, Peter Fink, Eric Evenchick,
Maximilian Schneider, Wolfgang Grandegger
Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde, stable
If the overflow flag is set for a host frame and the allocation of the
error SKB fails, the URB should not be resubmitted immediately.
Instead, call can_rx_offload_irq_finish(), since an SKB may have been added
to rx-offload.
Closes: https://sashiko.dev/#/bug/linux-441137e2-cd75-411f-9ff5-dc4d473c5ddb
Fixes: 24bc41b45583 ("can: gs_usb: convert to NAPI/rx-offload to avoid OoO reception")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
drivers/net/can/usb/gs_usb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 5687544af99c..4635bb60e14b 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -743,7 +743,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
skb = alloc_can_err_skb(netdev, &cf);
if (!skb)
- goto resubmit_urb;
+ goto can_rx_offload_irq_finish;
cf->can_id |= CAN_ERR_CRTL;
cf->len = CAN_ERR_DLC;
@@ -752,6 +752,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
gs_usb_rx_offload(dev, skb, hf);
}
+can_rx_offload_irq_finish:
can_rx_offload_irq_finish(&dev->offload);
resubmit_urb:
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev()
2026-10-25 18:35 ` [PATCH 2/4] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev() Marc Kleine-Budde
@ 2026-10-27 7:37 ` netdev-bot+sashiko
2026-10-27 9:26 ` Marc Kleine-Budde
0 siblings, 1 reply; 8+ messages in thread
From: netdev-bot+sashiko @ 2026-10-27 7:37 UTC (permalink / raw)
To: mkl
Cc: mailhol, pfink, eric, max, wg, kernel, linux-can, linux-kernel,
stable, kuba
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 1 (1) · 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] This patch adds a memory leak to the gs_usb_probe() error path
in drivers/net/can/usb/gs_usb.c.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but the
gs_usb_probe() register-failure path keeps an existing use-after-free.
--
can: gs_usb: gs_usb_probe(): init netdev completely before register_candev()
This patch moves register_candev() out of gs_make_candev() and into a
second loop in gs_usb_probe(). Every channel, including dev->parent and
parent->hf_size_rx, is now fully set up before any channel is registered.
This closes the window where userspace could bring up a partially
initialized CAN interface.
Closes: https://sashiko.dev/#/bug/linux-be54de7d-0b75-408c-b3ee-dd90c9756857
Closes: https://sashiko.dev/#/bug/linux-71076d59-0843-4749-a5ab-fdd98a08582f
> diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
> index 15f28833f2deb..985d6a9113d96 100644
> --- a/drivers/net/can/usb/gs_usb.c
> +++ b/drivers/net/can/usb/gs_usb.c
> @@ -1490,18 +1490,8 @@ static struct gs_can *gs_make_candev(unsigned int channel,
> can_rx_offload_add_manual(netdev, &dev->offload, GS_NAPI_WEIGHT);
> SET_NETDEV_DEV(netdev, &intf->dev);
>
> - rc = register_candev(dev->netdev);
> - if (rc) {
> - dev_err(&intf->dev,
> - "Couldn't register candev for channel %d (%pe)\n",
> - channel, ERR_PTR(rc));
> - goto out_can_rx_offload_del;
> - }
> -
> return dev;
>
> -out_can_rx_offload_del:
> - can_rx_offload_del(&dev->offload);
> out_free_candev:
> free_candev(dev->netdev);
> return ERR_PTR(rc);
> @@ -1593,14 +1583,14 @@ static int gs_usb_probe(struct usb_interface *intf,
> /* save error code to return later */
> rc = PTR_ERR(parent->canch[i]);
>
> - /* on failure destroy previously created candevs */
> + /* on failure clean up previously created candevs */
> icount = i;
> - for (i = 0; i < icount; i++)
> - gs_destroy_candev(parent->canch[i]);
> + for (i = 0; i < icount; i++) {
> + can_rx_offload_del(&parent->canch[i]->offload);
> + free_candev(parent->canch[i]->netdev);
> + }
>
> - usb_kill_anchored_urbs(&parent->rx_submitted);
> - kfree(parent);
> - return rc;
> + goto out_usb_kill_anchored_urbs;
> }
> parent->canch[i]->parent = parent;
>
[ ... ]
> @@ -1621,7 +1611,30 @@ static int gs_usb_probe(struct usb_interface *intf,
> parent->hf_size_rx = max(parent->hf_size_rx, hf_size_rx);
> }
>
> + for (i = 0; i < icount; i++) {
> + struct gs_can *dev = parent->canch[i];
> +
> + rc = register_candev(dev->netdev);
> + if (rc) {
> + dev_err(&intf->dev,
> + "Couldn't register candev for channel %d (%pe)\n",
> + i, ERR_PTR(rc));
> +
> + icount = i;
> + for (i = 0; i < icount; i++)
> + gs_destroy_candev(parent->canch[i]);
[Severity: High]
Does this leak the candevs for channel i and every channel after it?
The second loop only runs after the first loop has called gs_make_candev()
for all channels. At that point every canch[] entry holds an allocated
netdev with rx-offload attached.
When register_candev() fails for channel i, only canch[0..i-1] go through
gs_destroy_candev(). Channels canch[i] through canch[channel_cnt - 1] never
get can_rx_offload_del() or free_candev().
The kfree(parent) at out_usb_kill_anchored_urbs then frees canch[], which
held the only pointers to those netdevs.
Before this patch, gs_make_candev() cleaned up its own channel when
register_candev() failed, and no later channels had been allocated yet.
The USB device can trigger this. register_candev() returns -EINVAL when
can_bittiming_const_valid() fails:
drivers/net/can/dev/dev.c:can_bittiming_const_valid() {
...
if (!btc->sjw_max)
return false;
...
}
gs_make_candev() copies sjw_max straight from the device's
GS_USB_BREQ_BT_CONST reply. A device that reports sjw_max == 0 for channel
0 would leak every channel on each probe.
Should this error path also run can_rx_offload_del() and free_candev() on
channels i through channel_cnt - 1, the same teardown the first loop's
error path uses?
> +
> + goto out_usb_kill_anchored_urbs;
> + }
> + }
> +
> return 0;
> +
> +out_usb_kill_anchored_urbs:
> + usb_kill_anchored_urbs(&parent->rx_submitted);
> + kfree(parent);
> +
> + return rc;
> }
[Severity: High]
This isn't a bug introduced by this patch, but can this teardown order
cause a use-after-free in gs_usb_receive_bulk_callback()?
The old gs_make_candev() failure path had the same pattern. Registered
channels 0..i-1 are destroyed one at a time, and gs_destroy_candev() frees
each netdev right after unregistering it. The freed pointers stay in
parent->canch[].
The shared RX URBs are only killed when the last active channel closes:
gs_can_close() {
...
parent->active_channels--;
if (!parent->active_channels) {
usb_kill_anchored_urbs(&parent->rx_submitted);
...
}
The only other place they are killed is out_usb_kill_anchored_urbs, which
runs after the whole destroy loop.
Suppose userspace has already brought up canch[0] and canch[1] when
register_candev() fails for a later channel. Unregistering canch[0] closes
it, but active_channels is still 1, so the RX URBs keep running after
canch[0] is freed.
If the device then sends a frame with hf->channel == 0, the callback
dereferences the freed entry:
gs_usb_receive_bulk_callback() {
...
dev = parent->canch[hf->channel];
netdev = dev->netdev;
stats = &netdev->stats;
if (!netif_device_present(netdev))
...
}
A frame with an out-of-range channel id goes to the device_detach label
instead. That code calls netif_device_detach() on every non-NULL canch[]
entry, which writes to the state field of the freed netdev.
The window is shorter now that no USB control messages run between
registrations, but the ordering is the same. gs_usb_disconnect() is not
affected, because usb_unbind_interface() disables the interface before it
calls disconnect.
Would it help to unregister all the registered channels first, so the last
close stops the shared RX URBs, and only then free them?
>
> static void gs_usb_disconnect(struct usb_interface *intf)
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261025-gs_usb-fixes-v1-0-f74ebbd4da36%40pengutronix.de
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/4] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails
2026-10-25 18:35 ` [PATCH 3/4] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails Marc Kleine-Budde
@ 2026-10-27 7:37 ` netdev-bot+sashiko
0 siblings, 0 replies; 8+ messages in thread
From: netdev-bot+sashiko @ 2026-10-27 7:37 UTC (permalink / raw)
To: mkl
Cc: mailhol, pfink, eric, max, wg, kernel, linux-can, linux-kernel,
stable, kuba
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 (1) · Low: 0 (1)
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).
- [Medium] In gs_usb_receive_bulk_callback()
(drivers/net/can/usb/gs_usb.c), both new SKB-allocation-failure…
Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but in
gs_usb_receive_bulk_callback() (drivers/net/can/usb/gs_usb.c) the…
- [Low] At this commit, the check_overflow block in
gs_usb_receive_bulk_callback() (drivers/net/can/usb/gs_usb.c:744-746)…
--
can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails
This commit changes the alloc_can_skb() and alloc_canfd_skb() failure
paths in gs_usb_receive_bulk_callback(). They now update the RX statistics
and jump to a new check_overflow label instead of resubmitting the URB
directly. As a result, GS_CAN_FLAG_OVERFLOW in the host frame is still
handled when the SKB allocation fails.
Closes: https://sashiko.dev/#/bug/linux-7b3fe6a0-4628-4d0e-aec0-69f4bf8ad5d4
> diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
> index 985d6a9113d96..5687544af99c8 100644
> --- a/drivers/net/can/usb/gs_usb.c
> +++ b/drivers/net/can/usb/gs_usb.c
> @@ -673,8 +673,12 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
> if (hf->echo_id == GS_HOST_FRAME_ECHO_ID_RX) { /* normal rx */
> if (hf->flags & GS_CAN_FLAG_FD) {
> skb = alloc_canfd_skb(netdev, &cfd);
> - if (!skb)
> - goto resubmit_urb;
> + if (!skb) {
> + netdev->stats.rx_dropped++;
> + netdev->stats.rx_errors++;
> +
> + goto check_overflow;
> + }
[Severity: Medium]
The commit message says "first update the dropped RX statistics". However,
both new allocation failure branches (CAN FD here, and Classical CAN in the
next hunk) also increment rx_errors. Is rx_errors the right counter for a
host-side allocation failure?
The kernel-doc for struct rtnl_link_stats64 in include/uapi/linux/if_link.h
defines the two counters like this:
* @rx_errors: Total number of bad packets received on this network device.
...
* @rx_dropped: Number of packets received but not processed,
* e.g. due to lack of resources or unsupported protocol.
In this path the frame arrived intact and only the SKB allocation on the
host failed.
Other CAN drivers that handle an alloc_can_skb() or alloc_canfd_skb()
failure count only rx_dropped. Examples are m_can.c, c_can_main.c,
mcp251xfd-rx.c, kvaser_usb_hydra.c and es58x_core.c. The shared rx-offload
helper also leaves rx_errors alone:
drivers/net/can/dev/rx-offload.c:can_rx_offload_offload_one() {
...
if (IS_ERR(skb)) {
offload->dev->stats.rx_dropped++;
offload->dev->stats.rx_fifo_errors++;
...
}
With this change, would memory pressure on the host show up as RX errors
on a gs_usb interface? Those would look like bus or controller faults, and
the change would reach stable through the Cc: stable tag.
A minor point: the new lines use netdev->stats directly, while the rest of
gs_usb_receive_bulk_callback() uses the local stats pointer.
>
> cfd->can_id = le32_to_cpu(hf->can_id);
> cfd->len = data_length;
> @@ -686,8 +690,12 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
> memcpy(cfd->data, hf->canfd->data, data_length);
> } else {
> skb = alloc_can_skb(netdev, &cf);
> - if (!skb)
> - goto resubmit_urb;
> + if (!skb) {
> + netdev->stats.rx_dropped++;
> + netdev->stats.rx_errors++;
> +
> + goto check_overflow;
> + }
>
> cf->can_id = le32_to_cpu(hf->can_id);
> can_frame_set_cc_len(cf, hf->can_dlc, dev->can.ctrlmode);
[Severity: Medium]
This isn't a bug introduced by this patch, but the Classical CAN error
frame handling is still skipped when alloc_can_skb() fails. A little
further down, after the allocation succeeds:
/* ERROR frames tell us information about the controller */
if (le32_to_cpu(hf->can_id) & CAN_ERR_FLAG)
gs_update_state(dev, cf);
gs_update_state() is the only place where controller state reported by the
device reaches dev->can.state and can_stats (restarts, bus_off,
error_warning, error_passive). It reads cf->can_id and cf->data[1], and the
same values are available in hf->can_id and hf->classic_can->data[1].
An error frame can carry a BUS_OFF, RESTARTED, warning or passive
transition. If one arrives while alloc_can_skb() fails, the goto
check_overflow skips the state update. Can dev->can.state then stay stale
until another state change frame arrives and its allocation succeeds?
Some peer drivers update controller state even when the error SKB
allocation fails. For example, esd_usb.c does:
skb = alloc_can_err_skb(priv->netdev, &cf);
if (!skb)
stats->rx_dropped++;
if (state != priv->old_state) {
The original return, and the later goto resubmit_urb from commit
68c5724ecd15, also skipped this update. The patch does not address it.
[ ... ]
> @@ -728,6 +736,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
> netif_wake_queue(netdev);
> }
>
> +check_overflow:
> if (hf->flags & GS_CAN_FLAG_OVERFLOW) {
> stats->rx_over_errors++;
> stats->rx_errors++;
[Severity: Low]
This is a pre-existing issue, but at this commit the overflow block
continues like this:
skb = alloc_can_err_skb(netdev, &cf);
if (!skb)
goto resubmit_urb;
...
}
can_rx_offload_irq_finish(&dev->offload);
resubmit_urb:
If alloc_can_err_skb() fails, this path skips
can_rx_offload_irq_finish(). An RX SKB queued earlier in the same callback
by gs_usb_rx_offload(), or an echo SKB queued by gs_usb_get_echo_skb(),
then stays on offload->skb_irq_queue. NAPI is not scheduled until a later
URB completion calls irq_finish.
On the new allocation failure paths added here, nothing has been queued
before check_overflow, so this patch does not make the delay worse.
The next patch in this series, "can: gs_usb:
gs_usb_receive_bulk_callback(): add missing call to
can_rx_offload_irq_finish", changes this to goto can_rx_offload_irq_finish
and adds a matching label, which fixes the skipped irq_finish.
One part is not covered by that patch: when alloc_can_err_skb() fails,
rx_dropped is not incremented for the lost overflow error frame. The
overflow event itself is still counted in rx_over_errors and rx_errors.
Should rx_dropped be incremented here as well?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261025-gs_usb-fixes-v1-0-f74ebbd4da36%40pengutronix.de
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev()
2026-10-27 7:37 ` netdev-bot+sashiko
@ 2026-10-27 9:26 ` Marc Kleine-Budde
0 siblings, 0 replies; 8+ messages in thread
From: Marc Kleine-Budde @ 2026-10-27 9:26 UTC (permalink / raw)
To: netdev-bot+sashiko
Cc: mailhol, pfink, eric, max, wg, kernel, linux-can, linux-kernel,
stable, kuba
[-- Attachment #1: Type: text/plain, Size: 977 bytes --]
On 27.10.2026 07:37:27, netdev-bot+sashiko@kernel.org wrote:
> A frame with an out-of-range channel id goes to the device_detach label
> instead. That code calls netif_device_detach() on every non-NULL canch[]
> entry, which writes to the state field of the freed netdev.
>
> The window is shorter now that no USB control messages run between
> registrations, but the ordering is the same. gs_usb_disconnect() is not
> affected, because usb_unbind_interface() disables the interface before it
> calls disconnect.
>
> Would it help to unregister all the registered channels first, so the last
> close stops the shared RX URBs, and only then free them?
Will be fixed in v5.
pw-bot: cr
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] 8+ messages in thread
end of thread, other threads:[~2026-10-27 9:26 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-25 18:35 [PATCH 0/4] gs_usb: fixes Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 1/4] can: gs_usb: gs_can_start_xmit(): don't leak uninitialized memory over USB Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 2/4] can: gs_usb: gs_usb_probe(): init netdev completely before register_candev() Marc Kleine-Budde
2026-10-27 7:37 ` netdev-bot+sashiko
2026-10-27 9:26 ` Marc Kleine-Budde
2026-10-25 18:35 ` [PATCH 3/4] can: gs_usb: gs_usb_receive_bulk_callback(): check for overflow flag if SKB allocation fails Marc Kleine-Budde
2026-10-27 7:37 ` netdev-bot+sashiko
2026-10-25 18:35 ` [PATCH 4/4] can: gs_usb: gs_usb_receive_bulk_callback(): add missing call to can_rx_offload_irq_finish Marc Kleine-Budde
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®