can: bcm: add missing rcu read protection for procfs content
commit dac5e6249159ac255dad9781793dbe5908ac9ddb upstream.
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: f1b4e32aca
("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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
76c84c3728
commit
1f912f8484
@@ -207,7 +207,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, " / bound %s", bcm_proc_getifname(net, ifname, bo->ifindex));
|
||||||
seq_printf(m, " <<<\n");
|
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;
|
unsigned long reduction;
|
||||||
|
|
||||||
@@ -263,6 +265,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
|
|||||||
seq_printf(m, "# sent %ld\n", op->frames_abs);
|
seq_printf(m, "# sent %ld\n", op->frames_abs);
|
||||||
}
|
}
|
||||||
seq_putc(m, '\n');
|
seq_putc(m, '\n');
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PROC_FS */
|
#endif /* CONFIG_PROC_FS */
|
||||||
@@ -816,7 +821,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
|
|||||||
REGMASK(op->can_id),
|
REGMASK(op->can_id),
|
||||||
bcm_rx_handler, op);
|
bcm_rx_handler, op);
|
||||||
|
|
||||||
list_del(&op->list);
|
list_del_rcu(&op->list);
|
||||||
bcm_remove_op(op);
|
bcm_remove_op(op);
|
||||||
return 1; /* done */
|
return 1; /* done */
|
||||||
}
|
}
|
||||||
@@ -836,7 +841,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) {
|
list_for_each_entry_safe(op, n, ops, list) {
|
||||||
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
|
if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
|
||||||
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
|
(op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
|
||||||
list_del(&op->list);
|
list_del_rcu(&op->list);
|
||||||
bcm_remove_op(op);
|
bcm_remove_op(op);
|
||||||
return 1; /* done */
|
return 1; /* done */
|
||||||
}
|
}
|
||||||
@@ -1258,7 +1263,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
|||||||
bcm_rx_handler, op, "bcm", sk);
|
bcm_rx_handler, op, "bcm", sk);
|
||||||
if (err) {
|
if (err) {
|
||||||
/* this bcm rx op is broken -> remove it */
|
/* this bcm rx op is broken -> remove it */
|
||||||
list_del(&op->list);
|
list_del_rcu(&op->list);
|
||||||
bcm_remove_op(op);
|
bcm_remove_op(op);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user