subflow_syn_recv_sock() sets drop_req when an MP_JOIN SYN takes the fatal fallback and destroys the cloned child. tcp_fastopen_create_child() ignored the flag and could queue the destroyed child. With an MPTCP listener using server-side Fast Open, a valid-cookie MP_JOIN SYN could then expose the freed child through accept(). Release the locked child and drop the request before tcp_conn_request() sends a SYN-ACK. Initialize drop_req when allocating the request so the check cannot observe stale state after request-socket reuse. Changes in v2: - unlock the child before dropping its reference - drop the request instead of sending a SYN-ACK after the MPTCP reset, as suggested by Jiayuan Chen Fixes: 90bf45134d55 ("mptcp: add new sock flag to deal with join subflows") Reported-by: Kimi Security Team Suggested-by: Jiayuan Chen Signed-off-by: Yilin Zhang --- net/ipv4/tcp_fastopen.c | 6 ++++++ net/ipv4/tcp_input.c | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 471c78be5513..22494ff746c7 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -337,6 +337,12 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk, if (!child) return NULL; + if (own_req && rsk_drop_req(req)) { + bh_unlock_sock(child); + sock_put(child); + return NULL; + } + spin_lock(&queue->fastopenq.lock); queue->fastopenq.qlen++; spin_unlock(&queue->fastopenq.lock); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0f60a1dbf927..eb0e4259c280 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -7669,8 +7669,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, tcp_rsk(req)->txhash = net_tx_rndhash(); #if IS_ENABLED(CONFIG_MPTCP) tcp_rsk(req)->is_mptcp = 0; + tcp_rsk(req)->drop_req = false; #endif tcp_clear_options(&tmp_opt); tmp_opt.mss_clamp = af_ops->mss_clamp; tmp_opt.user_mss = READ_ONCE(tp->rx_opt.user_mss); @@ -7775,6 +7776,10 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, READ_ONCE(sk->sk_data_ready)(sk); bh_unlock_sock(fastopen_sk); sock_put(fastopen_sk); + } else if (rsk_drop_req(req)) { + reqsk_free(req); + dst_release(dst); + return 0; } else { tcp_rsk(req)->tfo_listener = false; if (!want_cookie && -- 2.43.0