Commit ea1300b9 authored by Florian Westphal's avatar Florian Westphal Committed by David S. Miller
Browse files

mptcp: don't return sockets in foreign netns



mptcp_token_get_sock() may return a mptcp socket that is in
a different net namespace than the socket that received the token value.

The mptcp syncookie code path had an explicit check for this,
this moves the test into mptcp_token_get_sock() function.

Eventually token.c should be converted to pernet storage, but
such change is not suitable for net tree.

Fixes: 2c5ebd00 ("mptcp: refactor token container")
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f7e745f8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ static int mptcp_diag_dump_one(struct netlink_callback *cb,
	struct sock *sk;

	net = sock_net(in_skb->sk);
	msk = mptcp_token_get_sock(req->id.idiag_cookie[0]);
	msk = mptcp_token_get_sock(net, req->id.idiag_cookie[0]);
	if (!msk)
		goto out_nosk;

+1 −1
Original line number Diff line number Diff line
@@ -709,7 +709,7 @@ int mptcp_token_new_connect(struct sock *sk);
void mptcp_token_accept(struct mptcp_subflow_request_sock *r,
			struct mptcp_sock *msk);
bool mptcp_token_exists(u32 token);
struct mptcp_sock *mptcp_token_get_sock(u32 token);
struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token);
struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
					 long *s_num);
void mptcp_token_destroy(struct mptcp_sock *msk);
+1 −1
Original line number Diff line number Diff line
@@ -86,7 +86,7 @@ static struct mptcp_sock *subflow_token_join_request(struct request_sock *req)
	struct mptcp_sock *msk;
	int local_id;

	msk = mptcp_token_get_sock(subflow_req->token);
	msk = mptcp_token_get_sock(sock_net(req_to_sk(req)), subflow_req->token);
	if (!msk) {
		SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINNOTOKEN);
		return NULL;
+1 −12
Original line number Diff line number Diff line
@@ -108,18 +108,12 @@ bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subfl

	e->valid = 0;

	msk = mptcp_token_get_sock(e->token);
	msk = mptcp_token_get_sock(net, e->token);
	if (!msk) {
		spin_unlock_bh(&join_entry_locks[i]);
		return false;
	}

	/* If this fails, the token got re-used in the mean time by another
	 * mptcp socket in a different netns, i.e. entry is outdated.
	 */
	if (!net_eq(sock_net((struct sock *)msk), net))
		goto err_put;

	subflow_req->remote_nonce = e->remote_nonce;
	subflow_req->local_nonce = e->local_nonce;
	subflow_req->backup = e->backup;
@@ -128,11 +122,6 @@ bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subfl
	subflow_req->msk = msk;
	spin_unlock_bh(&join_entry_locks[i]);
	return true;

err_put:
	spin_unlock_bh(&join_entry_locks[i]);
	sock_put((struct sock *)msk);
	return false;
}

void __init mptcp_join_cookie_init(void)
+8 −3
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ bool mptcp_token_exists(u32 token)

/**
 * mptcp_token_get_sock - retrieve mptcp connection sock using its token
 * @net: restrict to this namespace
 * @token: token of the mptcp connection to retrieve
 *
 * This function returns the mptcp connection structure with the given token.
@@ -238,7 +239,7 @@ bool mptcp_token_exists(u32 token)
 *
 * returns NULL if no connection with the given token value exists.
 */
struct mptcp_sock *mptcp_token_get_sock(u32 token)
struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token)
{
	struct hlist_nulls_node *pos;
	struct token_bucket *bucket;
@@ -251,11 +252,15 @@ struct mptcp_sock *mptcp_token_get_sock(u32 token)
again:
	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
		msk = mptcp_sk(sk);
		if (READ_ONCE(msk->token) != token)
		if (READ_ONCE(msk->token) != token ||
		    !net_eq(sock_net(sk), net))
			continue;

		if (!refcount_inc_not_zero(&sk->sk_refcnt))
			goto not_found;
		if (READ_ONCE(msk->token) != token) {

		if (READ_ONCE(msk->token) != token ||
		    !net_eq(sock_net(sk), net)) {
			sock_put(sk);
			goto again;
		}
Loading