Linux CAN drivers development
 help / color / mirror / Atom feed
* [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening
@ 2026-10-30 10:44 Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 01/13] can: peak_usb: fix missing CAN_ERR_FLAG when reporting error counters Stéphane Grosjean via B4 Relay
                   ` (12 more replies)
  0 siblings, 13 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani, Stefan Günther,
	stable

This series contains bug fixes, cleanups and input validation
improvements for the PEAK-System USB CAN drivers.

Patch 1 fixes CAN error frame generation, where CAN_ERR_CNT overwrote
previously set CAN error flags.

Patches 2, 3 and 5 are cleanups: make a public header self-contained,
sort the CAN_CTRLMODE_* flags in ctrlmode_supported, and replace
open-coded bitmask operations with bitops. Patch 5 also makes the
state flag updates atomic, which patch 6 relies on.

Patch 4 adds bounds checks to the PCAN-USB RX parser, so that
truncated or malformed records are rejected instead of being read
beyond the received data.

Patch 6 validates the channel numbers received from PCAN-USB FD
devices, rejects records for channels that are not set up, and stops
RX on all channels before they are released, on disconnect as well as
on probe failure.

Patch 7 fixes the RX parsing of self-received RTR frames with SRR set,
which left the RX cursor one byte behind.

Patches 8 and 9 fix related issues found while reviewing the above:
the same channel slot check in the PCAN-USB Pro driver, and the netdevs
being registered before their channels are initialized.

Patches 10 and 11 add the missing validation of the data received from
PCAN-USB Pro devices: the data length of the CAN frames, and the record
count of the messages, which could make the decoders read past the
received data.

Patch 12 stops dumping stale RX buffer bytes on decode errors, dumps an
undecodable URB only once, and rate limits the decode error messages.

Patch 13 fixes an uninitialized stack byte that could be returned to
userspace as the PCAN-USB CAN channel ID.

---
Changes in v7:
- Patch 3: also sort the flags added to ctrlmode_supported at runtime
  in pcan_usb_init().
  Found by Sashiko AI review on v6:
  https://lore.kernel.org/r/179281433115.3130.15136732593858786026@kernel.org
- Patch 6: on probe failure, also stop RX on the channel being probed,
  which may already be open at this point of the series, and not only on
  its previous siblings, as the comment of peak_usb_stop_rx() says. The
  remaining use-after-free on this path is pre-existing and fixed by
  patch 9.
  Found by Sashiko AI review on v6:
  https://lore.kernel.org/r/179281433224.3130.6010222623227756144@kernel.org
- Patch 9: don't log "can%d removed" for channels that were created but
  never registered, when probing fails. Commit message: the RX of the
  channels already registered is still stopped if registering a later
  one fails.
  Found by Sashiko AI review on v6:
  https://lore.kernel.org/r/179281433446.3130.6290059781976829176@kernel.org
- Patch 11: commit message only: describe what the old
  pcan_usb_pro_wait_rsp() code could actually do (accept a truncated
  response and return stale request bytes as the channel id), instead of
  walking past the command buffer, which the current callers prevent.
  Found by Sashiko AI review on v6:
  https://lore.kernel.org/r/179281433565.3130.14307625292135673040@kernel.org
- Patch 3: add the Assisted-by: tag.
- Not changed, after review of v6:
  - PCAN-USB restart timer not stopped before free_candev() (reported
    on patch 9): this is fixed by Tristan Madani's patch, which is
    independent of this series and applies on top of it:
    https://lore.kernel.org/r/20261025210256.629830-1-tristan@talencesecurity.com
  - patch 8: the pre-existing NULL usb_if dereference and use-after-free
    on the probe error path are fixed by patch 9; a record for an unset
    channel still stops the decoding of the URB, and can no longer
    happen once patch 9 is applied, while patch 12 rate limits the dump;
  - patches 6 and 9: bus-off not sent to a still attached device when
    CONNECTED is cleared before unregister_candev() (probe failure with
    an opened channel, unbind): pre-existing, left for the separate
    series announced in v6, together with the netdev_err() messages of
    the command helpers during probe.
- Tested on PCAN-USB Pro FD, PCAN-USB Pro and PCAN-USB plugged on the
  same hub, with the driver of this series built against v7.0: probe,
  hot unplug and re-plug of the PCAN-USB Pro FD and of the PCAN-USB
  with their interfaces up (one "removed" message per registered
  channel), module removal with all the interfaces up. The probe error
  path that skips the message for unregistered netdevs was not
  exercised.
- Link to v6: https://lore.kernel.org/r/20261022-canfd_check_channel_idx-v6-0-197704231551@peak-system.fr

Changes in v6:
- Patch 6: clear CONNECTED under RTNL in peak_usb_stop_rx(), so that it
  is serialized with peak_usb_ndo_open(): no RX URB can be anchored but
  not yet submitted when the RX anchors are poisoned, which made
  usb_poison_anchored_urbs() busy-wait.
  Found by Sashiko AI review on v5:
  https://sashiko.dev/#/patchset/20261020-canfd_check_channel_idx-v5-0-a62b35b867f0@peak-system.fr?part=6
- Patch 7: update rx_bytes together with rx_packets, once the SRR byte
  has been checked, so that a frame dropped because this byte is
  missing is not counted.
  Found by Sashiko AI review on v5:
  https://sashiko.dev/#/patchset/20261020-canfd_check_channel_idx-v5-0-a62b35b867f0@peak-system.fr?part=7
- Patch 4: add Cc: stable, since patch 7, which is tagged for stable,
  relies on the bounds check it adds.
  Found by Sashiko AI review on v3:
  https://lore.kernel.org/r/179262353124.3131.13235647451945152794@kernel.org
- New patches 10 and 11: validate the data length of PCAN-USB Pro CAN
  records, and don't read past the received message in the PCAN-USB Pro
  decoders. Pre-existing issues found by Sashiko AI review on v3 to v5:
  https://lore.kernel.org/r/179264019905.3131.17443314322038603114@kernel.org
- Patch 12 (was 10): also remove the dumps done by the PCAN-USB Pro and
  FD decoders, which dumped the same URB a second time without any rate
  limit, and rate limit the decode error messages. New subject.
  Found by Sashiko AI review on v3 to v5:
  https://lore.kernel.org/r/179264020123.3131.12155600294986434879@kernel.org
- New patch 13: don't return an uninitialized PCAN-USB CAN channel ID.
  Pre-existing issue found by Sashiko AI review on v5:
  https://lore.kernel.org/r/179264020017.3131.2617691177294766125@kernel.org
- Patches 6 to 13: add the Assisted-by: tag, as required by
  Documentation/process/coding-assistants.rst.
- Not changed, after review:
  - patch 8: a record for an unset channel still stops the decoding of
    the URB, as the other malformed records do, and as in patch 6. This
    can no longer happen once patch 9 is applied;
  - PCAN-USB with CC_LEN8_DLC (reported on v3): checked on hardware
    (firmware 8.6.1), the device puts DLC data bytes in the records with
    a DLC of 9 to 15, so advancing the RX cursor by the DLC is correct;
  - the other pre-existing issues reported on v5 (asynchronous restart
    URBs and PCAN-USB restart timer not drained on disconnect, bus-off
    not sent on unbind, driver-loaded state not cleared on probe
    failure) will be addressed in a separate series;
  - patch 9: the "can%d removed" message logged on probe failure, and
    the netdev_err() messages of the command helpers during probe, are
    left as they are: they are cosmetic, and will be dealt with in that
    separate series.
- Tested on PCAN-USB, PCAN-USB Pro and PCAN-USB Pro FD on the same bus:
  probe, ethtool -e, reception of Classical CAN data and RTR frames of
  all lengths, of len8_dlc frames, and of back-to-back bursts, module
  removal with all the interfaces up, hot unplug of the PCAN-USB Pro and
  of the PCAN-USB Pro FD during RX and TX traffic. The new error paths
  of patches 10 to 13 were not exercised, since they need a malformed
  device.
- Link to v5: https://lore.kernel.org/r/20261020-canfd_check_channel_idx-v5-0-a62b35b867f0@peak-system.fr

Changes in v5:
- Register the netdevs only once all the channels of the interface are
  initialized, since they share resources during the init of a sibling
  (patch 9).
- Link to v4: https://lore.kernel.org/r/20261020-canfd_check_channel_idx-v4-0-bfbde81f8bab@peak-system.fr

Changes in v4:
- Register the netdev only once the channel is initialized, instead of
  only reordering unregister_candev() and dev_free() on probe failure
  (patch 9).
- Link to v3: https://lore.kernel.org/r/20261020-canfd_check_channel_idx-v3-0-74d17c5a599e@peak-system.fr

Changes in v3:
- Fix out-of-bounds read of the error counters in PCAN-USB bus events.
- Harden channel handling in PCAN-USB FD: publish/read channel slots
  with smp_store_release()/READ_ONCE(), clear them on teardown, stop RX
  on all channels on disconnect and on the siblings on probe failure,
  and reject ndo_open() once disconnected.
- Fix RX cursor desync for self-received RTR frames with SRR.
- Replace open-coded bitmask operations with bitops.
- Add channel slot checks to PCAN-USB Pro.
- Unregister the netdev before dev_free() on probe failure.
- Only dump received bytes, rate limited, on decode error.
- Link to v2: https://patch.msgid.link/20261009-canfd_check_channel_idx-v2-0-f7b772929791@peak-system.fr

Changes in v2:
- Kill all pending RX URBs before unregistering sibling netdevs.
- Reject records targeting unavailable channels during device
  initialization in rare corner cases involving malformed device
  input.
- Link to v1: https://patch.msgid.link/20261008-canfd_check_channel_idx-v1-0-0a3bb82f4e09@peak-system.fr

---
Marc Kleine-Budde (1):
      can: peak_usb: add missing includes

Stefan Günther (1):
      can: peak_usb: fix missing CAN_ERR_FLAG when reporting error counters

Stéphane Grosjean (11):
      can: peak_usb: sort ctrlmode_supported flags
      can: peak_usb: harden PCAN-USB message validation
      can: peak_usb: replace open-coded bitmask operations with bitops
      can: peak_usb: harden channel handling in PCAN-USB FD
      can: peak_usb: fix RX cursor desync for self-received RTR frames with SRR
      can: peak_usb: reject records for unset channels in PCAN-USB Pro
      can: peak_usb: register the netdevs only once all channels are set up
      can: peak_usb: validate the data length of PCAN-USB Pro CAN records
      can: peak_usb: don't read past the message in PCAN-USB Pro decoders
      can: peak_usb: dump undecodable URBs once and rate limit decode errors
      can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID

 drivers/net/can/usb/peak_usb/pcan_usb.c      |  70 +++++++++------
 drivers/net/can/usb/peak_usb/pcan_usb_core.c | 105 +++++++++++++++++------
 drivers/net/can/usb/peak_usb/pcan_usb_core.h |  16 +++-
 drivers/net/can/usb/peak_usb/pcan_usb_fd.c   | 123 ++++++++++++++++++---------
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c  |  86 +++++++++++++------
 5 files changed, 276 insertions(+), 124 deletions(-)
---
base-commit: a7bfaba4823e3c165bb2004c74eff7c096672bc7
change-id: 20261007-canfd_check_channel_idx-a4d7a1a1ee7d

Best regards,
-- 
Stéphane Grosjean <s.grosjean@peak-system.fr>



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

* [PATCH v7 01/13] can: peak_usb: fix missing CAN_ERR_FLAG when reporting error counters
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 02/13] can: peak_usb: add missing includes Stéphane Grosjean via B4 Relay
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani, Stefan Günther,
	stable

From: Stefan Günther <stefangun@pm.me>

When the device reports error counters, the driver incorrectly uses an
assignment (=) instead of a bitwise OR (|=) for CAN_ERR_CNT. This wipes
out the CAN_ERR_FLAG and CAN_ERR_CRTL flags, causing the error frame to
be sent to userspace as a regular CAN frame with ID 0x200.

Fix this by using a bitwise OR to preserve the flags.

Signed-off-by: Stefan Günther <stefangun@pm.me>
Cc: stable@vger.kernel.org
Fixes: 3e5c291c7942 ("can: add CAN_ERR_CNT flag to notify availability of error counter")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 8fd058c32856..785224e00c4e 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -526,7 +526,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
 			/* Supply TX/RX error counters in case of
 			 * controller error.
 			 */
-			cf->can_id = CAN_ERR_CNT;
+			cf->can_id |= CAN_ERR_CNT;
 			cf->data[6] = mc->pdev->bec.txerr;
 			cf->data[7] = mc->pdev->bec.rxerr;
 		}

-- 
2.53.0



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

* [PATCH v7 02/13] can: peak_usb: add missing includes
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 01/13] can: peak_usb: fix missing CAN_ERR_FLAG when reporting error counters Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 03/13] can: peak_usb: sort ctrlmode_supported flags Stéphane Grosjean via B4 Relay
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Marc Kleine-Budde <mkl@pengutronix.de>

To make the header self contained, so that LSP servers don't throw errors,
make the header file self contained and include all needed header files.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/usb/peak_usb/pcan_usb_core.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
index 65999f04f4b7..9ad7d31d2720 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
@@ -11,6 +11,12 @@
 #ifndef PCAN_USB_CORE_H
 #define PCAN_USB_CORE_H
 
+#include <linux/can/dev.h>
+#include <linux/can/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/usb.h>
+
 /* PEAK-System vendor id. */
 #define PCAN_USB_VENDOR_ID		0x0c72
 

-- 
2.53.0



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

* [PATCH v7 03/13] can: peak_usb: sort ctrlmode_supported flags
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 01/13] can: peak_usb: fix missing CAN_ERR_FLAG when reporting error counters Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 02/13] can: peak_usb: add missing includes Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 04/13] can: peak_usb: harden PCAN-USB message validation Stéphane Grosjean via B4 Relay
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

Order the CAN_CTRLMODE_* flags in ctrlmode_supported according to
their numerical values.

This is a cosmetic change only and does not alter the driver
behavior.

Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c     |  7 ++++---
 drivers/net/can/usb/peak_usb/pcan_usb_fd.c  | 32 ++++++++++++++++++-----------
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c |  3 ++-
 3 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 785224e00c4e..afe5e68d5ea3 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -915,8 +915,8 @@ static int pcan_usb_init(struct peak_usb_device *dev)
 	if (dev->device_rev >= 41) {
 		struct can_priv *priv = netdev_priv(dev->netdev);
 
-		priv->ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT |
-					    CAN_CTRLMODE_LOOPBACK;
+		priv->ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK |
+					    CAN_CTRLMODE_ONE_SHOT;
 	} else {
 		dev_info(dev->netdev->dev.parent,
 			 "Firmware update available. Please contact support.peak@hms-networks.com\n");
@@ -1016,7 +1016,8 @@ const struct peak_usb_adapter pcan_usb = {
 	.name = "PCAN-USB",
 	.device_id = PCAN_USB_PRODUCT_ID,
 	.ctrl_count = 1,
-	.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
+	.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			      CAN_CTRLMODE_3_SAMPLES |
 			      CAN_CTRLMODE_CC_LEN8_DLC,
 	.clock = {
 		.freq = PCAN_USB_CRYSTAL_HZ / 2,
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index 0d46f4ce5dca..82502594a409 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -1198,9 +1198,11 @@ const struct peak_usb_adapter pcan_usb_fd = {
 	.name = "PCAN-USB FD",
 	.device_id = PCAN_USBFD_PRODUCT_ID,
 	.ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
-	.ctrlmode_supported = CAN_CTRLMODE_FD |
-			CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
-			CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
+	.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			      CAN_CTRLMODE_3_SAMPLES |
+			      CAN_CTRLMODE_ONE_SHOT |
+			      CAN_CTRLMODE_FD |
+			      CAN_CTRLMODE_CC_LEN8_DLC,
 	.clock = {
 		.freq = PCAN_UFD_CRYSTAL_HZ,
 	},
@@ -1274,9 +1276,11 @@ const struct peak_usb_adapter pcan_usb_chip = {
 	.name = "PCAN-Chip USB",
 	.device_id = PCAN_USBCHIP_PRODUCT_ID,
 	.ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
-	.ctrlmode_supported = CAN_CTRLMODE_FD |
-		CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
-		CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
+	.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			      CAN_CTRLMODE_3_SAMPLES |
+			      CAN_CTRLMODE_ONE_SHOT |
+			      CAN_CTRLMODE_FD |
+			      CAN_CTRLMODE_CC_LEN8_DLC,
 	.clock = {
 		.freq = PCAN_UFD_CRYSTAL_HZ,
 	},
@@ -1350,9 +1354,11 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
 	.name = "PCAN-USB Pro FD",
 	.device_id = PCAN_USBPROFD_PRODUCT_ID,
 	.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
-	.ctrlmode_supported = CAN_CTRLMODE_FD |
-			CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
-			CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
+	.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			      CAN_CTRLMODE_3_SAMPLES |
+			      CAN_CTRLMODE_ONE_SHOT |
+			      CAN_CTRLMODE_FD |
+			      CAN_CTRLMODE_CC_LEN8_DLC,
 	.clock = {
 		.freq = PCAN_UFD_CRYSTAL_HZ,
 	},
@@ -1426,9 +1432,11 @@ const struct peak_usb_adapter pcan_usb_x6 = {
 	.name = "PCAN-USB X6",
 	.device_id = PCAN_USBX6_PRODUCT_ID,
 	.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
-	.ctrlmode_supported = CAN_CTRLMODE_FD |
-			CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
-			CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
+	.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			      CAN_CTRLMODE_3_SAMPLES |
+			      CAN_CTRLMODE_ONE_SHOT |
+			      CAN_CTRLMODE_FD |
+			      CAN_CTRLMODE_CC_LEN8_DLC,
 	.clock = {
 		.freq = PCAN_UFD_CRYSTAL_HZ,
 	},
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index b6be8c19e537..4c3d89a160af 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -1072,7 +1072,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
 	.name = "PCAN-USB Pro",
 	.device_id = PCAN_USBPRO_PRODUCT_ID,
 	.ctrl_count = PCAN_USBPRO_CHANNEL_COUNT,
-	.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
+	.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
+			      CAN_CTRLMODE_3_SAMPLES |
 			      CAN_CTRLMODE_ONE_SHOT,
 	.clock = {
 		.freq = PCAN_USBPRO_CRYSTAL_HZ,

-- 
2.53.0



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

* [PATCH v7 04/13] can: peak_usb: harden PCAN-USB message validation
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (2 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 03/13] can: peak_usb: sort ctrlmode_supported flags Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 05/13] can: peak_usb: replace open-coded bitmask operations with bitops Stéphane Grosjean via B4 Relay
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani, stable

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

Add boundary checks when parsing PCAN-USB messages and reject
malformed buffers whose contents would otherwise lead to accesses
outside the received USB data area.

This prevents potential out-of-bounds memory accesses caused by
corrupted or malicious device messages.

Fixes: 46be265d3388 ("can: usb: PEAK-System Technik PCAN-USB specific part")
Cc: stable@vger.kernel.org
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index afe5e68d5ea3..b515acd36466 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -558,6 +558,8 @@ static int pcan_usb_handle_bus_evt(struct pcan_usb_msg_context *mc, u8 ir)
 	switch (ir) {
 	case PCAN_USB_ERR_CNT_DEC:
 	case PCAN_USB_ERR_CNT_INC:
+		if ((mc->ptr + 3) > mc->end)
+			return -EINVAL;
 
 		/* save rx/tx error counters from in the device context */
 		pdev->bec.rxerr = mc->ptr[1];
@@ -696,8 +698,11 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
 		mc->ptr += rec_len;
 
 		/* Ignore next byte (client private id) if SRR bit is set */
-		if (can_id_flags & PCAN_USB_TX_SRR)
+		if (can_id_flags & PCAN_USB_TX_SRR) {
+			if ((mc->ptr + 1) > mc->end)
+				goto decode_failed;
 			mc->ptr++;
+		}
 
 		/* update statistics */
 		mc->netdev->stats.rx_bytes += cf->len;
@@ -733,14 +738,19 @@ static int pcan_usb_decode_msg(struct peak_usb_device *dev, u8 *ibuf, u32 lbuf)
 	int err;
 
 	for (err = 0; mc.rec_idx < mc.rec_cnt && !err; mc.rec_idx++) {
-		u8 sl = *mc.ptr++;
-
-		/* handle status and error frames here */
-		if (sl & PCAN_USB_STATUSLEN_INTERNAL) {
-			err = pcan_usb_decode_status(&mc, sl);
-		/* handle normal can frames here */
+		/* check if status_len byte can be read next */
+		if (mc.ptr >= mc.end) {
+			err = -EINVAL;
 		} else {
-			err = pcan_usb_decode_data(&mc, sl);
+			u8 sl = *mc.ptr++;
+
+			/* handle status and error frames here */
+			if (sl & PCAN_USB_STATUSLEN_INTERNAL) {
+				err = pcan_usb_decode_status(&mc, sl);
+			/* handle normal can frames here */
+			} else {
+				err = pcan_usb_decode_data(&mc, sl);
+			}
 		}
 	}
 

-- 
2.53.0



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

* [PATCH v7 05/13] can: peak_usb: replace open-coded bitmask operations with bitops
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (3 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 04/13] can: peak_usb: harden PCAN-USB message validation Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 06/13] can: peak_usb: harden channel handling in PCAN-USB FD Stéphane Grosjean via B4 Relay
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

The PCAN_USB_STATE_* flags of struct peak_usb_device are set, cleared
and tested from different contexts (ndo_open/ndo_stop, USB disconnect,
URB completion) with non-atomic open-coded bitmask operations.

Turn these flags into bit numbers, make the state field an unsigned
long and use set_bit(), clear_bit() and test_bit() instead, so that
updating one flag can no longer overwrite a concurrent update of
another one. The next patch relies on this to clear CONNECTED while a
channel may be opened.

dev->state is zeroed by alloc_candev(), so setting CONNECTED with
set_bit() at creation is equivalent to the former assignment.

Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c      |  4 ++--
 drivers/net/can/usb/peak_usb/pcan_usb_core.c | 10 +++++-----
 drivers/net/can/usb/peak_usb/pcan_usb_core.h |  9 ++++++---
 drivers/net/can/usb/peak_usb/pcan_usb_fd.c   |  2 +-
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c  |  6 +++---
 5 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index b515acd36466..b9cd6cbeb912 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -158,7 +158,7 @@ static int pcan_usb_send_cmd(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
 	int actual_length;
 
 	/* usb device unregistered? */
-	if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
 		return 0;
 
 	dev->cmd_buf[PCAN_USB_CMD_FUNC] = f;
@@ -188,7 +188,7 @@ static int pcan_usb_wait_rsp(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
 	int actual_length;
 
 	/* usb device unregistered? */
-	if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
 		return 0;
 
 	/* first, send command */
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index 55aad01cd8ca..a1b17e1e6fea 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -263,7 +263,7 @@ static void peak_usb_read_bulk_callback(struct urb *urb)
 	/* protect from any incoming empty msgs */
 	if ((urb->actual_length > 0) && (dev->adapter->dev_decode_buf)) {
 		/* handle these kinds of msgs only if _start callback called */
-		if (dev->state & PCAN_USB_STATE_STARTED) {
+		if (test_bit(PCAN_USB_STATE_STARTED, &dev->state)) {
 			err = dev->adapter->dev_decode_buf(dev, urb);
 			if (err)
 				pcan_dump_mem("received usb message",
@@ -537,7 +537,7 @@ static int peak_usb_start(struct peak_usb_device *dev)
 			goto err_adapter;
 	}
 
-	dev->state |= PCAN_USB_STATE_STARTED;
+	set_bit(PCAN_USB_STATE_STARTED, &dev->state);
 
 	/* can set bus on now */
 	if (dev->adapter->dev_set_bus) {
@@ -631,7 +631,7 @@ static int peak_usb_ndo_stop(struct net_device *netdev)
 {
 	struct peak_usb_device *dev = netdev_priv(netdev);
 
-	dev->state &= ~PCAN_USB_STATE_STARTED;
+	clear_bit(PCAN_USB_STATE_STARTED, &dev->state);
 	netif_stop_queue(netdev);
 
 	close_candev(netdev);
@@ -941,7 +941,7 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
 	dev->netdev = netdev;
 	dev->adapter = peak_usb_adapter;
 	dev->ctrl_idx = ctrl_idx;
-	dev->state = PCAN_USB_STATE_CONNECTED;
+	set_bit(PCAN_USB_STATE_CONNECTED, &dev->state);
 
 	dev->ep_msg_in = peak_usb_adapter->ep_msg_in;
 	dev->ep_msg_out = peak_usb_adapter->ep_msg_out[ctrl_idx];
@@ -1044,7 +1044,7 @@ static void peak_usb_disconnect(struct usb_interface *intf)
 		char name[IFNAMSIZ];
 
 		dev_prev_siblings = dev->prev_siblings;
-		dev->state &= ~PCAN_USB_STATE_CONNECTED;
+		clear_bit(PCAN_USB_STATE_CONNECTED, &dev->state);
 		strscpy(name, netdev->name, IFNAMSIZ);
 
 		unregister_candev(netdev);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
index 9ad7d31d2720..cb8777c3e08e 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
@@ -109,15 +109,18 @@ struct peak_tx_urb_context {
 	struct urb *urb;
 };
 
-#define PCAN_USB_STATE_CONNECTED	0x00000001
-#define PCAN_USB_STATE_STARTED		0x00000002
+/* bit numbers for struct peak_usb_device::state (used with set_bit()/
+ * clear_bit()/test_bit() for atomic read-modify-write across contexts)
+ */
+#define PCAN_USB_STATE_CONNECTED	0
+#define PCAN_USB_STATE_STARTED		1
 
 /* PEAK-System USB device */
 struct peak_usb_device {
 	struct can_priv can;
 	const struct peak_usb_adapter *adapter;
 	unsigned int ctrl_idx;
-	u32 state;
+	unsigned long state;
 
 	struct usb_device *udev;
 	struct net_device *netdev;
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index 82502594a409..15d275d6a127 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -202,7 +202,7 @@ static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail)
 	ptrdiff_t cmd_len;
 
 	/* usb device unregistered? */
-	if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
 		return 0;
 
 	/* if a packet is not filled completely by commands, the command list
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index 4c3d89a160af..cbc23953ce61 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -210,7 +210,7 @@ static int pcan_usb_pro_send_cmd(struct peak_usb_device *dev,
 	int err;
 
 	/* usb device unregistered? */
-	if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
 		return 0;
 
 	err = usb_bulk_msg(dev->udev,
@@ -234,7 +234,7 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev,
 	int i, err = 0;
 
 	/* usb device unregistered? */
-	if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
 		return 0;
 
 	req_data_type = pum->u.rec_buffer[4];
@@ -318,7 +318,7 @@ int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id,
 	unsigned int p;
 
 	/* usb device unregistered? */
-	if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
 		return 0;
 
 	req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER;

-- 
2.53.0



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

* [PATCH v7 06/13] can: peak_usb: harden channel handling in PCAN-USB FD
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (4 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 05/13] can: peak_usb: replace open-coded bitmask operations with bitops Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-11-01  2:15   ` netdev-bot+sashiko
  2026-10-30 10:44 ` [PATCH v7 07/13] can: peak_usb: fix RX cursor desync for self-received RTR frames with SRR Stéphane Grosjean via B4 Relay
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

Records received from PCAN-USB FD family devices carry a CAN channel
number used to index the adapter CAN device table usb_if->dev[].

The decoders only checked this number against the size of the table
(2 entries). On single-channel adapters (PCAN-USB FD, PCAN-Chip USB),
dev[1] is never set, so a record for channel 1 led to a NULL pointer
dereference in URB completion context. On two-channel adapters, a
channel slot is also NULL until that channel has been initialized,
while the RX URBs of channel 0 may already be running.

Check the channel number against the number of controllers of the
adapter and reject records for a channel whose slot is empty. Such a
record makes the decoder stop processing the rest of the URB.

When probing a channel fails after its slot has been filled, the channel
is freed but its slot kept pointing to it. Clear the slot in
pcan_usb_fd_free() and, before freeing the channel, stop RX on this
channel and on the sibling channels already created, since the whole
interface is then released anyway. Slots are published with
smp_store_release() and read with READ_ONCE().

Finally, peak_usb_disconnect() now stops RX on all channels before
unregistering any of them: it clears CONNECTED, which makes
peak_usb_ndo_open() fail, then poisons the RX anchors. This matters
when it is called from the probe error path, where the USB core has
not disabled the interface.

CONNECTED is cleared under RTNL, to serialize with peak_usb_ndo_open():
otherwise, an ndo_open() that has already passed the CONNECTED test
may have anchored an RX URB without having submitted it yet, which
makes usb_poison_anchored_urbs() busy-wait until it is submitted.

Fixes: a6921dd524fe ("can: peak_usb: add range checking in decode operations")
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb_core.c | 39 ++++++++++++++++-
 drivers/net/can/usb/peak_usb/pcan_usb_fd.c   | 62 +++++++++++++++++++++-------
 2 files changed, 84 insertions(+), 17 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index a1b17e1e6fea..f5c39b43b0fa 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
 #include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
@@ -574,6 +575,9 @@ static int peak_usb_ndo_open(struct net_device *netdev)
 	struct peak_usb_device *dev = netdev_priv(netdev);
 	int err;
 
+	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
+		return -ENODEV;
+
 	/* common open */
 	err = open_candev(netdev);
 	if (err)
@@ -904,6 +908,29 @@ int pcan_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info
 	return 0;
 }
 
+/*
+ * stop RX on dev and on all its previous siblings: clearing CONNECTED makes
+ * peak_usb_ndo_open() fail, then poisoning the RX anchors waits for running
+ * completion handlers and makes any later submission on them fail.
+ *
+ * peak_usb_ndo_open() runs under RTNL: clearing CONNECTED under RTNL ensures
+ * that no ndo_open() is in progress (so no RX URB is anchored but not yet
+ * submitted, which usb_poison_anchored_urbs() would busy-wait on) and that
+ * any later one fails.
+ */
+static void peak_usb_stop_rx(struct peak_usb_device *dev)
+{
+	struct peak_usb_device *d;
+
+	rtnl_lock();
+	for (d = dev; d; d = d->prev_siblings)
+		clear_bit(PCAN_USB_STATE_CONNECTED, &d->state);
+	rtnl_unlock();
+
+	for (d = dev; d; d = d->prev_siblings)
+		usb_poison_anchored_urbs(&d->rx_submitted);
+}
+
 /*
  * create one device which is attached to CAN controller #ctrl_idx of the
  * usb adapter.
@@ -1014,6 +1041,13 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
 	return 0;
 
 adap_dev_free:
+	/* the whole interface is released when probing a channel fails:
+	 * stop RX on this channel, which may already be open, and on the
+	 * channels already created, since their RX URBs may carry records
+	 * for this one.
+	 */
+	peak_usb_stop_rx(dev);
+
 	if (dev->adapter->dev_free)
 		dev->adapter->dev_free(dev);
 
@@ -1038,13 +1072,14 @@ static void peak_usb_disconnect(struct usb_interface *intf)
 	struct peak_usb_device *dev;
 	struct peak_usb_device *dev_prev_siblings;
 
-	/* unregister as many netdev devices as siblings */
+	/* stop RX on all channels before unregistering and freeing them */
+	peak_usb_stop_rx(usb_get_intfdata(intf));
+
 	for (dev = usb_get_intfdata(intf); dev; dev = dev_prev_siblings) {
 		struct net_device *netdev = dev->netdev;
 		char name[IFNAMSIZ];
 
 		dev_prev_siblings = dev->prev_siblings;
-		clear_bit(PCAN_USB_STATE_CONNECTED, &dev->state);
 		strscpy(name, netdev->name, IFNAMSIZ);
 
 		unregister_candev(netdev);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index 15d275d6a127..eee5b5eaa247 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -60,6 +60,7 @@ struct __packed pcan_ufd_fw_info {
 
 /* handle device specific info used by the netdevices */
 struct pcan_usb_fd_if {
+	const struct peak_usb_adapter *adapter;
 	struct peak_usb_device	*dev[PCAN_USB_MAX_CHANNEL];
 	struct pcan_ufd_fw_info	fw_info;
 	struct peak_time_ref	time_ref;
@@ -536,10 +537,16 @@ static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if,
 	struct sk_buff *skb;
 	const u16 rx_msg_flags = le16_to_cpu(rm->flags);
 
-	if (pucan_msg_get_channel(rm) >= ARRAY_SIZE(usb_if->dev))
-		return -ENOMEM;
+	/* Reject invalid channel numbers reported by the firmware */
+	if (pucan_msg_get_channel(rm) >= usb_if->adapter->ctrl_count)
+		return -EINVAL;
+
+	dev = READ_ONCE(usb_if->dev[pucan_msg_get_channel(rm)]);
+
+	/* reject records for a channel that is not (or no longer) set up */
+	if (!dev)
+		return -EINVAL;
 
-	dev = usb_if->dev[pucan_msg_get_channel(rm)];
 	netdev = dev->netdev;
 
 	if (rx_msg_flags & PUCAN_MSG_EXT_DATA_LEN) {
@@ -605,10 +612,16 @@ static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if,
 	struct can_frame *cf;
 	struct sk_buff *skb;
 
-	if (pucan_stmsg_get_channel(sm) >= ARRAY_SIZE(usb_if->dev))
-		return -ENOMEM;
+	/* Reject invalid channel numbers reported by the firmware */
+	if (pucan_stmsg_get_channel(sm) >= usb_if->adapter->ctrl_count)
+		return -EINVAL;
+
+	dev = READ_ONCE(usb_if->dev[pucan_stmsg_get_channel(sm)]);
+
+	/* reject records for a channel that is not (or no longer) set up */
+	if (!dev)
+		return -EINVAL;
 
-	dev = usb_if->dev[pucan_stmsg_get_channel(sm)];
 	pdev = container_of(dev, struct pcan_usb_fd_device, dev);
 	netdev = dev->netdev;
 
@@ -662,10 +675,16 @@ static int pcan_usb_fd_decode_error(struct pcan_usb_fd_if *usb_if,
 	struct pcan_usb_fd_device *pdev;
 	struct peak_usb_device *dev;
 
-	if (pucan_ermsg_get_channel(er) >= ARRAY_SIZE(usb_if->dev))
+	/* Reject invalid channel numbers reported by the firmware */
+	if (pucan_ermsg_get_channel(er) >= usb_if->adapter->ctrl_count)
+		return -EINVAL;
+
+	dev = READ_ONCE(usb_if->dev[pucan_ermsg_get_channel(er)]);
+
+	/* reject records for a channel that is not (or no longer) set up */
+	if (!dev)
 		return -EINVAL;
 
-	dev = usb_if->dev[pucan_ermsg_get_channel(er)];
 	pdev = container_of(dev, struct pcan_usb_fd_device, dev);
 
 	/* keep a trace of tx and rx error counters for later use */
@@ -685,10 +704,16 @@ static int pcan_usb_fd_decode_overrun(struct pcan_usb_fd_if *usb_if,
 	struct can_frame *cf;
 	struct sk_buff *skb;
 
-	if (pufd_omsg_get_channel(ov) >= ARRAY_SIZE(usb_if->dev))
+	/* Reject invalid channel numbers reported by the firmware */
+	if (pufd_omsg_get_channel(ov) >= usb_if->adapter->ctrl_count)
+		return -EINVAL;
+
+	dev = READ_ONCE(usb_if->dev[pufd_omsg_get_channel(ov)]);
+
+	/* reject records for a channel that is not (or no longer) set up */
+	if (!dev)
 		return -EINVAL;
 
-	dev = usb_if->dev[pufd_omsg_get_channel(ov)];
 	netdev = dev->netdev;
 
 	/* allocate an skb to store the error frame */
@@ -981,6 +1006,9 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
 		if (!pdev->usb_if)
 			goto err_out;
 
+		/* needed by the decoders to check channel numbers */
+		pdev->usb_if->adapter = dev->adapter;
+
 		/* allocate command buffer once for all for the interface */
 		pdev->cmd_buffer_addr = kzalloc(PCAN_UFD_CMD_BUFFER_SIZE,
 						GFP_KERNEL);
@@ -1054,7 +1082,8 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
 		fw_info = &pdev->usb_if->fw_info;
 	}
 
-	pdev->usb_if->dev[dev->ctrl_idx] = dev;
+	/* publish dev to the decoders, after the ctrlmode copies above */
+	smp_store_release(&pdev->usb_if->dev[dev->ctrl_idx], dev);
 	dev->can_channel_id =
 		le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]);
 
@@ -1124,14 +1153,17 @@ static void pcan_usb_fd_exit(struct peak_usb_device *dev)
 	}
 }
 
-/* called when the USB adapter is unplugged */
+/* called when the USB adapter is unplugged, or when probing a sibling fails */
 static void pcan_usb_fd_free(struct peak_usb_device *dev)
 {
+	struct pcan_usb_fd_device *pdev =
+		container_of(dev, struct pcan_usb_fd_device, dev);
+
+	/* clear this channel's slot: dev is going to be freed */
+	WRITE_ONCE(pdev->usb_if->dev[dev->ctrl_idx], NULL);
+
 	/* last device: can free shared objects now */
 	if (!dev->prev_siblings && !dev->next_siblings) {
-		struct pcan_usb_fd_device *pdev =
-			container_of(dev, struct pcan_usb_fd_device, dev);
-
 		/* free commands buffer */
 		kfree(pdev->cmd_buffer_addr);
 

-- 
2.53.0



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

* [PATCH v7 07/13] can: peak_usb: fix RX cursor desync for self-received RTR frames with SRR
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (5 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 06/13] can: peak_usb: harden channel handling in PCAN-USB FD Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 08/13] can: peak_usb: reject records for unset channels in PCAN-USB Pro Stéphane Grosjean via B4 Relay
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani, stable

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

pcan_usb_encode_msg() appends a one-byte "writer id" whenever
PCAN_USB_TX_SRR is set in can_id_flags, for both RTR and non-RTR
frames: the data block and the SRR writer id byte are two independent,
unconditional steps.

pcan_usb_decode_data() only consumed that extra byte in the non-RTR
branch, inside the same conditional block that reads the CAN data
payload. A self-received RTR frame with the SRR bit set (e.g. a
loopback echo with CAN_CTRLMODE_LOOPBACK) therefore left the RX cursor
one byte short, causing the private id byte to be misparsed as the
next record's status/len byte and the rest of the URB to be misparsed
or rejected.

Move the private id byte skip out of the RTR/non-RTR branch so it is
applied whenever SRR is set, matching the encoder's layout.

Since a frame can now be dropped when this byte is missing, update
rx_bytes together with rx_packets, once the frame has been fully
decoded.

Fixes: 3a7939495ce8 ("can: peak_usb: PCAN-USB: add support of loopback and one-shot mode")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index b9cd6cbeb912..4c93aa060fea 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -655,6 +655,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
 	struct sk_buff *skb;
 	struct can_frame *cf;
 	struct skb_shared_hwtstamps *hwts;
+	u8 rx_bytes = 0;
 	u32 can_id_flags;
 
 	skb = alloc_can_skb(mc->netdev, &cf);
@@ -696,18 +697,21 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
 
 		memcpy(cf->data, mc->ptr, cf->len);
 		mc->ptr += rec_len;
+		rx_bytes = cf->len;
+	}
 
-		/* Ignore next byte (client private id) if SRR bit is set */
-		if (can_id_flags & PCAN_USB_TX_SRR) {
-			if ((mc->ptr + 1) > mc->end)
-				goto decode_failed;
-			mc->ptr++;
-		}
-
-		/* update statistics */
-		mc->netdev->stats.rx_bytes += cf->len;
+	/* Ignore next byte (client private id) if SRR bit is set.
+	 * Note: this test must be done even when the frame is an RTR frame.
+	 */
+	if (can_id_flags & PCAN_USB_TX_SRR) {
+		if ((mc->ptr + 1) > mc->end)
+			goto decode_failed;
+		mc->ptr++;
 	}
+
+	/* update statistics */
 	mc->netdev->stats.rx_packets++;
+	mc->netdev->stats.rx_bytes += rx_bytes;
 
 	/* convert timestamp into kernel time */
 	hwts = skb_hwtstamps(skb);

-- 
2.53.0



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

* [PATCH v7 08/13] can: peak_usb: reject records for unset channels in PCAN-USB Pro
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (6 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 07/13] can: peak_usb: fix RX cursor desync for self-received RTR frames with SRR Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-11-01  2:15   ` netdev-bot+sashiko
  2026-10-30 10:44 ` [PATCH v7 09/13] can: peak_usb: register the netdevs only once all channels are set up Stéphane Grosjean via B4 Relay
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

Records received from a PCAN-USB Pro device carry a CAN channel number
used to index the CAN device table usb_if->dev[]. The decoders only
check this number against the size of the table.

The slot of channel 1 stays NULL until that channel has been
initialized, while the RX URBs of channel 0, which share the same
bulk-in endpoint, may already be running. A record for channel 1
received in that window leads to a NULL pointer dereference in URB
completion context. Moreover, when probing channel 1 fails after its
slot has been filled, the slot keeps pointing to the freed channel.

Reject records for a channel whose slot is empty, and clear the slot
of a channel in pcan_usb_pro_free(). Slots are published with
smp_store_release() and read with READ_ONCE().

Fixes: d8a199355f8f ("can: usb: PEAK-System Technik PCAN-USB Pro specific part")
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index cbc23953ce61..151c5ea2859b 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -543,7 +543,12 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
 	if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
 		return -EINVAL;
 
-	dev = usb_if->dev[ctrl_idx];
+	dev = READ_ONCE(usb_if->dev[ctrl_idx]);
+
+	/* reject records for a channel that is not (or no longer) set up */
+	if (!dev)
+		return -EINVAL;
+
 	netdev = dev->netdev;
 
 	skb = alloc_can_skb(netdev, &can_frame);
@@ -590,7 +595,12 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
 	if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
 		return -EINVAL;
 
-	dev = usb_if->dev[ctrl_idx];
+	dev = READ_ONCE(usb_if->dev[ctrl_idx]);
+
+	/* reject records for a channel that is not (or no longer) set up */
+	if (!dev)
+		return -EINVAL;
+
 	netdev = dev->netdev;
 
 	/* nothing should be sent while in BUS_OFF state */
@@ -933,7 +943,8 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
 	}
 
 	pdev->usb_if = usb_if;
-	usb_if->dev[dev->ctrl_idx] = dev;
+	/* publish dev to the decoders */
+	smp_store_release(&usb_if->dev[dev->ctrl_idx], dev);
 
 	/* set LED in default state (end of init phase) */
 	pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_DEVICE, 1);
@@ -981,6 +992,9 @@ static void pcan_usb_pro_exit(struct peak_usb_device *dev)
  */
 static void pcan_usb_pro_free(struct peak_usb_device *dev)
 {
+	/* clear this channel's slot: dev is going to be freed */
+	WRITE_ONCE(pcan_usb_pro_dev_if(dev)->dev[dev->ctrl_idx], NULL);
+
 	/* last device: can free pcan_usb_pro_interface object now */
 	if (!dev->prev_siblings && !dev->next_siblings)
 		kfree(pcan_usb_pro_dev_if(dev));

-- 
2.53.0



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

* [PATCH v7 09/13] can: peak_usb: register the netdevs only once all channels are set up
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (7 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 08/13] can: peak_usb: reject records for unset channels in PCAN-USB Pro Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:44 ` [PATCH v7 10/13] can: peak_usb: validate the data length of PCAN-USB Pro CAN records Stéphane Grosjean via B4 Relay
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

peak_usb_create_dev() registers the netdev of a channel before calling
dev_init(), dev_set_bus() and dev_get_can_channel_id(). Userspace can
therefore open or configure the netdev while the channel is still being
initialized, outside of rtnl_lock():

- peak_usb_ndo_open() may run before dev_init() has set up the adapter
  private data, e.g. pdev->usb_if, which is then dereferenced while
  still NULL by pcan_usb_pro_start() or pcan_usb_fd_start();
- the commands sent by the open or bittiming callbacks may race with
  the ones sent by dev_init() on the same command buffer;
- dev_set_bus(dev, 0) may switch the controller off right after
  peak_usb_ndo_open() has started it.

On multi-channel adapters, the same applies to the channels already
created while a sibling is being initialized, since they share the
interface resources: on PCAN-USB FD, the command buffer and the
firmware info used by the sibling init, and the ctrlmode copied from
the first channel.

Moreover, if dev_init() or dev_set_bus() fails, the adapter private
data is released before unregister_candev(), which closes the netdev
if it has been opened in the meantime, and then accesses the released
data (interface object and, on PCAN-USB FD, command buffer).

Register the netdevs in peak_usb_probe(), only once all the channels of
the interface have been initialized, and only unregister (and report as
removed) the registered ones in peak_usb_disconnect(). Since no netdev
is registered while the channels are being created, there is no RX to
stop anymore when creating a channel fails. If registering a netdev
fails, peak_usb_disconnect() still stops RX on the channels already
registered, which may have been opened in the meantime. Since the
channel id is now read before the netdev is registered, PCAN-USB reports
a failure to read it with dev_err() instead of netdev_err().

Fixes: bb4785551f64 ("can: usb: PEAK-System Technik USB adapters driver core")
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c      |  7 ++-
 drivers/net/can/usb/peak_usb/pcan_usb_core.c | 68 +++++++++++++++++-----------
 drivers/net/can/usb/peak_usb/pcan_usb_core.h |  1 +
 3 files changed, 47 insertions(+), 29 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 4c93aa060fea..777df7fd3e89 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -390,9 +390,12 @@ static int pcan_usb_get_can_channel_id(struct peak_usb_device *dev, u32 *can_ch_
 	int err;
 
 	err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args);
+	/* explicit use of dev_xxx() instead of netdev_xxx() here: this is
+	 * also called during probe, before the netdev is registered.
+	 */
 	if (err)
-		netdev_err(dev->netdev, "getting can channel id failure: %d\n", err);
-
+		dev_err(dev->netdev->dev.parent,
+			"getting can channel id failure: %d\n", err);
 	else
 		*can_ch_id = args[0];
 
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index f5c39b43b0fa..e5198ec5c760 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -1006,15 +1006,6 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
 	SET_NETDEV_DEV(netdev, &intf->dev);
 	netdev->dev_id = ctrl_idx;
 
-	err = register_candev(netdev);
-	if (err) {
-		dev_err(&intf->dev, "couldn't register CAN device: %d\n", err);
-		goto lbl_restore_intf_data;
-	}
-
-	if (dev->prev_siblings)
-		(dev->prev_siblings)->next_siblings = dev;
-
 	/* keep hw revision into the netdevice */
 	tmp16 = le16_to_cpu(usb_dev->descriptor.bcdDevice);
 	dev->device_rev = tmp16 >> 8;
@@ -1022,7 +1013,7 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
 	if (dev->adapter->dev_init) {
 		err = dev->adapter->dev_init(dev);
 		if (err)
-			goto lbl_unregister_candev;
+			goto lbl_restore_intf_data;
 	}
 
 	/* set bus off */
@@ -1035,25 +1026,15 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
 	/* get CAN channel id early */
 	dev->adapter->dev_get_can_channel_id(dev, &dev->can_channel_id);
 
-	netdev_info(netdev, "attached to %s channel %u (device 0x%08X)\n",
-		    peak_usb_adapter->name, ctrl_idx, dev->can_channel_id);
+	if (dev->prev_siblings)
+		(dev->prev_siblings)->next_siblings = dev;
 
 	return 0;
 
 adap_dev_free:
-	/* the whole interface is released when probing a channel fails:
-	 * stop RX on this channel, which may already be open, and on the
-	 * channels already created, since their RX URBs may carry records
-	 * for this one.
-	 */
-	peak_usb_stop_rx(dev);
-
 	if (dev->adapter->dev_free)
 		dev->adapter->dev_free(dev);
 
-lbl_unregister_candev:
-	unregister_candev(netdev);
-
 lbl_restore_intf_data:
 	usb_set_intfdata(intf, dev->prev_siblings);
 	kfree(dev->cmd_buf);
@@ -1078,11 +1059,15 @@ static void peak_usb_disconnect(struct usb_interface *intf)
 	for (dev = usb_get_intfdata(intf); dev; dev = dev_prev_siblings) {
 		struct net_device *netdev = dev->netdev;
 		char name[IFNAMSIZ];
+		bool registered;
 
 		dev_prev_siblings = dev->prev_siblings;
 		strscpy(name, netdev->name, IFNAMSIZ);
 
-		unregister_candev(netdev);
+		/* on probe error, some netdevs may not be registered yet */
+		registered = test_bit(PCAN_USB_STATE_REGISTERED, &dev->state);
+		if (registered)
+			unregister_candev(netdev);
 
 		kfree(dev->cmd_buf);
 		dev->next_siblings = NULL;
@@ -1090,7 +1075,8 @@ static void peak_usb_disconnect(struct usb_interface *intf)
 			dev->adapter->dev_free(dev);
 
 		free_candev(netdev);
-		dev_info(&intf->dev, "%s removed\n", name);
+		if (registered)
+			dev_info(&intf->dev, "%s removed\n", name);
 	}
 
 	usb_set_intfdata(intf, NULL);
@@ -1103,6 +1089,7 @@ static int peak_usb_probe(struct usb_interface *intf,
 			  const struct usb_device_id *id)
 {
 	const struct peak_usb_adapter *peak_usb_adapter;
+	struct peak_usb_device *dev;
 	int i, err = -ENOMEM;
 
 	/* get corresponding PCAN-USB adapter */
@@ -1117,13 +1104,40 @@ static int peak_usb_probe(struct usb_interface *intf,
 
 	for (i = 0; i < peak_usb_adapter->ctrl_count; i++) {
 		err = peak_usb_create_dev(peak_usb_adapter, intf, i);
+		if (err)
+			goto lbl_disconnect;
+	}
+
+	/* register the netdevs only once all the channels are set up: the
+	 * channels of an interface share resources (command buffer, firmware
+	 * info, ctrlmode copied from the 1st channel...) that must not be
+	 * used through a netdev while a sibling is being initialized.
+	 */
+	for (dev = usb_get_intfdata(intf); dev->prev_siblings;
+	     dev = dev->prev_siblings)
+		;
+
+	for (; dev; dev = dev->next_siblings) {
+		err = register_candev(dev->netdev);
 		if (err) {
-			/* deregister already created devices */
-			peak_usb_disconnect(intf);
-			break;
+			dev_err(&intf->dev, "couldn't register CAN device: %d\n",
+				err);
+			goto lbl_disconnect;
 		}
+		set_bit(PCAN_USB_STATE_REGISTERED, &dev->state);
+
+		netdev_info(dev->netdev,
+			    "attached to %s channel %u (device 0x%08X)\n",
+			    peak_usb_adapter->name, dev->ctrl_idx,
+			    dev->can_channel_id);
 	}
 
+	return 0;
+
+lbl_disconnect:
+	/* unregister (if needed) and free already created devices */
+	peak_usb_disconnect(intf);
+
 	return err;
 }
 
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
index cb8777c3e08e..614854c998de 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
@@ -114,6 +114,7 @@ struct peak_tx_urb_context {
  */
 #define PCAN_USB_STATE_CONNECTED	0
 #define PCAN_USB_STATE_STARTED		1
+#define PCAN_USB_STATE_REGISTERED	2
 
 /* PEAK-System USB device */
 struct peak_usb_device {

-- 
2.53.0



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

* [PATCH v7 10/13] can: peak_usb: validate the data length of PCAN-USB Pro CAN records
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (8 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 09/13] can: peak_usb: register the netdevs only once all channels are set up Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:44 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:45 ` [PATCH v7 11/13] can: peak_usb: don't read past the message in PCAN-USB Pro decoders Stéphane Grosjean via B4 Relay
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:44 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani, stable

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

The PCAN-USB Pro decoder takes the data length of a received CAN frame
from the 4-bit DLC field of the record, i.e. 0 to 15, and copies that
many bytes from the record into can_frame->data. This length is checked
neither against CAN_MAX_DLEN nor against the size of the record, which
depends on its type: RXMSG8, RXMSG4 and RXMSG0/RXRTR records carry 8, 4
and 0 data bytes. pcan_usb_pro_decode_buf() only checks that the record
fits in the URB, according to its type.

A faulty or malicious device can therefore make the driver:
- copy bytes located beyond the record into the frame, i.e. stale bytes
  of the RX buffer or, when the record ends the 1024-byte buffer, bytes
  beyond it, and deliver them to the CAN sockets;
- write up to 7 bytes past can_frame->data[] with a DLC of 9 to 15;
- deliver an RTR frame whose len is greater than CAN_MAX_DLEN.

Convert the DLC with can_cc_dlc2len() and reject a data frame whose
length exceeds the number of data bytes of its record type, as the
other malformed records are.

Found by Sashiko AI review.

Fixes: d8a199355f8f ("can: usb: PEAK-System Technik PCAN-USB Pro specific part")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index 151c5ea2859b..f94494e01f4a 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -534,6 +534,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
 				      struct pcan_usb_pro_rxmsg *rx)
 {
 	const unsigned int ctrl_idx = (rx->len >> 4) & 0x0f;
+	const u8 len = can_cc_dlc2len(rx->len & 0x0f);
 	struct peak_usb_device *dev;
 	struct net_device *netdev;
 	struct can_frame *can_frame;
@@ -543,6 +544,12 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
 	if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
 		return -EINVAL;
 
+	/* the number of data bytes depends on the record type */
+	if (!(rx->flags & PCAN_USBPRO_RTR) &&
+	    len > pcan_usb_pro_sizeof_rec[rx->data_type] -
+		  offsetof(struct pcan_usb_pro_rxmsg, data))
+		return -EINVAL;
+
 	dev = READ_ONCE(usb_if->dev[ctrl_idx]);
 
 	/* reject records for a channel that is not (or no longer) set up */
@@ -556,7 +563,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
 		return -ENOMEM;
 
 	can_frame->can_id = le32_to_cpu(rx->id);
-	can_frame->len = rx->len & 0x0f;
+	can_frame->len = len;
 
 	if (rx->flags & PCAN_USBPRO_EXT)
 		can_frame->can_id |= CAN_EFF_FLAG;

-- 
2.53.0



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

* [PATCH v7 11/13] can: peak_usb: don't read past the message in PCAN-USB Pro decoders
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (9 preceding siblings ...)
  2026-10-30 10:44 ` [PATCH v7 10/13] can: peak_usb: validate the data length of PCAN-USB Pro CAN records Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:45 ` Stéphane Grosjean via B4 Relay
  2026-10-30 10:45 ` [PATCH v7 12/13] can: peak_usb: dump undecodable URBs once and rate limit decode errors Stéphane Grosjean via B4 Relay
  2026-10-30 10:45 ` [PATCH v7 13/13] can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID Stéphane Grosjean via B4 Relay
  12 siblings, 0 replies; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:45 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

The messages received from a PCAN-USB Pro device start with a record
count, followed by records whose size depends on their type, given by
their first byte. Both pcan_usb_pro_decode_buf() and
pcan_usb_pro_wait_rsp() trust this count:

- pcan_usb_pro_decode_buf() reads the type of the next record before
  checking that this record starts inside the URB. When the device
  claims more records than the URB holds, it reads the byte following
  the URB data, which is beyond the 1024-byte RX buffer when the URB
  fills it;
- pcan_usb_pro_wait_rsp() doesn't check the records against the
  received length at all. A truncated response is then accepted, and
  pcan_usb_pro_get_can_channel_id() returns stale bytes of its own
  request as the channel id. With the current callers, the walk only
  stays within the command buffer because its unused tail is zeroed.

Stop decoding a message at its end in both functions, and in
pcan_usb_pro_wait_rsp() also reject a record that doesn't fit in the
message.

Found by Sashiko AI review.

Fixes: d8a199355f8f ("can: usb: PEAK-System Technik PCAN-USB Pro specific part")
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index f94494e01f4a..b869a20438cf 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -244,9 +244,9 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev,
 	for (i = 0; !err && i < PCAN_USBPRO_RSP_SUBMIT_MAX; i++) {
 		struct pcan_usb_pro_msg rsp;
 		union pcan_usb_pro_rec *pr;
+		u8 *pc, *rsp_end;
 		u32 r, rec_cnt;
 		u16 rec_len;
-		u8 *pc;
 
 		err = usb_bulk_msg(dev->udev,
 			usb_rcvbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDIN),
@@ -271,13 +271,18 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev,
 		pc = pcan_msg_init(&rsp, pum->u.rec_buffer,
 			actual_length);
 
+		rsp_end = pum->u.rec_buffer + actual_length;
 		rec_cnt = le32_to_cpu(*rsp.u.rec_cnt);
 
 		/* loop on records stored into message */
 		for (r = 0; r < rec_cnt; r++) {
+			/* rec_cnt comes from the device: stay in the message */
+			if (pc >= rsp_end)
+				break;
+
 			pr = (union pcan_usb_pro_rec *)pc;
 			rec_len = pcan_usb_pro_sizeof_rec[pr->data_type];
-			if (!rec_len) {
+			if (!rec_len || pc + rec_len > rsp_end) {
 				netdev_err(dev->netdev,
 					   "got unprocessed record in msg\n");
 				pcan_dump_mem("rcvd rsp msg", pum->u.rec_buffer,
@@ -745,8 +750,15 @@ static int pcan_usb_pro_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 	rec_cnt = le16_to_cpu(*usb_msg.u.rec_cnt_rd);
 	for (; rec_cnt > 0; rec_cnt--) {
 		union pcan_usb_pro_rec *pr = (union pcan_usb_pro_rec *)rec_ptr;
-		u16 sizeof_rec = pcan_usb_pro_sizeof_rec[pr->data_type];
+		u16 sizeof_rec;
+
+		/* rec_cnt comes from the device: don't read past the message */
+		if (rec_ptr >= msg_end) {
+			err = -EBADMSG;
+			break;
+		}
 
+		sizeof_rec = pcan_usb_pro_sizeof_rec[pr->data_type];
 		if (!sizeof_rec) {
 			netdev_err(netdev,
 				   "got unsupported rec in usb msg:\n");

-- 
2.53.0



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

* [PATCH v7 12/13] can: peak_usb: dump undecodable URBs once and rate limit decode errors
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (10 preceding siblings ...)
  2026-10-30 10:45 ` [PATCH v7 11/13] can: peak_usb: don't read past the message in PCAN-USB Pro decoders Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:45 ` Stéphane Grosjean via B4 Relay
  2026-11-01  2:15   ` netdev-bot+sashiko
  2026-10-30 10:45 ` [PATCH v7 13/13] can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID Stéphane Grosjean via B4 Relay
  12 siblings, 1 reply; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:45 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

When the decoding of a received URB fails, peak_usb_read_bulk_callback()
dumps the whole RX buffer to the kernel log. The buffer is allocated with
kmalloc() and its size is the adapter RX buffer size (up to 2048 bytes),
so the bytes beyond urb->actual_length are uninitialized memory or
leftovers from previous transfers.

Moreover, the PCAN-USB Pro and PCAN-USB FD decoders already dump the
received bytes themselves before returning the error, so the same URB is
dumped twice. Neither these dumps nor the error messages printed by the
decoders are rate limited, while a faulty or malicious device can make
every transfer fail to decode, or carry unknown records.

Dump only the urb->actual_length bytes received, from
peak_usb_read_bulk_callback() only, and rate limit this dump as well as
the error messages the decoders print about the received data.

The dumps and messages of the adapter decoders were pointed out by
Sashiko AI review.

Fixes: bb4785551f64 ("can: usb: PEAK-System Technik USB adapters driver core")
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c      |  8 +++++---
 drivers/net/can/usb/peak_usb/pcan_usb_core.c |  4 ++--
 drivers/net/can/usb/peak_usb/pcan_usb_fd.c   | 27 ++++++++++++-------------
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c  | 30 ++++++++++++++--------------
 4 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 777df7fd3e89..626593251e5d 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -637,7 +637,8 @@ static int pcan_usb_decode_status(struct pcan_usb_msg_context *mc,
 			return err;
 		break;
 	default:
-		netdev_err(mc->netdev, "unexpected function %u\n", f);
+		if (net_ratelimit())
+			netdev_err(mc->netdev, "unexpected function %u\n", f);
 		break;
 	}
 
@@ -776,8 +777,9 @@ static int pcan_usb_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 			urb->actual_length);
 
 	} else if (urb->actual_length > 0) {
-		netdev_err(dev->netdev, "usb message length error (%u)\n",
-			urb->actual_length);
+		if (net_ratelimit())
+			netdev_err(dev->netdev, "usb message length error (%u)\n",
+				   urb->actual_length);
 		err = -EINVAL;
 	}
 
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index e5198ec5c760..1d306160fa35 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -266,10 +266,10 @@ static void peak_usb_read_bulk_callback(struct urb *urb)
 		/* handle these kinds of msgs only if _start callback called */
 		if (test_bit(PCAN_USB_STATE_STARTED, &dev->state)) {
 			err = dev->adapter->dev_decode_buf(dev, urb);
-			if (err)
+			if (err && net_ratelimit())
 				pcan_dump_mem("received usb message",
 					      urb->transfer_buffer,
-					      urb->transfer_buffer_length);
+					      urb->actual_length);
 		}
 	}
 
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
index eee5b5eaa247..9c34f431f773 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -796,15 +796,17 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 
 		/* check if the record goes out of current packet */
 		if (rx_msg_size > msg_end - msg_ptr) {
-			netdev_err(netdev,
-				   "got frag rec: should inc usb rx buf sze\n");
+			if (net_ratelimit())
+				netdev_err(netdev,
+					   "got frag rec: should inc usb rx buf sze\n");
 			err = -EBADMSG;
 			break;
 		}
 
 		rx_msg_min_size = pcan_usb_fd_rx_msg_min_size(rx_msg_type);
 		if (rx_msg_size < rx_msg_min_size) {
-			netdev_err(netdev, "got short rec\n");
+			if (net_ratelimit())
+				netdev_err(netdev, "got short rec\n");
 			err = -EBADMSG;
 			break;
 		}
@@ -813,7 +815,7 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 		case PUCAN_MSG_CAN_RX:
 			err = pcan_usb_fd_decode_canmsg(usb_if, rx_msg);
 			if (err < 0)
-				goto fail;
+				return err;
 			break;
 
 		case PCAN_UFD_MSG_CALIBRATION:
@@ -823,35 +825,32 @@ static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 		case PUCAN_MSG_ERROR:
 			err = pcan_usb_fd_decode_error(usb_if, rx_msg);
 			if (err < 0)
-				goto fail;
+				return err;
 			break;
 
 		case PUCAN_MSG_STATUS:
 			err = pcan_usb_fd_decode_status(usb_if, rx_msg);
 			if (err < 0)
-				goto fail;
+				return err;
 			break;
 
 		case PCAN_UFD_MSG_OVERRUN:
 			err = pcan_usb_fd_decode_overrun(usb_if, rx_msg);
 			if (err < 0)
-				goto fail;
+				return err;
 			break;
 
 		default:
-			netdev_err(netdev,
-				   "unhandled msg type 0x%02x (%d): ignored\n",
-				   rx_msg_type, rx_msg_type);
+			if (net_ratelimit())
+				netdev_err(netdev,
+					   "unhandled msg type 0x%02x (%d): ignored\n",
+					   rx_msg_type, rx_msg_type);
 			break;
 		}
 
 		msg_ptr += rx_msg_size;
 	}
 
-fail:
-	if (err)
-		pcan_dump_mem("received msg",
-			      urb->transfer_buffer, urb->actual_length);
 	return err;
 }
 
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index b869a20438cf..9fd603a868d6 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -741,7 +741,9 @@ static int pcan_usb_pro_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 	rec_ptr = pcan_msg_init(&usb_msg, urb->transfer_buffer,
 					urb->actual_length);
 	if (!rec_ptr) {
-		netdev_err(netdev, "bad msg hdr len %d\n", urb->actual_length);
+		if (net_ratelimit())
+			netdev_err(netdev, "bad msg hdr len %d\n",
+				   urb->actual_length);
 		return -EINVAL;
 	}
 
@@ -760,16 +762,18 @@ static int pcan_usb_pro_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 
 		sizeof_rec = pcan_usb_pro_sizeof_rec[pr->data_type];
 		if (!sizeof_rec) {
-			netdev_err(netdev,
-				   "got unsupported rec in usb msg:\n");
+			if (net_ratelimit())
+				netdev_err(netdev,
+					   "got unsupported rec in usb msg:\n");
 			err = -ENOTSUPP;
 			break;
 		}
 
 		/* check if the record goes out of current packet */
 		if (rec_ptr + sizeof_rec > msg_end) {
-			netdev_err(netdev,
-				"got frag rec: should inc usb rx buf size\n");
+			if (net_ratelimit())
+				netdev_err(netdev,
+					   "got frag rec: should inc usb rx buf size\n");
 			err = -EBADMSG;
 			break;
 		}
@@ -781,13 +785,13 @@ static int pcan_usb_pro_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 		case PCAN_USBPRO_RXRTR:
 			err = pcan_usb_pro_handle_canmsg(usb_if, &pr->rx_msg);
 			if (err < 0)
-				goto fail;
+				return err;
 			break;
 
 		case PCAN_USBPRO_RXSTATUS:
 			err = pcan_usb_pro_handle_error(usb_if, &pr->rx_status);
 			if (err < 0)
-				goto fail;
+				return err;
 			break;
 
 		case PCAN_USBPRO_RXTS:
@@ -795,20 +799,16 @@ static int pcan_usb_pro_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 			break;
 
 		default:
-			netdev_err(netdev,
-				   "unhandled rec type 0x%02x (%d): ignored\n",
-				   pr->data_type, pr->data_type);
+			if (net_ratelimit())
+				netdev_err(netdev,
+					   "unhandled rec type 0x%02x (%d): ignored\n",
+					   pr->data_type, pr->data_type);
 			break;
 		}
 
 		rec_ptr += sizeof_rec;
 	}
 
-fail:
-	if (err)
-		pcan_dump_mem("received msg",
-			      urb->transfer_buffer, urb->actual_length);
-
 	return err;
 }
 

-- 
2.53.0



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

* [PATCH v7 13/13] can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID
  2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
                   ` (11 preceding siblings ...)
  2026-10-30 10:45 ` [PATCH v7 12/13] can: peak_usb: dump undecodable URBs once and rate limit decode errors Stéphane Grosjean via B4 Relay
@ 2026-10-30 10:45 ` Stéphane Grosjean via B4 Relay
  2026-11-01  2:15   ` netdev-bot+sashiko
  12 siblings, 1 reply; 18+ messages in thread
From: Stéphane Grosjean via B4 Relay @ 2026-10-30 10:45 UTC (permalink / raw)
  To: Marc Kleine-Budde, Vincent Mailhol, Wolfgang Grandegger,
	Stéphane Grosjean, Dan Carpenter, Lukas Magel
  Cc: linux-can, linux-kernel, Tristan Madani, stable

From: Stéphane Grosjean <s.grosjean@peak-system.fr>

pcan_usb_get_can_channel_id() takes the CAN channel ID of a PCAN-USB
from the args[] array, which pcan_usb_wait_rsp() fills with the response
of the device. However, args[] is not initialized, and
pcan_usb_wait_rsp() returns success without touching it once the device
is no longer connected.

peak_usb_disconnect() clears PCAN_USB_STATE_CONNECTED before it
unregisters the netdevs. An ETHTOOL_GEEPROM request handled in this
window makes peak_usb_get_eeprom() copy an uninitialized stack byte to
userspace, and cache it in dev->can_channel_id.

Initialize args[], so that a null ID is returned in that case.

Found by Sashiko AI review.

Fixes: 36d007c6fc79 ("can: peak_usb: add ethtool interface to user-configurable CAN channel identifier")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Stéphane Grosjean <s.grosjean@peak-system.fr>
---
 drivers/net/can/usb/peak_usb/pcan_usb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 626593251e5d..4f255f2a33fe 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -386,7 +386,7 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
  */
 static int pcan_usb_get_can_channel_id(struct peak_usb_device *dev, u32 *can_ch_id)
 {
-	u8 args[PCAN_USB_CMD_ARGS_LEN];
+	u8 args[PCAN_USB_CMD_ARGS_LEN] = {};
 	int err;
 
 	err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args);

-- 
2.53.0



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

* Re: [PATCH v7 06/13] can: peak_usb: harden channel handling in PCAN-USB FD
  2026-10-30 10:44 ` [PATCH v7 06/13] can: peak_usb: harden channel handling in PCAN-USB FD Stéphane Grosjean via B4 Relay
@ 2026-11-01  2:15   ` netdev-bot+sashiko
  0 siblings, 0 replies; 18+ messages in thread
From: netdev-bot+sashiko @ 2026-11-01  2:15 UTC (permalink / raw)
  To: s.grosjean
  Cc: mkl, mailhol, wg, error27, lukas.magel, linux-can, linux-kernel,
	tristmd, kuba

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

Critical: 0 · High: 0 (3) · Medium: 1 · 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).

- [Medium] On the adap_dev_free path, the new peak_usb_stop_rx(dev) call
  clears PCAN_USB_STATE_CONNECTED before unregister_candev() runs…

Pre-existing issues:
- [High] Asynchronous restart URBs can outlive the peak_usb_device they
  point to on the probe-error teardown path.
- [High] On the adap_dev_free error path of peak_usb_create_dev(),
  dev_free() (pcan_usb_fd_free()) frees the shared usb_if and…
- [High] peak_usb_create_dev() calls register_candev()
  (pcan_usb_core.c:1009) before dev_init() (1022).

--

can: peak_usb: harden channel handling in PCAN-USB FD

The PCAN-USB FD decoders now check record channel numbers against the
adapter's controller count. They also reject records whose usb_if->dev[]
slot is empty, and pcan_usb_fd_free() clears a channel's slot.

The patch also adds peak_usb_stop_rx(), which clears CONNECTED under RTNL
and poisons the RX anchors. It is called on the probe error path and in
peak_usb_disconnect() before channels are freed.

> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
> index a1b17e1e6fea6..f5c39b43b0fa1 100644
> --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c

[ ... ]

> @@ -574,6 +575,9 @@ static int peak_usb_ndo_open(struct net_device *netdev)
>  	struct peak_usb_device *dev = netdev_priv(netdev);
>  	int err;
>  
> +	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
> +		return -ENODEV;
> +

[Severity: High]
This is a pre-existing issue, but does this CONNECTED test close the
window where the netdev is visible before its private data is set up?

peak_usb_create_dev() sets CONNECTED and calls register_candev(). Only
after that does it call dev_init():

	set_bit(PCAN_USB_STATE_CONNECTED, &dev->state);
	...
	err = register_candev(netdev);
	...
	if (dev->adapter->dev_init) {
		err = dev->adapter->dev_init(dev);

Until pcan_usb_fd_init() runs, pdev->usb_if and pdev->cmd_buffer_addr are
still NULL. Can userspace configure or open the netdev in that window?
That would make pcan_usb_fd_start() dereference pdev->usb_if, or make the
bittiming command builders use the NULL cmd_buffer_addr.

The later commit "can: peak_usb: register the netdevs only once all
channels are set up" appears to fix this. It moves register_candev() into
peak_usb_probe(), after all channels are initialized.

>  	/* common open */
>  	err = open_candev(netdev);
>  	if (err)

[ ... ]

> @@ -1014,6 +1041,13 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
>  	return 0;
>  
>  adap_dev_free:
> +	/* the whole interface is released when probing a channel fails:
> +	 * stop RX on this channel, which may already be open, and on the
> +	 * channels already created, since their RX URBs may carry records
> +	 * for this one.
> +	 */
> +	peak_usb_stop_rx(dev);

[Severity: Medium]
Does clearing CONNECTED here suppress the shutdown commands that ndo_stop
sends for a channel that is already open?

On this path the netdev is still registered and may be up. The later
unregister_candev() runs peak_usb_ndo_stop(), which calls dev_stop() and
dev_set_bus(dev, 0). With CONNECTED now clear, pcan_usb_fd_send_cmd()
returns early:

	/* usb device unregistered? */
	if (!test_bit(PCAN_USB_STATE_CONNECTED, &dev->state))
		return 0;

Before this patch, CONNECTED was still set when ndo_stop ran here. Could
a probe failure now leave the controller bus-on, with calibration records
still streaming, while the device stays attached?

The later commit "can: peak_usb: register the netdevs only once all
channels are set up" removes peak_usb_stop_rx() from adap_dev_free, and
no netdev is registered on this path there.

peak_usb_disconnect() still clears CONNECTED before it unregisters an open
channel, but the old loop already did that before unregister_candev().

> +
>  	if (dev->adapter->dev_free)
>  		dev->adapter->dev_free(dev);
>  

[Severity: High]
This isn't a bug introduced by this patch, but is it safe to call
dev_free() before unregister_candev() on this error path?

If the failing channel has no siblings, pcan_usb_fd_free() frees the
shared objects:

	kfree(pdev->cmd_buffer_addr);
	...
	kfree(pdev->usb_if);

The code then falls through to lbl_unregister_candev and calls
unregister_candev() on a netdev that is registered and possibly open.
Wouldn't peak_usb_ndo_stop() -> pcan_usb_fd_stop() then access the freed
usb_if?

	pdev->usb_if->dev_opened_count--;

pcan_usb_fd_set_bus() would also build its command in the freed
cmd_buffer_addr.

The later commit "can: peak_usb: register the netdevs only once all
channels are set up" also fixes this, because no netdev is registered
by the time adap_dev_free is reached.

[ ... ]

> @@ -1038,13 +1072,14 @@ static void peak_usb_disconnect(struct usb_interface *intf)
>  	struct peak_usb_device *dev;
>  	struct peak_usb_device *dev_prev_siblings;
>  
> -	/* unregister as many netdev devices as siblings */
> +	/* stop RX on all channels before unregistering and freeing them */
> +	peak_usb_stop_rx(usb_get_intfdata(intf));

[Severity: High]
This is a pre-existing issue, but can an asynchronous restart URB outlive
the peak_usb_device it points to on the probe error path?

peak_usb_set_mode(CAN_MODE_START) -> peak_usb_restart() ->
dev_restart_async() submits a URB with dev as its context, without
anchoring it. In pcan_usb_fd_restart_async():

	usb_fill_bulk_urb(urb, dev->udev,
			  usb_sndbulkpipe(dev->udev, fw_info->cmd_out_ep),
			  buf, pc - buf,
			  pcan_usb_pro_restart_complete, dev);

	/* and submit it. */
	return usb_submit_urb(urb, GFP_ATOMIC);

pcan_usb_pro_restart_async() does the same. pcan_usb.c passes pdev as the
context instead.

When peak_usb_probe() calls peak_usb_disconnect() after a probe failure,
the USB core has not disabled the interface. The commit message says so
too.

On that path, peak_usb_stop_rx() only poisons rx_submitted. Then
unregister_candev() -> peak_usb_ndo_stop() runs. There, close_candev()
only cancels restart_work, and peak_usb_unlink_all_urbs() only kills the
rx_submitted and tx_submitted anchors. Finally free_candev() frees the
netdev.

A restart URB can still be pending on the command endpoint, for example
if the device keeps NAKing it. Wouldn't its completion, when it finally
runs, do this on the freed netdev?

pcan_usb_pro_restart_complete()
    peak_usb_restart_complete(urb->context)
        dev->can.state = CAN_STATE_ERROR_ACTIVE;
        netif_wake_queue(dev->netdev);

The later commit "can: peak_usb: register the netdevs only once all
channels are set up" narrows the trigger. A later sibling's
register_candev() has to fail after channel 0 was registered, opened,
went bus-off and had a restart submitted. No patch in the series tracks
or kills restart URBs.

> +
>  	for (dev = usb_get_intfdata(intf); dev; dev = dev_prev_siblings) {

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261030-canfd_check_channel_idx-v7-0-fc4a3faf3acf%40peak-system.fr

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

* Re: [PATCH v7 08/13] can: peak_usb: reject records for unset channels in PCAN-USB Pro
  2026-10-30 10:44 ` [PATCH v7 08/13] can: peak_usb: reject records for unset channels in PCAN-USB Pro Stéphane Grosjean via B4 Relay
@ 2026-11-01  2:15   ` netdev-bot+sashiko
  0 siblings, 0 replies; 18+ messages in thread
From: netdev-bot+sashiko @ 2026-11-01  2:15 UTC (permalink / raw)
  To: s.grosjean
  Cc: mkl, mailhol, wg, error27, lukas.magel, linux-can, linux-kernel,
	tristmd, kuba

Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.

Low priority / nit picks for your consideration:

- [Low] When a record names a channel whose slot is NULL,
  pcan_usb_pro_handle_canmsg() and pcan_usb_pro_handle_error() return…

Pre-existing issues:
- [High] peak_usb_create_dev() calls register_candev()
  (pcan_usb_core.c:1009) before dev_init() (1023).
- [Medium] pcan_usb_pro_decode_buf() reads pr->data_type
  (pcan_usb_pro.c:741) before checking that rec_ptr is still below…

--

can: peak_usb: reject records for unset channels in PCAN-USB Pro

With this patch, the PCAN-USB Pro record decoders reject records whose
channel slot in usb_if->dev[] is NULL. A channel's slot is also cleared
in pcan_usb_pro_free(). Slots are published with smp_store_release()
and read with READ_ONCE().

> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
> index cbc23953ce610..151c5ea2859be 100644
> --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
> @@ -543,7 +543,12 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
>  	if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
>  		return -EINVAL;
>  
> -	dev = usb_if->dev[ctrl_idx];
> +	dev = READ_ONCE(usb_if->dev[ctrl_idx]);
> +
> +	/* reject records for a channel that is not (or no longer) set up */
> +	if (!dev)
> +		return -EINVAL;

[Severity: Low]
When the slot is empty, pcan_usb_pro_handle_canmsg() returns -EINVAL.
pcan_usb_pro_decode_buf() treats any negative return as fatal for the
whole transfer:

pcan_usb_pro_decode_buf() {
    ...
	case PCAN_USBPRO_RXRTR:
		err = pcan_usb_pro_handle_canmsg(usb_if, &pr->rx_msg);
		if (err < 0)
			goto fail;
    ...
}

pcan_usb_pro_handle_error() does the same for RXSTATUS records. Channel
0 and channel 1 share the same bulk-in endpoint. Would one channel 1
record received while channel 1 is still inside peak_usb_create_dev()
cause the remaining channel 0 frames and RXTS records in that URB to be
dropped?

At this commit the URB is also dumped twice. It is dumped once in
pcan_usb_pro_decode_buf(), and again in peak_usb_read_bulk_callback(),
which dumps urb->transfer_buffer_length instead of urb->actual_length:

peak_usb_read_bulk_callback() {
    ...
			err = dev->adapter->dev_decode_buf(dev, urb);
			if (err)
				pcan_dump_mem("received usb message",
					      urb->transfer_buffer,
					      urb->transfer_buffer_length);
    ...
}

This is still better than the NULL dereference that happened before.
Later in the series, "can: peak_usb: register the netdevs only once all
channels are set up" registers the netdevs in peak_usb_probe() only
after every channel's dev_init() has filled its slot. That way RX
cannot run while a slot is NULL.

Also, "can: peak_usb: dump undecodable URBs once and rate limit decode
errors" changes this to a single rate limited dump of actual_length.
The FD sibling patch says that aborting the URB here is intentional.

> +
>  	netdev = dev->netdev;
>  
>  	skb = alloc_can_skb(netdev, &can_frame);
> @@ -590,7 +595,12 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
>  	if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
>  		return -EINVAL;
>  
> -	dev = usb_if->dev[ctrl_idx];
> +	dev = READ_ONCE(usb_if->dev[ctrl_idx]);
> +
> +	/* reject records for a channel that is not (or no longer) set up */
> +	if (!dev)
> +		return -EINVAL;

[Severity: Medium]
This is a pre-existing issue, not one introduced by this patch, but it
is in the caller of these handlers. pcan_usb_pro_decode_buf() reads
pr->data_type before it checks that rec_ptr is still below msg_end:

pcan_usb_pro_decode_buf() {
    ...
	rec_cnt = le16_to_cpu(*usb_msg.u.rec_cnt_rd);
	for (; rec_cnt > 0; rec_cnt--) {
		union pcan_usb_pro_rec *pr = (union pcan_usb_pro_rec *)rec_ptr;
		u16 sizeof_rec = pcan_usb_pro_sizeof_rec[pr->data_type];
    ...
}

rec_cnt comes from the device and is not checked. Suppose a device
fills the whole RX buffer with complete records and sends a rec_cnt
larger than the number of records. Can this loop then read one byte
past the end of the kmalloc'd RX buffer?

Later in the series, "can: peak_usb: don't read past the message in
PCAN-USB Pro decoders" appears to fix this by adding a
rec_ptr >= msg_end check before the data_type read.

[ ... ]

> @@ -933,7 +943,8 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
>  	}
>  
>  	pdev->usb_if = usb_if;

[Severity: High]
This isn't a bug introduced by this patch, but pdev->usb_if is only set
here. By that point peak_usb_create_dev() has already made the netdev
openable:

peak_usb_create_dev()
    register_candev(netdev)
    ...
    dev->adapter->dev_init(dev)
        pcan_usb_pro_init()
            pdev->usb_if = usb_if;

peak_usb_ndo_open() only checks PCAN_USB_STATE_CONNECTED, and that bit
is set before registration. A CAP_NET_ADMIN user could open the CAN
netdev between register_candev() and dev_init(). Can
pcan_usb_pro_start() then dereference a NULL pdev->usb_if?

pcan_usb_pro_start() {
    ...
	if (pdev->usb_if->dev_opened_count == 0) {
    ...
}

The RX path has the same problem. pcan_usb_pro_decode_buf() passes
pcan_usb_pro_dev_if(dev) to the record handlers without a NULL check.
The new !dev slot check does not cover this case, because the NULL
pointer here is usb_if and not the slot.

Later in the series, "can: peak_usb: register the netdevs only once all
channels are set up" appears to fix this. It moves register_candev()
into peak_usb_probe(), after every channel's dev_init() and
dev_set_bus(), and its commit message names this pcan_usb_pro_start()
NULL dereference.

> -	usb_if->dev[dev->ctrl_idx] = dev;
> +	/* publish dev to the decoders */
> +	smp_store_release(&usb_if->dev[dev->ctrl_idx], dev);

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261030-canfd_check_channel_idx-v7-0-fc4a3faf3acf%40peak-system.fr

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

* Re: [PATCH v7 12/13] can: peak_usb: dump undecodable URBs once and rate limit decode errors
  2026-10-30 10:45 ` [PATCH v7 12/13] can: peak_usb: dump undecodable URBs once and rate limit decode errors Stéphane Grosjean via B4 Relay
@ 2026-11-01  2:15   ` netdev-bot+sashiko
  0 siblings, 0 replies; 18+ messages in thread
From: netdev-bot+sashiko @ 2026-11-01  2:15 UTC (permalink / raw)
  To: s.grosjean
  Cc: mkl, mailhol, wg, error27, lukas.magel, linux-can, linux-kernel,
	tristmd, kuba

Thank you for your contribution! Sashiko AI review found more severe
issue(s) in other patches of this series. This mail is only an FYI, in case
you want to address the nit picks below when you respin.

Low priority / nit picks for your consideration:

- [Low] For an undecodable URB, the decoder's error message and the hex
  dump of the same URB are now gated by two separate net_ratelimit()…

--

can: peak_usb: dump undecodable URBs once and rate limit decode errors

This patch limits the hex dump of an undecodable URB to the
urb->actual_length bytes received. It removes the extra dumps from the
PCAN-USB FD and Pro decoders so that only peak_usb_read_bulk_callback()
dumps the URB. It also puts net_ratelimit() in front of the dump and the
decoder error messages.

[ ... ]

> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
> index e5198ec5c760d..1d306160fa354 100644
> --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
> @@ -266,10 +266,10 @@ static void peak_usb_read_bulk_callback(struct urb *urb)
>  		/* handle these kinds of msgs only if _start callback called */
>  		if (test_bit(PCAN_USB_STATE_STARTED, &dev->state)) {
>  			err = dev->adapter->dev_decode_buf(dev, urb);
> -			if (err)
> +			if (err && net_ratelimit())
>  				pcan_dump_mem("received usb message",
>  					      urb->transfer_buffer,
> -					      urb->transfer_buffer_length);
> +					      urb->actual_length);
>  		}
>  	}

[Severity: Low]
Can the decoder's error message and the dump of the same URB get split
up by two separate net_ratelimit() decisions?

Both calls use the single global net_ratelimit_state (5 * HZ interval,
burst of 10). For an undecodable URB, pcan_usb_fd_decode_buf() or
pcan_usb_pro_decode_buf() first calls net_ratelimit() for its own
message. peak_usb_read_bulk_callback() then calls it again for the dump.

For example, in pcan_usb_pro_decode_buf():

    if (!sizeof_rec) {
        if (net_ratelimit())
            netdev_err(netdev,
                       "got unsupported rec in usb msg:\n");
        err = -ENOTSUPP;
        break;
    }

Suppose the decoder's message takes the last token in the burst. The
dump in peak_usb_read_bulk_callback() is then suppressed. The "got
unsupported rec in usb msg:" line, which ends in a colon, gets logged
without the dump that should follow it. The reverse can also happen:
the dump appears without its message. The same applies to "bad msg hdr
len", "got frag rec" and "got short rec" in the FD and Pro decoders.

The per-record "unhandled msg type" and "unhandled rec type" messages
printed earlier in the loop for the same URB also use up tokens, and so
does other networking code. That makes it more likely that the dump for
a later fatal error in the URB is dropped.

Before this patch, the FD and Pro decoders always printed the dump right
after the message. Would making one rate-limit decision per URB, either
in the core or passed down to the decoders, keep each message and its
dump together?

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261030-canfd_check_channel_idx-v7-0-fc4a3faf3acf%40peak-system.fr

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

* Re: [PATCH v7 13/13] can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID
  2026-10-30 10:45 ` [PATCH v7 13/13] can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID Stéphane Grosjean via B4 Relay
@ 2026-11-01  2:15   ` netdev-bot+sashiko
  0 siblings, 0 replies; 18+ messages in thread
From: netdev-bot+sashiko @ 2026-11-01  2:15 UTC (permalink / raw)
  To: s.grosjean
  Cc: mkl, mailhol, wg, error27, lukas.magel, linux-can, linux-kernel,
	tristmd, 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] The same ETHTOOL_GEEPROM disconnect-window leak is still open
  for PCAN-USB Pro, through the same shared handler.

Pre-existing issues:
- [Medium] Baseline decision: false (kept only because
  requires_validation=true).
- [Low] Baseline decision: false (kept only because
  requires_validation=true).

--

can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID

This patch zero-initializes args[] in pcan_usb_get_can_channel_id().
After disconnect has cleared PCAN_USB_STATE_CONNECTED, pcan_usb_wait_rsp()
returns success without filling args[]. Without the initializer, an
ETHTOOL_GEEPROM request in that window copies an uninitialized stack byte
to userspace.

> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
> index 626593251e5d7..4f255f2a33feb 100644
> --- a/drivers/net/can/usb/peak_usb/pcan_usb.c
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
> @@ -386,7 +386,7 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
>   */
>  static int pcan_usb_get_can_channel_id(struct peak_usb_device *dev, u32 *can_ch_id)
>  {
> -	u8 args[PCAN_USB_CMD_ARGS_LEN];
> +	u8 args[PCAN_USB_CMD_ARGS_LEN] = {};

[Severity: Medium]
Is the same ETHTOOL_GEEPROM disconnect window still open for the PCAN-USB
Pro? It goes through the same peak_usb_get_eeprom() handler.

In pcan_usb_pro.c, pcan_usb_pro_get_can_channel_id() builds the GETDEVID
record with only one variadic argument:

	pcan_msg_add_rec(&um, PCAN_USBPRO_GETDEVID, dev->ctrl_idx);

pcan_msg_add_rec() handles GETDEVID in the same case as SETBTR and
SETDEVID. That case reads a second u32 argument, which this caller never
passes:

	case PCAN_USBPRO_SETBTR:
	case PCAN_USBPRO_GETDEVID:
	case PCAN_USBPRO_SETDEVID:
		*pc++ = va_arg(ap, int);
		pc += 2;
		*(__le32 *)pc = cpu_to_le32(va_arg(ap, u32));

That va_arg() is undefined behavior. In practice, whatever leftover
register or stack value it picks up ends up in the dev_num field of the
record in dev->cmd_buf.

The window opens after peak_usb_stop_rx() clears PCAN_USB_STATE_CONNECTED
and drops rtnl, and closes when unregister_candev() runs. Inside it,
pcan_usb_pro_send_cmd() and pcan_usb_pro_wait_rsp() both return 0 without
doing any USB I/O. Then this returns those leftover bytes as the channel
ID:

	pdn = (struct pcan_usb_pro_devid *)pc;
	*can_ch_id = le32_to_cpu(pdn->dev_num);

peak_usb_get_eeprom() then copies them to userspace. It also caches them
in dev->can_channel_id, which backs the can_channel_id sysfs attribute.

While the device is connected, the same 4 bytes are also sent to the
device with every GETDEVID request.

Would passing an explicit 0 as the second argument to pcan_msg_add_rec()
in pcan_usb_pro_get_can_channel_id() fix the Pro adapter? That could go
in a separate follow-up patch.

>  	int err;
>  
>  	err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args);

[Severity: Low]
This isn't a bug introduced by this patch, but pcan_usb_wait_rsp() ignores
actual_length from the CMDIN usb_bulk_msg(). It also doesn't check that
cmd_buf[PCAN_USB_CMD_FUNC] and cmd_buf[PCAN_USB_CMD_NUM] match the
request:

	err = usb_bulk_msg(dev->udev,
		usb_rcvbulkpipe(dev->udev, PCAN_USB_EP_CMDIN),
		dev->cmd_buf, PCAN_USB_CMD_LEN, &actual_length,
		PCAN_USB_COMMAND_TIMEOUT);
	if (err)
		...
	else if (p)
		memcpy(p, dev->cmd_buf + PCAN_USB_CMD_ARGS,
			PCAN_USB_CMD_ARGS_LEN);

Suppose the device sends a short reply, or a late reply to an earlier
command that timed out. Could stale bytes from dev->cmd_buf then
overwrite the new zero initializer in args[]?

pcan_usb_send_cmd(..., NULL) only rewrites cmd_buf[0] and cmd_buf[1]. So
pcan_usb_get_can_channel_id() could report a byte left over from an
earlier outgoing command as the channel ID, for example btr1 from
pcan_usb_set_bittiming().

[Severity: Medium]
This is a pre-existing issue, but two setters in this file have the same
uninitialized args[] problem on the transmit side.
pcan_usb_set_can_channel_id() only sets args[0]:

	u8 args[PCAN_USB_CMD_ARGS_LEN];
	...
	args[0] = can_ch_id;
	return pcan_usb_send_cmd(dev, PCAN_USB_CMD_DEVID, PCAN_USB_SET, args);

pcan_usb_set_bittiming() only sets args[0] and args[1].

pcan_usb_send_cmd() copies all PCAN_USB_CMD_ARGS_LEN bytes into
dev->cmd_buf and sends the whole command over the bulk OUT endpoint:

	if (p)
		memcpy(dev->cmd_buf + PCAN_USB_CMD_ARGS,
			p, PCAN_USB_CMD_ARGS_LEN);

Does this send 12 or 13 bytes of uninitialized kernel stack to the USB
device on every channel ID write and every bitrate change?

The other setters in pcan_usb.c, such as pcan_usb_set_sja1000(),
pcan_usb_set_bus() and pcan_usb_set_led(), zero-initialize their args[].

Could these two args[] arrays get the same {} initializer?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261030-canfd_check_channel_idx-v7-0-fc4a3faf3acf%40peak-system.fr

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

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

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30 10:44 [PATCH v7 00/13] can: peak_usb: fixes, cleanup and input validation hardening Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 01/13] can: peak_usb: fix missing CAN_ERR_FLAG when reporting error counters Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 02/13] can: peak_usb: add missing includes Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 03/13] can: peak_usb: sort ctrlmode_supported flags Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 04/13] can: peak_usb: harden PCAN-USB message validation Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 05/13] can: peak_usb: replace open-coded bitmask operations with bitops Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 06/13] can: peak_usb: harden channel handling in PCAN-USB FD Stéphane Grosjean via B4 Relay
2026-11-01  2:15   ` netdev-bot+sashiko
2026-10-30 10:44 ` [PATCH v7 07/13] can: peak_usb: fix RX cursor desync for self-received RTR frames with SRR Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 08/13] can: peak_usb: reject records for unset channels in PCAN-USB Pro Stéphane Grosjean via B4 Relay
2026-11-01  2:15   ` netdev-bot+sashiko
2026-10-30 10:44 ` [PATCH v7 09/13] can: peak_usb: register the netdevs only once all channels are set up Stéphane Grosjean via B4 Relay
2026-10-30 10:44 ` [PATCH v7 10/13] can: peak_usb: validate the data length of PCAN-USB Pro CAN records Stéphane Grosjean via B4 Relay
2026-10-30 10:45 ` [PATCH v7 11/13] can: peak_usb: don't read past the message in PCAN-USB Pro decoders Stéphane Grosjean via B4 Relay
2026-10-30 10:45 ` [PATCH v7 12/13] can: peak_usb: dump undecodable URBs once and rate limit decode errors Stéphane Grosjean via B4 Relay
2026-11-01  2:15   ` netdev-bot+sashiko
2026-10-30 10:45 ` [PATCH v7 13/13] can: peak_usb: don't return an uninitialized PCAN-USB CAN channel ID Stéphane Grosjean via B4 Relay
2026-11-01  2:15   ` netdev-bot+sashiko

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