Merge branch 'mptcp-fixes'

Florian Westphal says:

====================
mptcp: fix 'attempt to release socket in state...' splats

These two patches fix error handling corner-cases where
inet_sock_destruct gets called for a mptcp_sk that is not in TCP_CLOSE
state.  This results in unwanted error printks from the network stack.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-04-18 15:43:20 -07:00
commit 56e639e6a2
2 changed files with 37 additions and 4 deletions

View File

@ -1355,12 +1355,15 @@ struct sock *mptcp_sk_clone(const struct sock *sk, struct request_sock *req)
msk->subflow = NULL;
if (unlikely(mptcp_token_new_accept(subflow_req->token, nsk))) {
nsk->sk_state = TCP_CLOSE;
bh_unlock_sock(nsk);
/* we can't call into mptcp_close() here - possible BH context
* free the sock directly
* free the sock directly.
* sk_clone_lock() sets nsk refcnt to two, hence call sk_free()
* too.
*/
nsk->sk_prot->destroy(nsk);
sk_common_release(nsk);
sk_free(nsk);
return NULL;
}
@ -1431,6 +1434,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
newsk = new_mptcp_sock;
mptcp_copy_inaddrs(newsk, ssk);
list_add(&subflow->node, &msk->conn_list);
inet_sk_state_store(newsk, TCP_ESTABLISHED);
bh_unlock_sock(new_mptcp_sock);

View File

@ -347,6 +347,35 @@ static bool subflow_hmac_valid(const struct request_sock *req,
return ret;
}
static void mptcp_sock_destruct(struct sock *sk)
{
/* if new mptcp socket isn't accepted, it is free'd
* from the tcp listener sockets request queue, linked
* from req->sk. The tcp socket is released.
* This calls the ULP release function which will
* also remove the mptcp socket, via
* sock_put(ctx->conn).
*
* Problem is that the mptcp socket will not be in
* SYN_RECV state and doesn't have SOCK_DEAD flag.
* Both result in warnings from inet_sock_destruct.
*/
if (sk->sk_state == TCP_SYN_RECV) {
sk->sk_state = TCP_CLOSE;
WARN_ON_ONCE(sk->sk_socket);
sock_orphan(sk);
}
inet_sock_destruct(sk);
}
static void mptcp_force_close(struct sock *sk)
{
inet_sk_state_store(sk, TCP_CLOSE);
sk_common_release(sk);
}
static struct sock *subflow_syn_recv_sock(const struct sock *sk,
struct sk_buff *skb,
struct request_sock *req,
@ -422,7 +451,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
/* new mpc subflow takes ownership of the newly
* created mptcp socket
*/
inet_sk_state_store(new_msk, TCP_ESTABLISHED);
new_msk->sk_destruct = mptcp_sock_destruct;
mptcp_pm_new_connection(mptcp_sk(new_msk), 1);
ctx->conn = new_msk;
new_msk = NULL;
@ -444,7 +473,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
out:
/* dispose of the left over mptcp master, if any */
if (unlikely(new_msk))
sock_put(new_msk);
mptcp_force_close(new_msk);
return child;
close_child: