From 5145bb6a2c2683d541828f86d5321e0565f2e30c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 7 Sep 2026 07:58:38 +0000 Subject: [PATCH] sit: fix UAF in ipip6_tunnel_del_prl() When flushing all potential router list (PRL) entries, ipip6_tunnel_del_prl() called call_rcu(&x->rcu_head, prl_list_destroy_rcu) before clearing t->prl. A concurrent reader in isatap_chksrc() could enter an RCU read-side critical section after call_rcu() but before t->prl is set to NULL, allowing prl_list_destroy_rcu() to free nodes while the reader traverses them. Clear t->prl using RCU_INIT_POINTER() before invoking call_rcu(). Also use rcu_assign_pointer() when unlinking individual entries. Fixes: ef9a9d1183b3 ("ipv6 sit: RCU conversion phase I") Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260907075846.2913645-2-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/sit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 19b7fa8d1a2a..4438b2472b28 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -436,7 +436,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) (x = rtnl_dereference(*p)) != NULL; p = &x->next) { if (x->addr == a->addr) { - *p = x->next; + rcu_assign_pointer(*p, rtnl_dereference(x->next)); kfree_rcu(x, rcu_head); t->prl_count--; goto out; @@ -447,8 +447,8 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) x = rtnl_dereference(t->prl); if (x) { t->prl_count = 0; + RCU_INIT_POINTER(t->prl, NULL); call_rcu(&x->rcu_head, prl_list_destroy_rcu); - t->prl = NULL; } } out: