Thread (1 message) 1 message, 1 author, 6d ago

Re: [PATCH] tcp: fastopen: check rsk_drop_req() in tcp_fastopen_create_child()

From: Yilin Zhang <hidden>
Date: 2026-09-03 07:07:19
Also in: mptcp

Here is a packetdrill reproducer for the MPTCP subflow/TFO issue.

It first obtains a TFO cookie and the server key during an MP_CAPABLE
handshake, then sends an MP_JOIN SYN from a new source port with the
corresponding token and cookie. The final ACK is intentionally omitted.

With the fix, the request remains in the SYN queue: the MPTCP reset is
followed by a normal SYN/ACK that echoes the cookie, and the second
accept() returns EAGAIN. Without the fix, tcp_fastopen_create_child()
ignores drop_req=true after subflow_syn_recv_sock() destroys the cloned
child. The TFO path queues that child instead; the SYN/ACK omits the
cookie, and closing the listener reports a refcount/use-after-free
warning.

-- >8 -- gtests/net/mptcp/fastopen/server-tfo-mpjoin-syn_v4.pkt -- >8 --

// Regression test: an MP_JOIN SYN with a valid TFO cookie must not queue
// a destroyed child.
--tolerance_usecs=100000
`../common/defaults.sh`

// MPTCP listener with server-side Fast Open enabled.
+0.0  socket(..., SOCK_STREAM, IPPROTO_MPTCP) = 3
+0.0  setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0.0  setsockopt(3, SOL_TCP, TCP_FASTOPEN, [2], 4) = 0
+0.0  fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
+0.0  fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0.0  bind(3, ..., ...) = 0
+0.0  listen(3, 1) = 0

// Obtain a TFO cookie and learn the server key.
+0.1  <  S   0:0(0)         win 65535  <mss 1460, sackOK, TS val 100 ecr 0,   nop, wscale 8, FO,            nop, nop, mpcapable v1 flags[flag_h] nokey>
+0.0  >  S.  0:0(0)  ack 1             <mss 1460, nop, nop, sackOK,           nop, wscale 8, FO TFO_COOKIE, nop, nop, mpcapable v1 flags[flag_h] key[skey]>
+0.2  <  .   1:1(0)  ack 1     win 450  <                                                                              mpcapable v1 flags[flag_h] key[ckey=2, skey]>
+0.0  accept(3, ..., ...) = 4

// Use a new source port with the same address; the cookie remains valid.
+0.1  <  192.0.2.1:15000 > 192.168.0.1:8080  S  0:0(0)  win 65535  <mss 1460, sackOK, nop, wscale 8, FO TFO_COOKIE, nop, nop, mp_join_syn address_id=1 token=sha256_32(skey), nop, nop>
// The fatal MPTCP fallback destroys the cloned child and resets the flow.
+0.0  >  192.168.0.1:8080 > 192.0.2.1:15000  R.  0:0(0)  ack 1  <mp_reset 1>
// Normal SYN processing sends a SYN/ACK and echoes the TFO cookie.
+0.0  >  192.168.0.1:8080 > 192.0.2.1:15000  S.  0:0(0)  ack 1  <mss 1460, nop, nop, sackOK, nop, wscale 8, FO TFO_COOKIE, nop, nop, mp_join_syn_ack address_id=0 sender_hmac=auto>

// Without the final ACK, the request must remain in the SYN queue.
+0.2  accept(3, ..., ...) = -1 EAGAIN (Resource temporarily unavailable)

-- >8 --

For the MPTCP packetdrill fork, save this as
`gtests/net/mptcp/fastopen/server-tfo-mpjoin-syn_v4.pkt` and run it with
that fork's packetdrill binary.

Tested on Linux 7.3.0-rc1 (defconfig + MPTCP + KASAN, QEMU guest): the
unpatched kernel sends a SYN/ACK without the TFO cookie and reports
`refcount_t: underflow; use-after-free` when the listener closes; the
fixed kernel passes, with the second `accept()` returning EAGAIN.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help