Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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/20250520091424.142121-1-mkl@pengutronix.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

Paolo Abeni 9e89db3d 239af197

+55 -26
+1 -1
Documentation/devicetree/bindings/net/can/microchip,mcp2510.yaml
··· 1 1 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 2 %YAML 1.2 3 3 --- 4 - $id: http://devicetree.org/schemas/can/microchip,mcp2510.yaml# 4 + $id: http://devicetree.org/schemas/net/can/microchip,mcp2510.yaml# 5 5 $schema: http://devicetree.org/meta-schemas/core.yaml# 6 6 7 7 title: Microchip MCP251X stand-alone CAN controller
+54 -25
net/can/bcm.c
··· 58 58 #include <linux/can/skb.h> 59 59 #include <linux/can/bcm.h> 60 60 #include <linux/slab.h> 61 + #include <linux/spinlock.h> 61 62 #include <net/sock.h> 62 63 #include <net/net_namespace.h> 63 64 ··· 123 122 struct canfd_frame last_sframe; 124 123 struct sock *sk; 125 124 struct net_device *rx_reg_dev; 125 + spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */ 126 126 }; 127 127 128 128 struct bcm_sock { ··· 219 217 seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex)); 220 218 seq_printf(m, " <<<\n"); 221 219 222 - list_for_each_entry(op, &bo->rx_ops, list) { 220 + rcu_read_lock(); 221 + 222 + list_for_each_entry_rcu(op, &bo->rx_ops, list) { 223 223 224 224 unsigned long reduction; 225 225 ··· 277 273 seq_printf(m, "# sent %ld\n", op->frames_abs); 278 274 } 279 275 seq_putc(m, '\n'); 276 + 277 + rcu_read_unlock(); 278 + 280 279 return 0; 281 280 } 282 281 #endif /* CONFIG_PROC_FS */ ··· 292 285 { 293 286 struct sk_buff *skb; 294 287 struct net_device *dev; 295 - struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe; 288 + struct canfd_frame *cf; 296 289 int err; 297 290 298 291 /* no target device? => exit */ 299 292 if (!op->ifindex) 300 293 return; 294 + 295 + /* read currframe under lock protection */ 296 + spin_lock_bh(&op->bcm_tx_lock); 297 + cf = op->frames + op->cfsiz * op->currframe; 298 + spin_unlock_bh(&op->bcm_tx_lock); 301 299 302 300 dev = dev_get_by_index(sock_net(op->sk), op->ifindex); 303 301 if (!dev) { ··· 324 312 skb->dev = dev; 325 313 can_skb_set_owner(skb, op->sk); 326 314 err = can_send(skb, 1); 315 + 316 + /* update currframe and count under lock protection */ 317 + spin_lock_bh(&op->bcm_tx_lock); 318 + 327 319 if (!err) 328 320 op->frames_abs++; 329 321 ··· 336 320 /* reached last frame? */ 337 321 if (op->currframe >= op->nframes) 338 322 op->currframe = 0; 323 + 324 + if (op->count > 0) 325 + op->count--; 326 + 327 + spin_unlock_bh(&op->bcm_tx_lock); 339 328 out: 340 329 dev_put(dev); 341 330 } ··· 451 430 struct bcm_msg_head msg_head; 452 431 453 432 if (op->kt_ival1 && (op->count > 0)) { 454 - op->count--; 433 + bcm_can_tx(op); 455 434 if (!op->count && (op->flags & TX_COUNTEVT)) { 456 435 457 436 /* create notification to user */ ··· 466 445 467 446 bcm_send_to_user(op, &msg_head, NULL, 0); 468 447 } 469 - bcm_can_tx(op); 470 448 471 449 } else if (op->kt_ival2) { 472 450 bcm_can_tx(op); ··· 863 843 REGMASK(op->can_id), 864 844 bcm_rx_handler, op); 865 845 866 - list_del(&op->list); 846 + list_del_rcu(&op->list); 867 847 bcm_remove_op(op); 868 848 return 1; /* done */ 869 849 } ··· 883 863 list_for_each_entry_safe(op, n, ops, list) { 884 864 if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) && 885 865 (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) { 886 - list_del(&op->list); 866 + list_del_rcu(&op->list); 887 867 bcm_remove_op(op); 888 868 return 1; /* done */ 889 869 } ··· 976 956 } 977 957 op->flags = msg_head->flags; 978 958 959 + /* only lock for unlikely count/nframes/currframe changes */ 960 + if (op->nframes != msg_head->nframes || 961 + op->flags & TX_RESET_MULTI_IDX || 962 + op->flags & SETTIMER) { 963 + 964 + spin_lock_bh(&op->bcm_tx_lock); 965 + 966 + if (op->nframes != msg_head->nframes || 967 + op->flags & TX_RESET_MULTI_IDX) { 968 + /* potentially update changed nframes */ 969 + op->nframes = msg_head->nframes; 970 + /* restart multiple frame transmission */ 971 + op->currframe = 0; 972 + } 973 + 974 + if (op->flags & SETTIMER) 975 + op->count = msg_head->count; 976 + 977 + spin_unlock_bh(&op->bcm_tx_lock); 978 + } 979 + 979 980 } else { 980 981 /* insert new BCM operation for the given can_id */ 981 982 ··· 1004 963 if (!op) 1005 964 return -ENOMEM; 1006 965 966 + spin_lock_init(&op->bcm_tx_lock); 1007 967 op->can_id = msg_head->can_id; 1008 968 op->cfsiz = CFSIZ(msg_head->flags); 1009 969 op->flags = msg_head->flags; 970 + op->nframes = msg_head->nframes; 971 + 972 + if (op->flags & SETTIMER) 973 + op->count = msg_head->count; 1010 974 1011 975 /* create array for CAN frames and copy the data */ 1012 976 if (msg_head->nframes > 1) { ··· 1069 1023 1070 1024 } /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */ 1071 1025 1072 - if (op->nframes != msg_head->nframes) { 1073 - op->nframes = msg_head->nframes; 1074 - /* start multiple frame transmission with index 0 */ 1075 - op->currframe = 0; 1076 - } 1077 - 1078 - /* check flags */ 1079 - 1080 - if (op->flags & TX_RESET_MULTI_IDX) { 1081 - /* start multiple frame transmission with index 0 */ 1082 - op->currframe = 0; 1083 - } 1084 - 1085 1026 if (op->flags & SETTIMER) { 1086 1027 /* set timer values */ 1087 - op->count = msg_head->count; 1088 1028 op->ival1 = msg_head->ival1; 1089 1029 op->ival2 = msg_head->ival2; 1090 1030 op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1); ··· 1087 1055 op->flags |= TX_ANNOUNCE; 1088 1056 } 1089 1057 1090 - if (op->flags & TX_ANNOUNCE) { 1058 + if (op->flags & TX_ANNOUNCE) 1091 1059 bcm_can_tx(op); 1092 - if (op->count) 1093 - op->count--; 1094 - } 1095 1060 1096 1061 if (op->flags & STARTTIMER) 1097 1062 bcm_tx_start_timer(op); ··· 1301 1272 bcm_rx_handler, op, "bcm", sk); 1302 1273 if (err) { 1303 1274 /* this bcm rx op is broken -> remove it */ 1304 - list_del(&op->list); 1275 + list_del_rcu(&op->list); 1305 1276 bcm_remove_op(op); 1306 1277 return err; 1307 1278 }