Commit dac5e624 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Marc Kleine-Budde
Browse files

can: bcm: add missing rcu read protection for procfs content



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: f1b4e32a ("can: bcm: use call_rcu() instead of costly synchronize_rcu()")
Reported-by: default avatarAnderson Nascimento <anderson@allelesecurity.com>
Suggested-by: default avatarAnderson Nascimento <anderson@allelesecurity.com>
Tested-by: default avatarAnderson Nascimento <anderson@allelesecurity.com>
Signed-off-by: default avatarOliver 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: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent c2aba69d
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -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;
		}