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>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/can/microchip,mcp2510.yaml#
|
||||
$id: http://devicetree.org/schemas/net/can/microchip,mcp2510.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip MCP251X stand-alone CAN controller
|
||||
|
||||
+54
-25
@@ -58,6 +58,7 @@
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/bcm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
@@ -122,6 +123,7 @@ struct bcm_op {
|
||||
struct canfd_frame last_sframe;
|
||||
struct sock *sk;
|
||||
struct net_device *rx_reg_dev;
|
||||
spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */
|
||||
};
|
||||
|
||||
struct bcm_sock {
|
||||
@@ -217,7 +219,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
|
||||
seq_printf(m, " <<<\n");
|
||||
|
||||
list_for_each_entry(op, &bo->rx_ops, list) {
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(op, &bo->rx_ops, list) {
|
||||
|
||||
unsigned long reduction;
|
||||
|
||||
@@ -273,6 +277,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "# sent %ld\n", op->frames_abs);
|
||||
}
|
||||
seq_putc(m, '\n');
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
@@ -285,13 +292,18 @@ static void bcm_can_tx(struct bcm_op *op)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct net_device *dev;
|
||||
struct canfd_frame *cf = op->frames + op->cfsiz * op->currframe;
|
||||
struct canfd_frame *cf;
|
||||
int err;
|
||||
|
||||
/* no target device? => exit */
|
||||
if (!op->ifindex)
|
||||
return;
|
||||
|
||||
/* read currframe under lock protection */
|
||||
spin_lock_bh(&op->bcm_tx_lock);
|
||||
cf = op->frames + op->cfsiz * op->currframe;
|
||||
spin_unlock_bh(&op->bcm_tx_lock);
|
||||
|
||||
dev = dev_get_by_index(sock_net(op->sk), op->ifindex);
|
||||
if (!dev) {
|
||||
/* RFC: should this bcm_op remove itself here? */
|
||||
@@ -312,6 +324,10 @@ static void bcm_can_tx(struct bcm_op *op)
|
||||
skb->dev = dev;
|
||||
can_skb_set_owner(skb, op->sk);
|
||||
err = can_send(skb, 1);
|
||||
|
||||
/* update currframe and count under lock protection */
|
||||
spin_lock_bh(&op->bcm_tx_lock);
|
||||
|
||||
if (!err)
|
||||
op->frames_abs++;
|
||||
|
||||
@@ -320,6 +336,11 @@ static void bcm_can_tx(struct bcm_op *op)
|
||||
/* reached last frame? */
|
||||
if (op->currframe >= op->nframes)
|
||||
op->currframe = 0;
|
||||
|
||||
if (op->count > 0)
|
||||
op->count--;
|
||||
|
||||
spin_unlock_bh(&op->bcm_tx_lock);
|
||||
out:
|
||||
dev_put(dev);
|
||||
}
|
||||
@@ -430,7 +451,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
|
||||
struct bcm_msg_head msg_head;
|
||||
|
||||
if (op->kt_ival1 && (op->count > 0)) {
|
||||
op->count--;
|
||||
bcm_can_tx(op);
|
||||
if (!op->count && (op->flags & TX_COUNTEVT)) {
|
||||
|
||||
/* create notification to user */
|
||||
@@ -445,7 +466,6 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
|
||||
|
||||
bcm_send_to_user(op, &msg_head, NULL, 0);
|
||||
}
|
||||
bcm_can_tx(op);
|
||||
|
||||
} else if (op->kt_ival2) {
|
||||
bcm_can_tx(op);
|
||||
@@ -843,7 +863,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
|
||||
REGMASK(op->can_id),
|
||||
bcm_rx_handler, op);
|
||||
|
||||
list_del(&op->list);
|
||||
list_del_rcu(&op->list);
|
||||
bcm_remove_op(op);
|
||||
return 1; /* done */
|
||||
}
|
||||
@@ -863,7 +883,7 @@ static int bcm_delete_tx_op(struct list_head *ops, struct bcm_msg_head *mh,
|
||||
list_for_each_entry_safe(op, n, ops, list) {
|
||||
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
|
||||
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
|
||||
list_del(&op->list);
|
||||
list_del_rcu(&op->list);
|
||||
bcm_remove_op(op);
|
||||
return 1; /* done */
|
||||
}
|
||||
@@ -956,6 +976,27 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||
}
|
||||
op->flags = msg_head->flags;
|
||||
|
||||
/* only lock for unlikely count/nframes/currframe changes */
|
||||
if (op->nframes != msg_head->nframes ||
|
||||
op->flags & TX_RESET_MULTI_IDX ||
|
||||
op->flags & SETTIMER) {
|
||||
|
||||
spin_lock_bh(&op->bcm_tx_lock);
|
||||
|
||||
if (op->nframes != msg_head->nframes ||
|
||||
op->flags & TX_RESET_MULTI_IDX) {
|
||||
/* potentially update changed nframes */
|
||||
op->nframes = msg_head->nframes;
|
||||
/* restart multiple frame transmission */
|
||||
op->currframe = 0;
|
||||
}
|
||||
|
||||
if (op->flags & SETTIMER)
|
||||
op->count = msg_head->count;
|
||||
|
||||
spin_unlock_bh(&op->bcm_tx_lock);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* insert new BCM operation for the given can_id */
|
||||
|
||||
@@ -963,9 +1004,14 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||
if (!op)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&op->bcm_tx_lock);
|
||||
op->can_id = msg_head->can_id;
|
||||
op->cfsiz = CFSIZ(msg_head->flags);
|
||||
op->flags = msg_head->flags;
|
||||
op->nframes = msg_head->nframes;
|
||||
|
||||
if (op->flags & SETTIMER)
|
||||
op->count = msg_head->count;
|
||||
|
||||
/* create array for CAN frames and copy the data */
|
||||
if (msg_head->nframes > 1) {
|
||||
@@ -1023,22 +1069,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||
|
||||
} /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */
|
||||
|
||||
if (op->nframes != msg_head->nframes) {
|
||||
op->nframes = msg_head->nframes;
|
||||
/* start multiple frame transmission with index 0 */
|
||||
op->currframe = 0;
|
||||
}
|
||||
|
||||
/* check flags */
|
||||
|
||||
if (op->flags & TX_RESET_MULTI_IDX) {
|
||||
/* start multiple frame transmission with index 0 */
|
||||
op->currframe = 0;
|
||||
}
|
||||
|
||||
if (op->flags & SETTIMER) {
|
||||
/* set timer values */
|
||||
op->count = msg_head->count;
|
||||
op->ival1 = msg_head->ival1;
|
||||
op->ival2 = msg_head->ival2;
|
||||
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,
|
||||
op->flags |= TX_ANNOUNCE;
|
||||
}
|
||||
|
||||
if (op->flags & TX_ANNOUNCE) {
|
||||
if (op->flags & TX_ANNOUNCE)
|
||||
bcm_can_tx(op);
|
||||
if (op->count)
|
||||
op->count--;
|
||||
}
|
||||
|
||||
if (op->flags & STARTTIMER)
|
||||
bcm_tx_start_timer(op);
|
||||
@@ -1272,7 +1301,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||
bcm_rx_handler, op, "bcm", sk);
|
||||
if (err) {
|
||||
/* this bcm rx op is broken -> remove it */
|
||||
list_del(&op->list);
|
||||
list_del_rcu(&op->list);
|
||||
bcm_remove_op(op);
|
||||
return err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user