mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-10-26 10:57:38 +08:00
rtnetlink: wait for RCU readers in rtnl_link_unregister()
rtnl_link_ops_get() finds ops on link_ops under rcu_read_lock() and only
then takes ops->srcu. rtnl_link_unregister() unlinks ops, then calls
synchronize_srcu() and cleanup_srcu_struct() without first waiting for
RCU readers. A reader that found ops before list_del_rcu() and has not yet
taken ops->srcu is not waited for.
Such a reader then locks a cleaned-up srcu_struct and keeps using ops
after the module that owns it is gone. rtnl_newlink() and
rtnl_dump_ifinfo() both look up ops without RTNL, the latter for any
user that dumps links filtered by kind.
With delays added between the lookup and srcu_read_lock() in
rtnl_link_ops_get(), and before rtnl_link_ops_put() in
rtnl_dump_ifinfo(), running "ip link show type dummy" alongside
"rmmod dummy" on a KASAN kernel gives:
BUG: KASAN: vmalloc-out-of-bounds in __srcu_read_unlock+0x57/0x70
Read of size 8 at addr ffffffffc02ff318 by task ip/147
Call Trace:
__srcu_read_unlock+0x57/0x70
rtnl_dump_ifinfo.cold+0x30/0x3b
rtnl_dumpit+0x7a/0x1b0
netlink_dump+0x486/0x11b0
__netlink_dump_start+0x661/0x910
rtnetlink_rcv_msg+0x611/0x9e0
netlink_rcv_skb+0x126/0x380
netlink_unicast+0x605/0x830
netlink_sendmsg+0x6d0/0xbb0
__sys_sendto+0x335/0x3a0
Call synchronize_rcu() before synchronize_srcu(), as
rtnl_af_unregister() already does. This should be enough because
rtnl_link_ops_get() is the only RCU walker of link_ops, and it takes
ops->srcu before rcu_read_unlock(), so every reader that found ops is
covered by synchronize_srcu() once the RCU grace period ends. The extra
grace period only costs time at module unload.
Readers and the writer were serialized by RTNL until link_ops got its
own mutex, which is why the missing RCU wait did not matter before.
Cc: stable+noautosel@kernel.org # needs real net-admin (non-ns)
Fixes: 6b57ff21a3 ("rtnetlink: Protect link_ops by mutex.")
Reviewed-by: Eric Dumazet <edumazet@kernel.org>
Signed-off-by: Andrea Parri <parri.andrea@gmail.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20261001143040.28467-1-parri.andrea@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
1 parent
c0402d7640
commit
3b70edea39
1 file changed
+4
@@ -707,6 +707,10 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops)
|
||||
list_del_rcu(&ops->list);
|
||||
mutex_unlock(&link_ops_mutex);
|
||||
|
||||
/* Wait for rtnl_link_ops_get() readers that found ops but have
|
||||
* not yet taken ops->srcu.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
synchronize_srcu(&ops->srcu);
|
||||
cleanup_srcu_struct(&ops->srcu);
|
||||
|
||||
|
||||
Reference in new issue
Block a user