Netdev List
 help / color / mirror / Atom feed
* [PATCH net] ipv4: free inet_opt after an RCU grace period
@ 2026-09-29 21:43 Eric Dumazet
  2026-09-29 21:49 ` netdev-bot+sinfo
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-09-29 21:43 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Neal Cardwell, Kuniyuki Iwashima, David Ahern,
	Ido Schimmel, edumazet, netdev, Eric Dumazet, Xinyang Ge

tcp_v4_syn_recv_sock() transfers ownership of ireq->ireq_opt to the
child socket (newinet->inet_opt) without copying it.

Another cpu can concurrently retransmit a SYNACK for the same request
socket (either from a retransmitted SYN, or from the SYNACK timer).
tcp_v4_send_synack() and inet_csk_route_req() read ireq->ireq_opt
under rcu_read_lock() only, and ip_build_and_send_pkt() and
ip_options_build() then read opt->optlen twice.

Since commit 079096f103fa ("tcp/dccp: install syn_recv requests
into ehash table"), request sockets are processed without holding
the listener lock, so nothing prevents the child socket from being
freed while the SYNACK is still being built. TCP child sockets do
not have SOCK_RCU_FREE, and inet_sock_destruct() frees inet_opt
with a plain kfree(), leading to a use-after-free in
ip_options_build().

Readers of inet_opt already use RCU, and other paths replacing
inet_opt (do_ip_setsockopt(), cipso_v4_sock_setattr()...) already use
kfree_rcu(). Use kfree_rcu() in inet_sock_destruct() as well.

IPv6 is not affected, tcp_v6_syn_recv_sock() duplicates the options.

Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table")
Reported-by: Xinyang Ge <xinyang@anthropic.com>
Signed-off-by: Eric Dumazet <edumazet@kernel.org>
---
 net/ipv4/af_inet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 4ce38c99fef9ef2a24edff34cd5b110dddfec193..14ce01092fda65dbcf835662c03d78f4de0301f2 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -161,7 +161,7 @@ void inet_sock_destruct(struct sock *sk)
 	WARN_ON_ONCE(sk->sk_wmem_queued);
 	WARN_ON_ONCE(sk->sk_forward_alloc);
 
-	kfree(rcu_dereference_protected(inet->inet_opt, 1));
+	kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu);
 	dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
 	dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1));
 	psp_sk_assoc_free(sk);
-- 
2.56.0.rc1.315.gc6ed9934b7-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH net] ipv4: free inet_opt after an RCU grace period
  2026-09-29 21:43 [PATCH net] ipv4: free inet_opt after an RCU grace period Eric Dumazet
@ 2026-09-29 21:49 ` netdev-bot+sinfo
  2026-09-30  1:49 ` Jiayuan Chen
  2026-10-01 21:45 ` netdev-bot+sashiko
  2 siblings, 0 replies; 6+ messages in thread
From: netdev-bot+sinfo @ 2026-09-29 21:49 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Neal Cardwell, Kuniyuki Iwashima, David Ahern, Ido Schimmel,
	edumazet, netdev, Xinyang Ge

Hi!

This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:

 - How the issue was discovered, e.g. hit in production, hit during
   development, syzbot report, manual code inspection, LLM or static
   analysis tool scan.

 - Whether the issue was actually triggered, or is only theoretical
   (e.g. found by code inspection). If it was triggered please include
   the symptoms, like the stack trace or error messages.

Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.

The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net] ipv4: free inet_opt after an RCU grace period
  2026-09-29 21:43 [PATCH net] ipv4: free inet_opt after an RCU grace period Eric Dumazet
  2026-09-29 21:49 ` netdev-bot+sinfo
@ 2026-09-30  1:49 ` Jiayuan Chen
  2026-09-30  6:42   ` Eric Dumazet
  2026-10-01 21:45 ` netdev-bot+sashiko
  2 siblings, 1 reply; 6+ messages in thread
From: Jiayuan Chen @ 2026-09-30  1:49 UTC (permalink / raw)
  To: Eric Dumazet, David S . Miller, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Neal Cardwell, Kuniyuki Iwashima, David Ahern,
	Ido Schimmel, edumazet, netdev, Xinyang Ge


On 9/30/26 5:43 AM, Eric Dumazet wrote:
> tcp_v4_syn_recv_sock() transfers ownership of ireq->ireq_opt to the
> child socket (newinet->inet_opt) without copying it.
>
> Another cpu can concurrently retransmit a SYNACK for the same request
> socket (either from a retransmitted SYN, or from the SYNACK timer).
> tcp_v4_send_synack() and inet_csk_route_req() read ireq->ireq_opt
> under rcu_read_lock() only, and ip_build_and_send_pkt() and
> ip_options_build() then read opt->optlen twice.
>
> Since commit 079096f103fa ("tcp/dccp: install syn_recv requests
> into ehash table"), request sockets are processed without holding
> the listener lock, so nothing prevents the child socket from being
> freed while the SYNACK is still being built. TCP child sockets do
> not have SOCK_RCU_FREE, and inet_sock_destruct() frees inet_opt
> with a plain kfree(), leading to a use-after-free in
> ip_options_build().
>
> Readers of inet_opt already use RCU, and other paths replacing
> inet_opt (do_ip_setsockopt(), cipso_v4_sock_setattr()...) already use
> kfree_rcu(). Use kfree_rcu() in inet_sock_destruct() as well.
>
> IPv6 is not affected, tcp_v6_syn_recv_sock() duplicates the options.
>
> Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table")
> Reported-by: Xinyang Ge <xinyang@anthropic.com>
> Signed-off-by: Eric Dumazet <edumazet@kernel.org>



For the SYNACK timer case, inet_csk_complete_hashdance() calls
timer_delete_sync() before the child can be freed, so I don't see how
that one can race. The retransmitted SYN path is the real one I think.

Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>

> ---
>   net/ipv4/af_inet.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
> index 4ce38c99fef9ef2a24edff34cd5b110dddfec193..14ce01092fda65dbcf835662c03d78f4de0301f2 100644
> --- a/net/ipv4/af_inet.c
> +++ b/net/ipv4/af_inet.c
> @@ -161,7 +161,7 @@ void inet_sock_destruct(struct sock *sk)
>   	WARN_ON_ONCE(sk->sk_wmem_queued);
>   	WARN_ON_ONCE(sk->sk_forward_alloc);
>   
> -	kfree(rcu_dereference_protected(inet->inet_opt, 1));
> +	kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu);
>   	dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
>   	dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1));
>   	psp_sk_assoc_free(sk);

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net] ipv4: free inet_opt after an RCU grace period
  2026-09-30  1:49 ` Jiayuan Chen
@ 2026-09-30  6:42   ` Eric Dumazet
  0 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-09-30  6:42 UTC (permalink / raw)
  To: Jiayuan Chen
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Neal Cardwell, Kuniyuki Iwashima, David Ahern, Ido Schimmel,
	edumazet, netdev, Xinyang Ge

On Wed, Sep 30, 2026 at 3:50 AM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
>
> On 9/30/26 5:43 AM, Eric Dumazet wrote:
> > tcp_v4_syn_recv_sock() transfers ownership of ireq->ireq_opt to the
> > child socket (newinet->inet_opt) without copying it.
> >
> > Another cpu can concurrently retransmit a SYNACK for the same request
> > socket (either from a retransmitted SYN, or from the SYNACK timer).
> > tcp_v4_send_synack() and inet_csk_route_req() read ireq->ireq_opt
> > under rcu_read_lock() only, and ip_build_and_send_pkt() and
> > ip_options_build() then read opt->optlen twice.
> >
> > Since commit 079096f103fa ("tcp/dccp: install syn_recv requests
> > into ehash table"), request sockets are processed without holding
> > the listener lock, so nothing prevents the child socket from being
> > freed while the SYNACK is still being built. TCP child sockets do
> > not have SOCK_RCU_FREE, and inet_sock_destruct() frees inet_opt
> > with a plain kfree(), leading to a use-after-free in
> > ip_options_build().
> >
> > Readers of inet_opt already use RCU, and other paths replacing
> > inet_opt (do_ip_setsockopt(), cipso_v4_sock_setattr()...) already use
> > kfree_rcu(). Use kfree_rcu() in inet_sock_destruct() as well.
> >
> > IPv6 is not affected, tcp_v6_syn_recv_sock() duplicates the options.
> >
> > Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table")
> > Reported-by: Xinyang Ge <xinyang@anthropic.com>
> > Signed-off-by: Eric Dumazet <edumazet@kernel.org>
>
>
>
> For the SYNACK timer case, inet_csk_complete_hashdance() calls
> timer_delete_sync() before the child can be freed, so I don't see how
> that one can race. The retransmitted SYN path is the real one I think.
>
> Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>

Agreed, if a V2 is needed, I can amend the changelog.

    Another cpu can concurrently process a retransmitted SYN for the same
    request socket, and send a SYNACK from tcp_check_req().
    tcp_v4_send_synack() and inet_csk_route_req() read ireq->ireq_opt
    under rcu_read_lock() only, and ip_build_and_send_pkt() and
    ip_options_build() then read opt->optlen twice.

    Note that the SYNACK timer is not an issue, because
    inet_csk_reqsk_queue_drop() calls timer_delete_sync() before the
    child can be freed.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net] ipv4: free inet_opt after an RCU grace period
  2026-09-29 21:43 [PATCH net] ipv4: free inet_opt after an RCU grace period Eric Dumazet
  2026-09-29 21:49 ` netdev-bot+sinfo
  2026-09-30  1:49 ` Jiayuan Chen
