]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
can: bcm: add missing rcu list annotations and operations
authorOliver Hartkopp <socketcan@hartkopp.net>
Tue, 14 Jul 2026 16:55:27 +0000 (18:55 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Thu, 16 Jul 2026 08:01:52 +0000 (10:01 +0200)
sashiko-bot remarked the missing use of list_add_rcu() in
bcm_[rx|tx]_setup() to have a proper initialized bcm_op structure
when bcm_proc_show() traverses the bcm_op's under rcu_read_lock().

To cover all initial settings of the bcm_op's the list_add_rcu() calls
are moved to the end of the setup code.

While at it, also fix the mirroring removal side: bcm_release() called
bcm_remove_op() - which frees the op via call_rcu() - on ops that were
still linked in bo->tx_ops/bo->rx_ops, without list_del_rcu() first.
Unlink each op with list_del_rcu() before handing it to bcm_remove_op(),
matching the existing pattern in bcm_delete_tx_op()/bcm_delete_rx_op().

Reported-by: sashiko-reviews@lists.linux.dev
Closes: https://lore.kernel.org/linux-can/20260610094654.A1FFE1F00893@smtp.kernel.org/
Fixes: dac5e6249159 ("can: bcm: add missing rcu read protection for procfs content")
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260714-bcm_fixes-v15-5-562f7e3e42da@hartkopp.net
Cc: stable@kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
net/can/bcm.c

index 03c98e4cc677d71c02d14a0c58509725f8ae63d3..5c1e83eeb4ff3dda445ab3db4e207119da2ad0a4 100644 (file)
@@ -265,7 +265,7 @@ static int bcm_proc_show(struct seq_file *m, void *v)
                           (reduction == 100) ? "near " : "", reduction);
        }
 
-       list_for_each_entry(op, &bo->tx_ops, list) {
+       list_for_each_entry_rcu(op, &bo->tx_ops, list) {
 
                seq_printf(m, "tx_op: %03X %s ", op->can_id,
                           bcm_proc_getifname(net, ifname, op->ifindex));
@@ -1017,6 +1017,7 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
        struct bcm_sock *bo = bcm_sk(sk);
        struct bcm_op *op;
        struct canfd_frame *cf;
+       bool add_op_to_list = false;
        unsigned int i;
        int err;
 
@@ -1158,8 +1159,7 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                hrtimer_setup(&op->thrtimer, hrtimer_dummy_timeout, CLOCK_MONOTONIC,
                              HRTIMER_MODE_REL_SOFT);
 
-               /* add this bcm_op to the list of the tx_ops */
-               list_add(&op->list, &bo->tx_ops);
+               add_op_to_list = true;
 
        } /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */
 
@@ -1181,6 +1181,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                op->flags |= TX_ANNOUNCE;
        }
 
+       /* add this bcm_op to the list of the tx_ops? */
+       if (add_op_to_list)
+               list_add_rcu(&op->list, &bo->tx_ops);
+
        if (op->flags & TX_ANNOUNCE)
                bcm_can_tx(op, NULL);
 
@@ -1373,9 +1377,6 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                hrtimer_setup(&op->thrtimer, bcm_rx_thr_handler, CLOCK_MONOTONIC,
                              HRTIMER_MODE_REL_SOFT);
 
-               /* add this bcm_op to the list of the rx_ops */
-               list_add(&op->list, &bo->rx_ops);
-
                /* call can_rx_register() */
                do_rx_register = 1;
 
@@ -1449,10 +1450,12 @@ 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_rcu(&op->list);
                        bcm_remove_op(op);
                        return err;
                }
+
+               /* add this bcm_op to the list of the rx_ops */
+               list_add_rcu(&op->list, &bo->rx_ops);
        }
 
        return msg_head->nframes * op->cfsiz + MHSIZ;
@@ -1786,8 +1789,10 @@ static int bcm_release(struct socket *sock)
                remove_proc_entry(bo->procname, net->can.bcmproc_dir);
 #endif /* CONFIG_PROC_FS */
 
-       list_for_each_entry_safe(op, next, &bo->tx_ops, list)
+       list_for_each_entry_safe(op, next, &bo->tx_ops, list) {
+               list_del_rcu(&op->list);
                bcm_remove_op(op);
+       }
 
        list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
                /*
@@ -1818,8 +1823,10 @@ static int bcm_release(struct socket *sock)
 
        synchronize_rcu();
 
-       list_for_each_entry_safe(op, next, &bo->rx_ops, list)
+       list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
+               list_del_rcu(&op->list);
                bcm_remove_op(op);
+       }
 
        /* remove device reference */
        if (bo->bound) {