summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2020-04-18 15:43:20 -0700
committerDavid S. Miller <davem@davemloft.net>2020-04-18 15:43:20 -0700
commit56e639e6a241de67488597fe2e07150f24ebc9de (patch)
tree40df7b66c503ce9569e475c97a602303a343f14e
parent310660a14b74c380b0ef5c12b66933d6a3d1b59f (diff)
parent9f5ca6a59816b406230adc440b6bb684fda90abe (diff)
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>
-rw-r--r--net/mptcp/protocol.c8
-rw-r--r--net/mptcp/subflow.c33
2 files changed, 37 insertions, 4 deletions
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 9936e33ac351..7e816c733ccb 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -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);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 50a8bea987c6..bc46b5091b9d 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -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 @@ create_child:
/* 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 @@ create_child:
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: