From: Hyunwoo Kim <imv4bel@gmail.com>
To: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, ncardwell@google.com, dsahern@kernel.org,
idosch@nvidia.com, kuniyu@google.com, horms@kernel.org,
willemb@google.com, andrew+netdev@lunn.ch, kees@kernel.org,
jiayuan.chen@linux.dev
Cc: kerneljasonxing@gmail.com, ij@kernel.org, martin.lau@kernel.org,
shakeel.butt@linux.dev, matttbe@kernel.org, martineau@kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
imv4bel@gmail.com, stable@vger.kernel.org
Subject: [PATCH net v2 8/8] tcp: do not inherit retransmit state from parent
Date: Mon, 24 Aug 2026 12:32:52 +0900 [thread overview]
Message-ID: <20260824033331.1084971-9-imv4bel@gmail.com> (raw)
In-Reply-To: <20260824033331.1084971-1-imv4bel@gmail.com>
A child gets a copy of the parent's retransmit state when it is cloned.
On a listener it is all zero, which is why commit eb2c80ca87b1 ("tcp: do
not clear packets_out in tcp_create_openreq_child()") and
commit 5c701549c9a6 ("tcp: move retrans_out, sacked_out, tlp_high_seq,
last_oow_ack_time init to tcp_disconnect()") dropped the initialization
of packets_out, retrans_out and sacked_out here. lost_out,
retransmit_skb_hint and highest_sack have never been cleared here.
The parent can morph from listener to active session while a request is
still being processed, and connect(AF_UNSPEC) followed by connect()
gets it there. tcp_check_req() does not hold the listener lock, so
nothing pins the parent's state between the TCP_LISTEN test and the
clone. The child then copies the counters and the two pointers into the
parent's retransmit queue.
sk_clone() sets sk_send_head to NULL, and tcp_rtx_queue is unioned with
it, so the child's retransmit queue is empty. That does not help.
packets_out is set again as soon as the child sends anything, and
tcp_xmit_retransmit_queue() picks the copied hint over the queue head.
When the parent disconnects, tcp_write_queue_purge() frees those skbs,
but the pointers the child copied are left alone. The child then gets
an ACK, enters the retransmit path and writes into a freed skb.
In short:
socket(AF_INET) -> setsockopt(TCP_DEFER_ACCEPT, 30) -> bind -> listen
// a client connects and sends one byte. the kernel processes
// that segment while the steps below run
connect(AF_UNSPEC) // stop listening
connect(peer) // become an active session
send() repeatedly // lower IP_TTL so the peer's IP_MINTTL
// drops most of them, and let one
// through to get a SACK
// parent: packets_out 6, sacked_out 1, lost_out 5, retrans_out 1
// retransmit_skb_hint points at an skb in the parent's queue
// the leftover request completes and copies this state
connect(AF_UNSPEC) // those skbs are freed
listen() // or the child is dropped
accept()
// the child sends data, one segment is lost, and the ACK that
// comes back takes the retransmit path to the copied hint
KASAN log:
BUG: KASAN: slab-use-after-free in __pskb_trim_head+0x66b/0x900
Write of size 16 at addr ffff888008141530 by task repro/76
...
Call Trace:
__pskb_trim_head+0x66b/0x900
tcp_trim_head+0x69/0x540
__tcp_retransmit_skb+0x14e/0x26b0
tcp_retransmit_skb+0x1b/0x250
tcp_xmit_retransmit_queue.part.0+0x3b1/0x970
tcp_ack+0x3382/0x7430
tcp_rcv_established+0x631/0x3a00
tcp_v4_do_rcv+0x449/0x960
__release_sock+0x1f2/0x2a0
release_sock+0x176/0x1d0
tcp_sendmsg+0x30/0x40
__sys_sendto+0x316/0x380
__x64_sys_sendto+0xdb/0x1b0
...
Allocated by task 76:
__alloc_skb+0x11e/0x890
tcp_stream_alloc_skb+0x2c/0x5c0
tcp_sendmsg_locked+0x1377/0x3df0
tcp_sendmsg+0x26/0x40
__sys_sendto+0x316/0x380
...
Freed by task 80:
skb_release_data+0x554/0x810
__kfree_skb+0x42/0x60
tcp_write_queue_purge+0x6ef/0xf40
tcp_disconnect+0x2fc/0x1e10
__inet_stream_connect+0x6d0/0xdf0
inet_stream_connect+0x52/0xa0
__sys_connect+0xfc/0x130
...
The buggy address belongs to the object at ffff888008141380
which belongs to the cache skbuff_small_head of size 704
We need to make sure this can not happen, by clearing them after socket
cloning. A listener always has them zero, so an ordinary passive open is
not affected. Clearing only the pointers is not enough: the counters
would then describe a retransmit queue the child does not have, and
tcp_fastretrans_alert() and tcp_retransmit_timer() warn.
Very similar to commit 8b485ce69876 ("tcp: do not inherit fastopen_req
from parent")
Fixes: 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
net/ipv4/tcp_minisocks.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 7fe318d9e0aed2..2fde196dd302f5 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -660,6 +660,12 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
tcp_ecn_openreq_child(newsk, req, skb);
newtp->fastopen_req = NULL;
RCU_INIT_POINTER(newtp->fastopen_rsk, NULL);
+ newtp->packets_out = 0;
+ newtp->retrans_out = 0;
+ newtp->sacked_out = 0;
+ newtp->lost_out = 0;
+ newtp->retransmit_skb_hint = NULL;
+ newtp->highest_sack = NULL;
newtp->bpf_chg_cc_inprogress = 0;
tcp_bpf_clone(sk, newsk);
--
2.43.0
next prev parent reply other threads:[~2026-08-24 3:34 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 3:32 [PATCH net v2 0/8] net: fixes for requests completing on a socket that no longer listens Hyunwoo Kim
2026-08-24 3:32 ` [PATCH net v2 1/8] tcp: fix use-after-free of the listener's ipv6_pinfo after IPV6_ADDRFORM Hyunwoo Kim
2026-08-24 3:32 ` [PATCH net v2 2/8] tcp: fix imbalanced icsk_accept_queue count in tcp_check_req() Hyunwoo Kim
2026-08-24 3:32 ` [PATCH net v2 3/8] ipv6: fix request socket use-after-free after IPV6_ADDRFORM Hyunwoo Kim
2026-08-24 3:32 ` [PATCH net v2 4/8] net: fix out-of-bounds write in sk_clone() racing with IPV6_ADDRFORM Hyunwoo Kim
2026-08-24 3:32 ` [PATCH net v2 5/8] tcp: do not inherit out_of_order_queue from parent Hyunwoo Kim
2026-08-24 3:32 ` [PATCH net v2 6/8] tcp: fix use-after-free in the lockless listener path Hyunwoo Kim
2026-08-24 3:32 ` [PATCH net v2 7/8] net: clear sk_tsq_flags in sk_clone() Hyunwoo Kim
2026-08-24 3:32 ` Hyunwoo Kim [this message]
2026-08-24 8:30 ` [PATCH net v2 0/8] net: fixes for requests completing on a socket that no longer listens David Laight
2026-08-24 12:56 ` Hyunwoo Kim
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260824033331.1084971-9-imv4bel@gmail.com \
--to=imv4bel@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=ij@kernel.org \
--cc=jiayuan.chen@linux.dev \
--cc=kees@kernel.org \
--cc=kerneljasonxing@gmail.com \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@kernel.org \
--cc=martineau@kernel.org \
--cc=matttbe@kernel.org \
--cc=ncardwell@google.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=shakeel.butt@linux.dev \
--cc=stable@vger.kernel.org \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox