Skip to content

Commit 9e89db3

Browse files
author
Paolo Abeni
committed
Merge tag 'linux-can-fixes-for-6.15-20250520' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Marc Kleine-Budde says: ==================== pull-request: can 2025-05-20 this is a pull request of 3 patches for net/main. The 1st patch is by Rob Herring, and fixes the $id path in the microchip,mcp2510.yaml device tree bindinds documentation. The last 2 patches are from Oliver Hartkopp and fix a use-after-free read and an out-of-bounds read in the CAN Broadcast Manager (BCM) protocol. linux-can-fixes-for-6.15-20250520 * tag 'linux-can-fixes-for-6.15-20250520' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: bcm: add missing rcu read protection for procfs content can: bcm: add locking for bcm_op runtime updates dt-bindings: can: microchip,mcp2510: Fix $id path ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 239af19 + 8283fd5 commit 9e89db3

File tree

2 files changed

+55
-26
lines changed

2 files changed

+55
-26
lines changed

Documentation/devicetree/bindings/net/can/microchip,mcp2510.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
22
%YAML 1.2
33
---
4-
$id: http://devicetree.org/schemas/can/microchip,mcp2510.yaml#
4+
$id: http://devicetree.org/schemas/net/can/microchip,mcp2510.yaml#
55
$schema: http://devicetree.org/meta-schemas/core.yaml#
66

77
title: Microchip MCP251X stand-alone CAN controller

net/can/bcm.c

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include <linux/can/skb.h>
5959
#include <linux/can/bcm.h>
6060
#include <linux/slab.h>
61+
#include <linux/spinlock.h>
6162
#include <net/sock.h>
6263
#include <net/net_namespace.h>
6364

@@ -122,6 +123,7 @@ struct bcm_op {
122123
struct canfd_frame last_sframe;
123124
struct sock *sk;
124125
struct net_device *rx_reg_dev;
126+
spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */
125127
};
126128

