From 8e81c8126cbb012fb5cf2a0db87a1c3451daf246 Mon Sep 17 00:00:00 2001 From: Christoph Paasch Date: Fri, 8 Mar 2019 08:11:31 -0800 Subject: [PATCH] mptcp: Ensure proper free'ing of master_sk upon failure We might have inet_opt set from the meta, but inet_sock_destruct will try to free it. We need to set it to NULL to prevent a use-after-free. We need to make sure that the socket is in SOCK_DEAD, thus call sock_orphan() as inet_sock_destruct checks for SOCK_DEAD. Same for TCP_CLOSE. The lock has been taken in sk_clone_lock(). Drop it! Fixes: Zero-day bug Signed-off-by: Christoph Paasch Signed-off-by: Matthieu Baerts --- net/mptcp/mptcp_ctrl.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/net/mptcp/mptcp_ctrl.c b/net/mptcp/mptcp_ctrl.c index d7e5f3e4d89ce..598b7a04aac9f 100644 --- a/net/mptcp/mptcp_ctrl.c +++ b/net/mptcp/mptcp_ctrl.c @@ -1146,15 +1146,13 @@ static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key, master_sk = sk_clone_lock(meta_sk, GFP_ATOMIC | __GFP_ZERO); meta_tp->is_master_sk = 0; if (!master_sk) - return -ENOBUFS; + goto err_alloc_master; master_tp = tcp_sk(master_sk); mpcb = kmem_cache_zalloc(mptcp_cb_cache, GFP_ATOMIC); - if (!mpcb) { - sk_free(master_sk); - return -ENOBUFS; - } + if (!mpcb) + goto err_alloc_mpcb; /* Store the mptcp version agreed on initial handshake */ mpcb->mptcp_ver = mptcp_ver; @@ -1212,11 +1210,7 @@ static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key, spin_unlock(&mptcp_tk_hashlock); rcu_read_unlock_bh(); - inet_put_port(master_sk); - kmem_cache_free(mptcp_cb_cache, mpcb); - sk_free(master_sk); - - return -ENOBUFS; + goto err_insert_token; } __mptcp_hash_insert(meta_tp, mpcb->mptcp_loc_token); @@ -1360,6 +1354,19 @@ static int mptcp_alloc_mpcb(struct sock *meta_sk, __u64 remote_key, __func__, mpcb->mptcp_loc_token); return 0; + +err_insert_token: + kmem_cache_free(mptcp_cb_cache, mpcb); + +err_alloc_mpcb: + inet_sk(master_sk)->inet_opt = NULL; + master_sk->sk_state = TCP_CLOSE; + sock_orphan(master_sk); + bh_unlock_sock(master_sk); + sk_free(master_sk); + +err_alloc_master: + return -ENOBUFS; } /* Called without holding lock on mpcb */