Skip to content

Commit

Permalink
Squash-to: mptcp: use the workqueue to destroy unaccepted sockets
Browse files Browse the repository at this point in the history
The workqueue could trigger before inet_csk_listen_stop() kicks-in,
or the closed socket could even land to accept(). Solve the race
falling back to TCP - we already complete the MPTCP level close
signaling.

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Link: https://lore.kernel.org/r/ee3e0181ffd7e4d81ed43d27f18401da3d5927d6.1677600530.git.pabeni@redhat.com
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
  • Loading branch information
Paolo Abeni authored and matttbe committed Feb 28, 2023
1 parent 84962aa commit 430272c
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 4 deletions.
14 changes: 13 additions & 1 deletion net/mptcp/protocol.c
Expand Up @@ -2342,15 +2342,27 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
goto out;
}

sock_orphan(ssk);
subflow->disposable = 1;

/* if ssk hit tcp_done(), tcp_cleanup_ulp() cleared the related ops
* the ssk has been already destroyed, we just need to release the
* reference owned by msk;
*/
if (!inet_csk(ssk)->icsk_ulp_ops) {
WARN_ON_ONCE(!sock_flag(sk, SOCK_DEAD));
kfree_rcu(subflow, rcu);
} else if (msk->in_accept_queue && msk->first == ssk) {
/* if the first subflow moved to a close state, e.g. due to
* incoming reset and we reach here before inet_child_forget()
* the TCP stack could later try to close it via
* inet_csk_listen_stop(), or deliver it to the user space via
* accept().
* We can't delete the subflow - or risk a double free - nor let
* the msk survive - or will be leaked in the non accept scenario:
* fallback and let TCP cope with the subflow cleanup.
*/
WARN_ON_ONCE(sock_flag(sk, SOCK_DEAD));
mptcp_subflow_drop_ctx(ssk);
} else {
/* otherwise tcp will dispose of the ssk and subflow ctx */
if (ssk->sk_state == TCP_LISTEN) {
Expand Down
2 changes: 2 additions & 0 deletions net/mptcp/protocol.h
Expand Up @@ -667,6 +667,8 @@ void mptcp_subflow_set_active(struct mptcp_subflow_context *subflow);

bool mptcp_subflow_active(struct mptcp_subflow_context *subflow);

void mptcp_subflow_drop_ctx(struct sock *ssk);

static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
struct mptcp_subflow_context *ctx)
{
Expand Down
6 changes: 3 additions & 3 deletions net/mptcp/subflow.c
Expand Up @@ -718,7 +718,7 @@ static void subflow_ulp_fallback(struct sock *sk,
mptcp_subflow_ops_undo_override(sk);
}

static void subflow_drop_ctx(struct sock *ssk)
void mptcp_subflow_drop_ctx(struct sock *ssk)
{
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(ssk);

Expand Down Expand Up @@ -824,7 +824,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,

if (new_msk)
mptcp_copy_inaddrs(new_msk, child);
subflow_drop_ctx(child);
mptcp_subflow_drop_ctx(child);
goto out;
}

Expand Down Expand Up @@ -915,7 +915,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
return child;

dispose_child:
subflow_drop_ctx(child);
mptcp_subflow_drop_ctx(child);
tcp_rsk(req)->drop_req = true;
inet_csk_prepare_for_destroy_sock(child);
tcp_done(child);
Expand Down

0 comments on commit 430272c

Please sign in to comment.