[PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice
From: Norbert Szetei
Date: Mon Sep 28 2026 - 13:45:33 EST
reuseport_stop_listen_sock() moves a shutdown()ed listener from the
listening section of reuse->socks[] to the closed section: it removes the
socket with __reuseport_detach_sock() and adds it back with
__reuseport_add_closed_sock(). The return value of the removal is
discarded and the add runs unconditionally.
The socket need not be in the listening section. inet_unhash() calls
reuseport_stop_listen_sock() for a listener whenever sk->sk_reuseport_cb
is set, but inet_hash() enters the reuseport path only when
sk->sk_reuseport is set, and SO_REUSEPORT can be cleared in any state.
Clearing it between shutdown() and listen() makes that listen() skip
reuseport_add_sock(), and with it reuseport_resurrect(), so the socket is
hashed as a listener while it is still in the closed section. On the next
shutdown() __reuseport_detach_sock() does not find it in the listening
section, returns false, and __reuseport_add_closed_sock() adds a second
copy of it to socks[].
sk_destruct() calls reuseport_detach_sock(), which removes one of the two
entries. reuseport_grow() then dereferences the other one, because its
loop runs over every slot up to reuse->max_socks:
BUG: KASAN: slab-use-after-free in reuseport_grow (net/core/sock_reuseport.c:291)
Write of size 8 at addr ffff888132359988 by task poc/621
reuseport_grow (net/core/sock_reuseport.c:291)
reuseport_add_sock (net/core/sock_reuseport.c:350)
inet_hash (net/ipv4/inet_hashtables.c:810)
inet_csk_listen_start (net/ipv4/inet_connection_sock.c:1359)
__inet_listen_sk (net/ipv4/af_inet.c:225)
inet_listen (net/ipv4/af_inet.c:247)
__sys_listen (net/socket.c:2014)
Allocated by task 621:
sk_prot_alloc (net/core/sock.c:2246)
sk_alloc (net/core/sock.c:2308)
inet_create (net/ipv4/af_inet.c:333)
Freed by task 0:
slab_free_after_rcu_debug (mm/slub.c:6570)
rcu_core (kernel/rcu/tree.c:2919)
The buggy address is located 904 bytes inside of
freed 2624-byte region [ffff888132359600, ffff88813235a040)
Only move the socket to the closed section when __reuseport_detach_sock()
reports that it was removed from the listening section.
Fixes: 333bb73f620e ("tcp: Keep TCP_CLOSE sockets in the reuseport group.")
Assisted-by: LLM
Signed-off-by: Norbert Szetei <norbert@xxxxxxxxxxxx>
---
net/core/sock_reuseport.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/core/sock_reuseport.c b/net/core/sock_reuseport.c
index 29948cb44b7d..031b641be317 100644
--- a/net/core/sock_reuseport.c
+++ b/net/core/sock_reuseport.c
@@ -479,8 +479,8 @@ void reuseport_stop_listen_sock(struct sock *sk)
*/
bpf_sk_reuseport_detach(sk);
- __reuseport_detach_sock(sk, reuse);
- __reuseport_add_closed_sock(sk, reuse);
+ if (__reuseport_detach_sock(sk, reuse))
+ __reuseport_add_closed_sock(sk, reuse);
spin_unlock_bh(&reuseport_lock);
return;
--
2.55.0