[PATCH v6 11/13] can: peak_usb: don't read past the message in PCAN-USB Pro decoders
From: Stéphane Grosjean via B4 Relay
Date: Thu Oct 22 2026 - 10:40:48 EST
From: Stéphane Grosjean <s.grosjean@xxxxxxxxxxxxxx>
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. Since the count is a 32-bit value, a bogus
response makes it walk the records past the command buffer.
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@xxxxxxxxxxxxxx>
---
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