* [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice
@ 2026-09-28 17:22 Norbert Szetei
2026-09-28 17:45 ` Kuniyuki Iwashima
2026-09-30 17:24 ` netdev-bot+sashiko
0 siblings, 2 replies; 5+ messages in thread
From: Norbert Szetei @ 2026-09-28 17:22 UTC (permalink / raw)
To: netdev
Cc: Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
David S. Miller, Jakub Kicinski, Simon Horman, Martin KaFai Lau,
Daniel Borkmann, linux-kernel
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@doyensec.com>
---
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
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice
2026-09-28 17:22 [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice Norbert Szetei
@ 2026-09-28 17:45 ` Kuniyuki Iwashima
2026-09-29 15:30 ` Norbert Szetei
2026-09-30 17:24 ` netdev-bot+sashiko
1 sibling, 1 reply; 5+ messages in thread
From: Kuniyuki Iwashima @ 2026-09-28 17:45 UTC (permalink / raw)
To: norbert
Cc: daniel, davem, edumazet, horms, kuba, kuniyu, linux-kernel,
martin.lau, netdev, pabeni, willemb
From: Norbert Szetei <norbert@doyensec.com>
Date: Mon, 28 Sep 2026 19:22:38 +0200
> 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.
This has long been a known problem, and I think it's time
to fix it instead of working around it:
diff --git a/net/core/sock.c b/net/core/sock.c
index 2948dffcc3e1..a33cdf99368d 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1324,6 +1324,8 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
case SO_REUSEPORT:
if (valbool && !sk_is_inet(sk))
ret = -EOPNOTSUPP;
+ else if (!valbool && rcu_access_pointer(sk->sk_reuseport_cb))
+ ret = -EBUSY;
else
sk->sk_reuseport = valbool;
break;
> 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@doyensec.com>
> ---
> 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
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice
2026-09-28 17:45 ` Kuniyuki Iwashima
@ 2026-09-29 15:30 ` Norbert Szetei
2026-09-29 18:31 ` Kuniyuki Iwashima
0 siblings, 1 reply; 5+ messages in thread
From: Norbert Szetei @ 2026-09-29 15:30 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: daniel, davem, edumazet, horms, kuba, linux-kernel, martin.lau,
netdev, pabeni, willemb
On Sep 28, 2026, at 19:45, Kuniyuki Iwashima <kuniyu@google.com> wrote:
> This has long been a known problem, and I think it's time
> to fix it instead of working around it:
>
> diff --git a/net/core/sock.c b/net/core/sock.c
> index 2948dffcc3e1..a33cdf99368d 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c
> @@ -1324,6 +1324,8 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
> case SO_REUSEPORT:
> if (valbool && !sk_is_inet(sk))
> ret = -EOPNOTSUPP;
> + else if (!valbool && rcu_access_pointer(sk->sk_reuseport_cb))
> + ret = -EBUSY;
> else
> sk->sk_reuseport = valbool;
> break;
Thanks for the suggestion. I tested it with my sock_reuseport.c change dropped
and I was not able to reproduce the issue, and migration and resurrect still
work.
One question before I send it as v2 with Suggested-by: you, unless you
would rather post it yourself.
Should the check be restricted to TCP?
else if (!valbool && sk->sk_protocol == IPPROTO_TCP &&
rcu_access_pointer(sk->sk_reuseport_cb))
ret = -EBUSY;
The closed section only exists for TCP, so TCP is the only protocol where
clearing the flag leads to the double add. With the check as it is, a bound
UDP socket also starts getting EBUSY from setsockopt(SO_REUSEPORT, 0).
N.
>> 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@doyensec.com>
>> ---
>> 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
>>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice
2026-09-29 15:30 ` Norbert Szetei
@ 2026-09-29 18:31 ` Kuniyuki Iwashima
0 siblings, 0 replies; 5+ messages in thread
From: Kuniyuki Iwashima @ 2026-09-29 18:31 UTC (permalink / raw)
To: Norbert Szetei
Cc: daniel, davem, edumazet, horms, kuba, linux-kernel, martin.lau,
netdev, pabeni, willemb
On Tue, Sep 29, 2026 at 8:31 AM Norbert Szetei <norbert@doyensec.com> wrote:
>
> On Sep 28, 2026, at 19:45, Kuniyuki Iwashima <kuniyu@google.com> wrote:
> > This has long been a known problem, and I think it's time
> > to fix it instead of working around it:
> >
> > diff --git a/net/core/sock.c b/net/core/sock.c
> > index 2948dffcc3e1..a33cdf99368d 100644
> > --- a/net/core/sock.c
> > +++ b/net/core/sock.c
> > @@ -1324,6 +1324,8 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
> > case SO_REUSEPORT:
> > if (valbool && !sk_is_inet(sk))
> > ret = -EOPNOTSUPP;
> > + else if (!valbool && rcu_access_pointer(sk->sk_reuseport_cb))
> > + ret = -EBUSY;
> > else
> > sk->sk_reuseport = valbool;
> > break;
>
> Thanks for the suggestion. I tested it with my sock_reuseport.c change dropped
> and I was not able to reproduce the issue, and migration and resurrect still
> work.
>
> One question before I send it as v2 with Suggested-by: you, unless you
> would rather post it yourself.
I had a few more patches in my local tree regarding this kind of bugs
but I didn't post them as I thought no one would stumble upon them,
but it's no longer the case, so let me post the series.
It will cover SO_BINDTODEVICE as well.
>
> Should the check be restricted to TCP?
>
> else if (!valbool && sk->sk_protocol == IPPROTO_TCP &&
> rcu_access_pointer(sk->sk_reuseport_cb))
> ret = -EBUSY;
>
>
> The closed section only exists for TCP, so TCP is the only protocol where
> clearing the flag leads to the double add. With the check as it is, a bound
> UDP socket also starts getting EBUSY from setsockopt(SO_REUSEPORT, 0).
>
> N.
>
> >> 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@doyensec.com>
> >> ---
> >> 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
> >>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice
2026-09-28 17:22 [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice Norbert Szetei
2026-09-28 17:45 ` Kuniyuki Iwashima
@ 2026-09-30 17:24 ` netdev-bot+sashiko
1 sibling, 0 replies; 5+ messages in thread
From: netdev-bot+sashiko @ 2026-09-30 17:24 UTC (permalink / raw)
To: norbert
Cc: netdev, edumazet, kuniyu, pabeni, willemb, davem, kuba, horms,
martin.lau, daniel, linux-kernel
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 1 (1) · Medium: 0 · Low: 0 (1)
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The patch stops the duplicate socks[] entry but leaves the root
cause that its own commit message names.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but it is still
reachable from the state the patch leaves in place.
- [Low] This problem wasn't introduced by this patch, but a listener that
is hashed yet sits in the closed section (the state described above)…
--
soreuseport: Fix use-after-free when a socket is added to socks[] twice
This patch makes reuseport_stop_listen_sock() move a socket to the closed
section of reuse->socks[] only when __reuseport_detach_sock() actually
removed it from the listening section. This stops a second copy of the
socket from being added to socks[], which led to a use-after-free in
reuseport_grow().
> 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);
[Severity: High]
This removes the duplicate socks[] entry. Does it still leave in place the
membership mismatch that the commit message names as the root cause?
inet_hash() only enters the reuseport path when sk->sk_reuseport is set:
net/ipv4/inet_hashtables.c:inet_hash() {
...
if (sk->sk_reuseport) {
err = inet_reuseport_add_sock(sk, ilb2);
...
}
inet_unhash() instead checks sk_reuseport_cb:
if (rcu_access_pointer(sk->sk_reuseport_cb))
reuseport_stop_listen_sock(sk);
Take this sequence: listen() with tcp_migrate_req or a MIGRATE prog,
shutdown(), setsockopt(SO_REUSEPORT, 0), then listen() again. The socket
is now a hashed TCP_LISTEN socket, but it is still in the closed section
of the old group G, and sk_reuseport_cb still points at G.
With this patch, the next reuseport_stop_listen_sock() on that socket does
nothing. The socket is never detached or resurrected, so this state lasts
until sk_destruct().
If the socket was autobound, __inet_put_port() released its port on the
first shutdown(). The second listen() can then pick a different port P2,
while G's live members stay on P1.
Could that lead to the following?
- After SO_REUSEPORT is set again, inet_lookup_reuseport() ->
reuseport_select_sock() uses the stale G. SYNs sent to P2 are then
handed to a listener on P1.
- A new SO_REUSEPORT listener on P2 matches this socket as sk2 in
reuseport_add_sock() and joins G through the stale cb. One group then
spans two ports.
- On a later shutdown(), inet_csk_listen_stop() ->
reuseport_migrate_sock() moves this socket's children to G's
listeners on P1.
The comment in reuseport_grow() ("Only reqsk left at this point.") also
assumes that sockets in the closed section are not live listeners. This
state also keeps the NULL dereference described below reachable.
Would a fix at the source work better? For example, inet_hash() could
detach a stale sk_reuseport_cb when !sk->sk_reuseport, or the cb could be
detached when SO_REUSEPORT is cleared. That would make the new conditional
here unnecessary.
The commit message doesn't mention that this state remains after the fix.
[Severity: High]
This is a pre-existing issue, but the hashed-but-closed state above seems
to make a NULL dereference reachable earlier in the same function:
net/core/sock_reuseport.c:reuseport_stop_listen_sock() {
...
reuse = rcu_dereference_protected(sk->sk_reuseport_cb,
lockdep_is_held(&reuseport_lock));
prog = rcu_dereference_protected(reuse->prog,
lockdep_is_held(&reuseport_lock));
...
}
inet_unhash() checked sk_reuseport_cb earlier, but it held only the
socket's own ilb2->lock at that point.
reuseport_grow() can clear a closed-section socket's cb under
reuseport_lock when the group cannot grow any further:
sk = reuse->socks[reuse->max_socks - reuse->num_closed_socks];
RCU_INIT_POINTER(sk->sk_reuseport_cb, NULL);
__reuseport_detach_closed_sock(sk, reuse);
reuseport_detach_sock() and reuseport_update_incoming_cpu() already guard
against this case:
/* reuseport_grow() has detached a closed sk */
if (!reuse)
goto out;
Normally a socket in the closed section is unhashed, so inet_unhash()
returns early. Here, though, the re-listened socket S is on P2 and G's
members are on P1, so they sit in different lhash2 buckets. Is this
interleaving possible?
CPU0 CPU1
shutdown(S) listen(T) on P1
inet_unhash(S) under B2->lock inet_hash(T) under B1->lock
sees S->sk_reuseport_cb == G reuseport_add_sock()
reuseport_stop_listen_sock(S) spin_lock_bh(&reuseport_lock)
spin_lock_bh(&reuseport_lock) reuseport_grow()
(waits) (max_socks * 2 > U16_MAX)
S->sk_reuseport_cb = NULL
spin_unlock_bh(&reuseport_lock)
reuse = NULL
reuse->prog <- NULL dereference
If it is, the oops happens with reuseport_lock held and BH disabled, and
any later reuseport operation would then spin on that lock.
Triggering it needs about 32K same-uid sockets in G and migration enabled.
tcp_migrate_req is per-netns and can be set from an unprivileged user
namespace.
Should reuseport_stop_listen_sock() have the same !reuse check as its
sibling functions?
>
> spin_unlock_bh(&reuseport_lock);
> return;
[Severity: Low]
This isn't a bug introduced by this patch, but the same socket (hashed as
a listener while still in G's closed section) also gets past the guards
in reuseport_attach_prog() and reuseport_detach_prog().
For a hashed socket, reuseport_attach_prog() only checks that the cb is
non-NULL before it overwrites reuse->prog:
} else if (!rcu_access_pointer(sk->sk_reuseport_cb)) {
/* The socket wasn't bound with SO_REUSEPORT */
return -EINVAL;
}
reuseport_detach_prog() only refuses unhashed sockets:
if (sk_unhashed(sk) && reuse->num_closed_socks) {
So a socket that G treats as shutdown()ed can replace or clear the
steering prog for all of G's live listeners, through
SO_ATTACH_REUSEPORT_CBPF or SO_DETACH_REUSEPORT_BPF.
The comment in reuseport_resurrect() says this should not happen:
* ... In setsockopt() path, we should
* not change the eBPF prog of listening sockets by attaching a
* prog to the shutdown()ed socket.
All members of G share sk_uid, so no privilege boundary is crossed. Is
this behavior intended, though?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/6E4F8645-9453-45F1-B068-52E1B14E8B0C%40doyensec.com
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-30 17:24 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-28 17:22 [PATCH net] soreuseport: Fix use-after-free when a socket is added to socks[] twice Norbert Szetei
2026-09-28 17:45 ` Kuniyuki Iwashima
2026-09-29 15:30 ` Norbert Szetei
2026-09-29 18:31 ` Kuniyuki Iwashima
2026-09-30 17:24 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®