@ 2026-10-01 21:45 ` netdev-bot+sashiko
  2026-10-01 21:59   ` Eric Dumazet
  2 siblings, 1 reply; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-10-01 21:45 UTC (permalink / raw)
  To: edumazet
  Cc: davem, kuba, pabeni, horms, ncardwell, kuniyu, dsahern, idosch,
	edumazet, netdev, xinyang

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.

Critical: 0 · High: 1 · Medium: 0 · Low: 0

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 fix is incomplete.

--

ipv4: free inet_opt after an RCU grace period

This commit changes inet_sock_destruct() to free inet->inet_opt with
kfree_rcu() instead of kfree(). tcp_v4_syn_recv_sock() hands
ireq->ireq_opt to the child socket without copying it. A SYNACK
retransmit running at the same time can still be reading it under
rcu_read_lock() only.

> diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
> index 4ce38c99fef9e..14ce01092fda6 100644
> --- a/net/ipv4/af_inet.c
> +++ b/net/ipv4/af_inet.c
> @@ -161,7 +161,7 @@ void inet_sock_destruct(struct sock *sk)
>  	WARN_ON_ONCE(sk->sk_wmem_queued);
>  	WARN_ON_ONCE(sk->sk_forward_alloc);
>  
> -	kfree(rcu_dereference_protected(inet->inet_opt, 1));
> +	kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu);

[Severity: High]
Is there a second handoff of ireq_opt that still ends in a plain kfree()?

With net.ipv4.tcp_migrate_req=1 and SO_REUSEPORT listeners,
reqsk_timer_handler() migrates a request socket whose listener has been
closed:

net/ipv4/inet_connection_sock.c:reqsk_timer_handler() {
    ...
		nreq = inet_reqsk_clone(req, nsk);
    ...
		if (!inet_ehash_insert(req_to_sk(nreq), req_to_sk(oreq), NULL)) {
    ...
		reqsk_migrate_reset(oreq);
    ...
}

inet_reqsk_clone() memcpy()s the request socket, so nreq->ireq_opt points
to the same ip_options_rcu as oreq. reqsk_migrate_reset() then clears
oreq's slot with a plain NULL store, and nreq becomes the owner.

At the same time, another CPU can hold a reference on oreq in
tcp_v4_rcv(), pick a new listener through reuseport_migrate_sock(), and
handle a retransmitted SYN:

tcp_v4_rcv()
  tcp_check_req()
    tcp_rtx_synack()
      tcp_v4_send_synack()
        rcu_dereference(ireq->ireq_opt)
        ip_build_and_send_pkt()
          ip_options_build()

nreq can then be dropped, for example by an RST through
tcp_check_req()->inet_csk_reqsk_queue_drop()->reqsk_put(), or when its
own timer expires. When that happens, the options are freed without a
grace period:

net/ipv4/tcp_ipv4.c:tcp_v4_reqsk_destructor() {
	kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1));
}

The reference on oreq no longer protects the options, because oreq does
not own them anymore. The reader's rcu_read_lock() gives no protection
against a plain kfree() either.

Can this lead to the same use-after-free in ip_build_and_send_pkt() and
ip_options_build()? Both read opt->optlen, so if the memory is reallocated
in between, the two reads could disagree. That could turn into an
out-of-bounds write while the SYNACK is being built.

The commit message says the other paths that replace inet_opt already
use kfree_rcu(). Should tcp_v4_reqsk_destructor() also be converted to
kfree_rcu(..., rcu) as part of this fix?

>  	dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
>  	dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1));
>  	psp_sk_assoc_free(sk);

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260929214351.856940-1-edumazet%40kernel.org

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net] ipv4: free inet_opt after an RCU grace period
  2026-10-01 21:45 ` netdev-bot+sashiko
@ 2026-10-01 21:59   ` Eric Dumazet
  0 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-10-01 21:59 UTC (permalink / raw)
  To: netdev-bot+sashiko
  Cc: davem, kuba, pabeni, horms, ncardwell, kuniyu, dsahern, idosch,
	edumazet, netdev, xinyang

On Thu, Oct 1, 2026 at 11:45 PM <netdev-bot+sashiko@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue(s) to consider.
>
> Critical: 0 · High: 1 · Medium: 0 · Low: 0
>
> 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 fix is incomplete.

Good catch, tcp_v4_reqsk_destructor() needs the same treatment
after a request migration. I will send a v2.

Not sure about the 'High' classification, as the race would involve 3 cpus.

pw-bot: cr

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-10-01 22:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-29 21:43 [PATCH net] ipv4: free inet_opt after an RCU grace period Eric Dumazet
2026-09-29 21:49 ` netdev-bot+sinfo
2026-09-30  1:49 ` Jiayuan Chen
2026-09-30  6:42   ` Eric Dumazet
2026-10-01 21:45 ` netdev-bot+sashiko
2026-10-01 21:59   ` Eric Dumazet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox