can: raw: fix ro->uniq use-after-free in raw_rcv()
Subsystems (3)
Oliver Hartkopp
maintainerPATCH 1/1 can: raw: fix ro->uniq use-after-free in raw_rcv()
From: Samuel Page <[email protected]>
raw_release() unregisters raw CAN receive filters via can_rx_unregister(), but receiver deletion is deferred with call_rcu(). This leaves a window where raw_rcv() may still be running in an RCU read-side critical section after raw_release() frees ro->uniq, leading to a use-after-free of the percpu uniq storage.
Move free_percpu(ro->uniq) out of raw_release() and into a raw-specific socket destructor. can_rx_unregister() takes an extra reference to the socket and only drops it from the RCU callback, so freeing uniq from sk_destruct ensures the percpu area is not released until the relevant callbacks have drained.
Fixes 514ac99c64b2 ("can: fix multiple delivery of a single CAN frame for overlapping CAN filters")
Cc [email protected] # v4.1+
Assisted-by Bynario AI
Signed-off-by Samuel Page <[email protected]>
Acked-by Oliver Hartkopp <[email protected]>
--- net/can/raw.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
net/can/raw.c +10 -1
@@ -361,6 +361,14 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg,return NOTIFY_DONE ; } +static void raw_sock_destruct (struct sock *sk) +{ +struct raw_sock *ro =raw_sk (sk); + +free_percpu (ro->uniq); +can_sock_destruct (sk); +} +static int raw_init (struct sock *sk) {struct raw_sock *ro =raw_sk (sk);
@@ -387,6 +395,8 @@ static int raw_init(struct sock *sk)if (unlikely (!ro->uniq))return -ENOMEM ; + sk->sk_destruct = raw_sock_destruct; +/* set notifier */ spin_lock (&raw_notifier_lock);list_add_tail (&ro->notifier, &raw_notifier_list);
@@ -436,7 +446,6 @@ static int raw_release(struct socket *sock) ro->bound =0 ; ro->dev =NULL ; ro->count =0 ; -free_percpu (ro->uniq);sock_orphan (sk); sock->sk =NULL ;
Signature · 1 line
2.53.0