]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
can: bcm: add missing rcu read protection for procfs content
authorOliver Hartkopp <socketcan@hartkopp.net>
Mon, 19 May 2025 12:50:27 +0000 (14:50 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Mon, 19 May 2025 14:58:19 +0000 (16:58 +0200)
When the procfs content is generated for a bcm_op which is in the process
to be removed the procfs output might show unreliable data (UAF).

As the removal of bcm_op's is already implemented with rcu handling this
patch adds the missing rcu_read_lock() and makes sure the list entries
are properly removed under rcu protection.

Fixes: f1b4e32aca08 ("can: bcm: use call_rcu() instead of costly synchronize_rcu()")
Reported-by: Anderson Nascimento <anderson@allelesecurity.com>
Suggested-by: Anderson Nascimento <anderson@allelesecurity.com>
Tested-by: Anderson Nascimento <anderson@allelesecurity.com>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20250519125027.11900-2-socketcan@hartkopp.net
Cc: stable@vger.kernel.org # >= 5.4
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
net/can/bcm.c

index 871707dab7db6135c5c4716c7224337b2ab8458c..6bc1cc4c94c5ef360807a61591d0a818fec8853b 100644 (file)
@@ -219,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;
 
@@ -275,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 */
@@ -858,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 */
                }
@@ -878,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 */
                }
@@ -1296,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;
                }