From: Ruide Cao TCP request migration clones pending request sockets with inet_reqsk_clone(). For MPTCP MP_JOIN requests this raw-copies subflow_req->msk, but the cloned request does not take a new reference. Both the original and the cloned request can later drop the same msk in subflow_req_destructor(), and a migrated request may keep a dangling msk pointer after the original owner has already been released. Add a request_sock clone callback and let MPTCP grab a reference for cloned subflow requests that carry an msk. This keeps ownership balanced across both successful migrations and failed clone/insert paths without changing other protocols. Fixes: c905dee62232 ("tcp: Migrate TCP_NEW_SYN_RECV requests at retransmitting SYN+ACKs.") Cc: stable@kernel.org Reported-by: Yuan Tan Reported-by: Yifan Wu Reported-by: Juefei Pu Reported-by: Xin Liu Signed-off-by: Ruide Cao Tested-by: Ren Wei Signed-off-by: Ren Wei --- include/net/request_sock.h | 2 ++ net/ipv4/inet_connection_sock.c | 3 +++ net/mptcp/subflow.c | 13 +++++++++++++ 3 files changed, 18 insertions(+) diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 5a9c826a7092..560e464c400f 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -36,6 +36,8 @@ struct request_sock_ops { struct sk_buff *skb, enum sk_rst_reason reason); void (*destructor)(struct request_sock *req); + void (*init_clone)(const struct request_sock *req, + struct request_sock *new_req); }; struct saved_syn { diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index e961936b6be7..140a9e96ad58 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -954,6 +954,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req, if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener) rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq); + if (req->rsk_ops->init_clone) + req->rsk_ops->init_clone(req, nreq); + return nreq; } diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 4ff5863aa9fd..5f4069647822 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -47,6 +47,17 @@ static void subflow_req_destructor(struct request_sock *req) mptcp_token_destroy_request(req); } +static void subflow_req_clone(const struct request_sock *req, + struct request_sock *new_req) +{ + struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(new_req); + + (void)req; + + if (subflow_req->msk) + sock_hold((struct sock *)subflow_req->msk); +} + static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2, void *hmac) { @@ -2143,6 +2154,7 @@ void __init mptcp_subflow_init(void) mptcp_subflow_v4_request_sock_ops = tcp_request_sock_ops; mptcp_subflow_v4_request_sock_ops.slab_name = "request_sock_subflow_v4"; mptcp_subflow_v4_request_sock_ops.destructor = subflow_v4_req_destructor; + mptcp_subflow_v4_request_sock_ops.init_clone = subflow_req_clone; if (subflow_ops_init(&mptcp_subflow_v4_request_sock_ops) != 0) panic("MPTCP: failed to init subflow v4 request sock ops\n"); @@ -2184,6 +2196,7 @@ void __init mptcp_subflow_v6_init(void) mptcp_subflow_v6_request_sock_ops = tcp6_request_sock_ops; mptcp_subflow_v6_request_sock_ops.slab_name = "request_sock_subflow_v6"; mptcp_subflow_v6_request_sock_ops.destructor = subflow_v6_req_destructor; + mptcp_subflow_v6_request_sock_ops.init_clone = subflow_req_clone; if (subflow_ops_init(&mptcp_subflow_v6_request_sock_ops) != 0) panic("MPTCP: failed to init subflow v6 request sock ops\n"); -- 2.34.1