127129
struct bcm_sock {
@@ -217,7 +219,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
217219
seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
218220
seq_printf(m, " <<<\n");
219221

220-
list_for_each_entry(op, &bo->rx_ops, list) {
222+
rcu_read_lock();
223+
224+
list_for_each_entry_rcu(op, &bo->rx_ops, list) {
221225

222226
unsigned long reduction;
223227

@@ -273,6 +277,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
273277
seq_printf(m, "# sent %ld\n", op->frames_abs);
274278
}
275279
seq_putc(m, '\n');
280+
281+
rcu_read_unlock();
282+
276283
return 0;
277284
}
278285
#endif /* CONFIG_PROC_FS */
@@ -285,13 +292,18 @@ static void bcm_can_tx(struct bcm_op *op)
285292
{
286293
struct sk_buff *skb;
287294
struct net_device *dev;
288-
struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe;
295+
struct canfd_frame *cf;
289296
int err;
290297

291298
/* no target device? => exit */
292299
if (!op->ifindex)
293300
return;
294301

302+
/* read currframe under lock protection */
303+
spin_lock_bh(&op->bcm_tx_lock);
304+
cf = op->frames + op->cfsiz * op->currframe;
305+
spin_unlock_bh(&op->bcm_tx_lock);
306+
295307
dev = dev_get_by_index(sock_net(op->sk), op->ifindex);
296308
if (!dev) {
297309
/* RFC: should this bcm_op remove itself here? */
@@ -312,6 +324,10 @@ static void bcm_can_tx(struct bcm_op *op)
312324
skb->dev = dev;
313325
can_skb_set_owner(skb, op->sk);
314326
err = can_send(skb, 1);
327+
328+
/* update currframe and count under lock protection */
329+
spin_lock_bh(&op->bcm_tx_lock);
330+
315331
if (!err)
316332
op->frames_abs++;
317333

@@ -320,6 +336,11 @@ static void bcm_can_tx(struct bcm_op *op)
320336
/* reached last frame? */
321337
if (op->currframe >= op->nframes)
322338
op->currframe = 0;
339+
340+
if (op->count > 0)
341+
op->count--;
342+
343+
spin_unlock_bh(&op->bcm_tx_lock);
323344
out:
324345
dev_put(dev);
325346
}
@@ -430,7 +451,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
430451
struct bcm_msg_head msg_head;
431452

432453
if (op->kt_ival1 && (op->count > 0)) {
433-
op->count--;
454+
bcm_can_tx(op);
434455
if (!op->count && (op->flags & TX_COUNTEVT)) {
435456

436457
/* create notification to user */
@@ -445,7 +466,6 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
445466

446467
bcm_send_to_user(op, &msg_head, NULL, 0);
447468
}
448-
bcm_can_tx(op);
449469

450470
} else if (op->kt_ival2) {
451471
bcm_can_tx(op);
@@ -843,7 +863,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
843863
REGMASK(op->can_id),
844864
bcm_rx_handler, op);
845865

846-
list_del(&op->list);
866+
list_del_rcu(&op->list);
847867
bcm_remove_op(op);
848868
return 1; /* done */
849869
}
@@ -863,7 +883,7 @@ static int bcm_delete_tx_op(struct list_head *ops, struct bcm_msg_head *mh,
863883
list_for_each_entry_safe(op, n, ops, list) {
864884
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
865885
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
866-
list_del(&op->list);
886+
list_del_rcu(&op->list);
867887
bcm_remove_op(op);
868888
return 1; /* done */
869889
}
@@ -956,16 +976,42 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
956976
}
957977
op->flags = msg_head->flags;
958978

979+
/* only lock for unlikely count/nframes/currframe changes */
980+
if (op->nframes != msg_head->nframes ||
981+
op->flags & TX_RESET_MULTI_IDX ||
982+
op->flags & SETTIMER) {
983+
984+
spin_lock_bh(&op->bcm_tx_lock);
985+
986+
if (op->nframes != msg_head->nframes ||
987+
op->flags & TX_RESET_MULTI_IDX) {
988+
/* potentially update changed nframes */
989+
op->nframes = msg_head->nframes;
990+
/* restart multiple frame transmission */
991+
op->currframe = 0;
992+
}
993+
994+
if (op->flags & SETTIMER)
995+
op->count = msg_head->count;
996+
997+
spin_unlock_bh(&op->bcm_tx_lock);
998+
}
999+
9591000
} else {
9601001
/* insert new BCM operation for the given can_id */
9611002

9621003
op = kzalloc(OPSIZ, GFP_KERNEL);
9631004
if (!op)
9641005
return -ENOMEM;
9651006

1007+
spin_lock_init(&op->bcm_tx_lock);
9661008
op->can_id = msg_head->can_id;
9671009
op->cfsiz = CFSIZ(msg_head->flags);
9681010
op->flags = msg_head->flags;
1011+
op->nframes = msg_head->nframes;
1012+
1013+
if (op->flags & SETTIMER)
1014+
op->count = msg_head->count;
9691015

9701016
/* create array for CAN frames and copy the data */
9711017
if (msg_head->nframes > 1) {
@@ -1023,22 +1069,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
10231069

10241070
} /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */
10251071

1026-
if (op->nframes != msg_head->nframes) {
1027-
op->nframes = msg_head->nframes;
1028-
/* start multiple frame transmission with index 0 */
1029-
op->currframe = 0;
1030-
}
1031-
1032-
/* check flags */
1033-
1034-
if (op->flags & TX_RESET_MULTI_IDX) {
1035-
/* start multiple frame transmission with index 0 */
1036-
op->currframe = 0;
1037-
}
1038-
10391072
if (op->flags & SETTIMER) {
10401073
/* set timer values */
1041-
op->count = msg_head->count;
10421074
op->ival1 = msg_head->ival1;
10431075
op->ival2 = msg_head->ival2;
10441076
op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
@@ -1055,11 +1087,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
10551087
op->flags |= TX_ANNOUNCE;
10561088
}
10571089

1058-
if (op->flags & TX_ANNOUNCE) {
1090+
if (op->flags & TX_ANNOUNCE)
10591091
bcm_can_tx(op);
1060-
if (op->count)
1061-
op->count--;
1062-
}
10631092

10641093
if (op->flags & STARTTIMER)
10651094
bcm_tx_start_timer(op);
@@ -1272,7 +1301,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
12721301
bcm_rx_handler, op, "bcm", sk);
12731302
if (err) {
12741303
/* this bcm rx op is broken -> remove it */
1275-
list_del(&op->list);
1304+
list_del_rcu(&op->list);
12761305
bcm_remove_op(op);
12771306
return err;
12781307
}

0 commit comments

Comments
 (0)