diff mbox series

[06/15] mptcp: Add key generation and token tree

Message ID 20191213205106.2467313-7-matthieu.baerts@tessares.net
State Deferred, archived
Headers show
Series Multipath TCP part 2: Single subflow | expand

Commit Message

Matthieu Baerts Dec. 13, 2019, 8:50 p.m. UTC
From: Peter Krystad <peter.krystad@linux.intel.com>

Generate the local keys, IDSN, and token when creating a new socket.
Introduce the token tree to track all tokens in use using a radix tree
with the MPTCP token itself as the index.

Will be used to obtain the MPTCP parent socket to handle incoming joins.

Co-developed-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Co-developed-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Florian Westphal <fw@strlen.de>
Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
---
 net/mptcp/Makefile   |   2 +-
 net/mptcp/crypto.c   | 122 +++++++++++++++++++++++++++
 net/mptcp/protocol.c |  16 ++++
 net/mptcp/protocol.h |  32 +++++++
 net/mptcp/subflow.c  |  66 +++++++++++++--
 net/mptcp/token.c    | 195 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 425 insertions(+), 8 deletions(-)
 create mode 100644 net/mptcp/crypto.c
 create mode 100644 net/mptcp/token.c

Comments

Peter Krystad Dec. 14, 2019, 5:14 a.m. UTC | #1
On Fri, 2019-12-13 at 21:50 +0100, Matthieu Baerts wrote:
> From: Peter Krystad <peter.krystad@linux.intel.com>
> 
> Generate the local keys, IDSN, and token when creating a new socket.
> Introduce the token tree to track all tokens in use using a radix tree
> with the MPTCP token itself as the index.

Add here:

Override the rebuild_header callback in inet_connection_sock_af_ops for
creating the local key on a new outgoing connection.

Override the init_req callback of tcp_request_sock_ops for creating the local
key on a new incoming connection.
 
> Will be used to obtain the MPTCP parent socket to handle incoming joins.
> 
> Co-developed-by: Davide Caratti <dcaratti@redhat.com>
> Signed-off-by: Davide Caratti <dcaratti@redhat.com>
> Co-developed-by: Florian Westphal <fw@strlen.de>
> Signed-off-by: Florian Westphal <fw@strlen.de>
> Co-developed-by: Paolo Abeni <pabeni@redhat.com>
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com>
> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
> ---
>  net/mptcp/Makefile   |   2 +-
>  net/mptcp/crypto.c   | 122 +++++++++++++++++++++++++++
>  net/mptcp/protocol.c |  16 ++++
>  net/mptcp/protocol.h |  32 +++++++
>  net/mptcp/subflow.c  |  66 +++++++++++++--
>  net/mptcp/token.c    | 195 +++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 425 insertions(+), 8 deletions(-)
>  create mode 100644 net/mptcp/crypto.c
>  create mode 100644 net/mptcp/token.c
> 
> diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile
> index e1ee5aade8b0..178ae81d8b66 100644
> --- a/net/mptcp/Makefile
> +++ b/net/mptcp/Makefile
> @@ -1,4 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0
>  obj-$(CONFIG_MPTCP) += mptcp.o
>  
> -mptcp-y := protocol.o subflow.o options.o
> +mptcp-y := protocol.o subflow.o options.o token.o crypto.o
> diff --git a/net/mptcp/crypto.c b/net/mptcp/crypto.c
> new file mode 100644
> index 000000000000..bbd6d01af211
> --- /dev/null
> +++ b/net/mptcp/crypto.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Multipath TCP cryptographic functions
> + * Copyright (c) 2017 - 2019, Intel Corporation.
> + *
> + * Note: This code is based on mptcp_ctrl.c, mptcp_ipv4.c, and
> + *       mptcp_ipv6 from multipath-tcp.org, authored by:
> + *
> + *       Sébastien Barré <sebastien.barre@uclouvain.be>
> + *       Christoph Paasch <christoph.paasch@uclouvain.be>
> + *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
> + *       Gregory Detal <gregory.detal@uclouvain.be>
> + *       Fabien Duchêne <fabien.duchene@uclouvain.be>
> + *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
> + *       Lavkesh Lahngir <lavkesh51@gmail.com>
> + *       Andreas Ripke <ripke@neclab.eu>
> + *       Vlad Dogaru <vlad.dogaru@intel.com>
> + *       Octavian Purdila <octavian.purdila@intel.com>
> + *       John Ronan <jronan@tssg.org>
> + *       Catalin Nicutar <catalin.nicutar@gmail.com>
> + *       Brandon Heller <brandonh@stanford.edu>
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/cryptohash.h>
> +#include <asm/unaligned.h>
> +
> +#include "protocol.h"
> +
> +struct sha1_state {
> +	u32 workspace[SHA_WORKSPACE_WORDS];
> +	u32 digest[SHA_DIGEST_WORDS];
> +	unsigned int count;
> +};
> +
> +static void sha1_init(struct sha1_state *state)
> +{
> +	sha_init(state->digest);
> +	state->count = 0;
> +}
> +
> +static void sha1_update(struct sha1_state *state, u8 *input)
> +{
> +	sha_transform(state->digest, input, state->workspace);
> +	state->count += SHA_MESSAGE_BYTES;
> +}
> +
> +static void sha1_pad_final(struct sha1_state *state, u8 *input,
> +			   unsigned int length, __be32 *mptcp_hashed_key)
> +{
> +	int i;
> +
> +	input[length] = 0x80;
> +	memset(&input[length + 1], 0, SHA_MESSAGE_BYTES - length - 9);
> +	put_unaligned_be64((length + state->count) << 3,
> +			   &input[SHA_MESSAGE_BYTES - 8]);
> +
> +	sha_transform(state->digest, input, state->workspace);
> +	for (i = 0; i < SHA_DIGEST_WORDS; ++i)
> +		put_unaligned_be32(state->digest[i], &mptcp_hashed_key[i]);
> +
> +	memzero_explicit(state->workspace, SHA_WORKSPACE_WORDS << 2);
> +}
> +
> +void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
> +{
> +	__be32 mptcp_hashed_key[SHA_DIGEST_WORDS];
> +	u8 input[SHA_MESSAGE_BYTES];
> +	struct sha1_state state;
> +
> +	sha1_init(&state);
> +	put_unaligned_be64(key, input);
> +	sha1_pad_final(&state, input, 8, mptcp_hashed_key);
> +
> +	if (token)
> +		*token = be32_to_cpu(mptcp_hashed_key[0]);
> +	if (idsn)
> +		*idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[3]));
> +}
> +
> +void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
> +			   u32 *hash_out)
> +{
> +	u8 input[SHA_MESSAGE_BYTES * 2];
> +	struct sha1_state state;
> +	u8 key1be[8];
> +	u8 key2be[8];
> +	int i;
> +
> +	put_unaligned_be64(key1, key1be);
> +	put_unaligned_be64(key2, key2be);
> +
> +	/* Generate key xored with ipad */
> +	memset(input, 0x36, SHA_MESSAGE_BYTES);
> +	for (i = 0; i < 8; i++)
> +		input[i] ^= key1be[i];
> +	for (i = 0; i < 8; i++)
> +		input[i + 8] ^= key2be[i];
> +
> +	put_unaligned_be32(nonce1, &input[SHA_MESSAGE_BYTES]);
> +	put_unaligned_be32(nonce2, &input[SHA_MESSAGE_BYTES + 4]);
> +
> +	sha1_init(&state);
> +	sha1_update(&state, input);
> +
> +	/* emit sha256(K1 || msg) on the second input block, so we can
> +	 * reuse 'input' for the last hashing
> +	 */
> +	sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], 8,
> +		       (__force __be32 *)&input[SHA_MESSAGE_BYTES]);
> +
> +	/* Prepare second part of hmac */
> +	memset(input, 0x5C, SHA_MESSAGE_BYTES);
> +	for (i = 0; i < 8; i++)
> +		input[i] ^= key1be[i];
> +	for (i = 0; i < 8; i++)
> +		input[i + 8] ^= key2be[i];
> +
> +	sha1_init(&state);
> +	sha1_update(&state, input);
> +	sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], SHA_DIGEST_WORDS << 2,
> +		       (__be32 *)hash_out);
> +}
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 147a3a9fdc0a..19b1250bb8cc 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -199,6 +199,7 @@ static void mptcp_close(struct sock *sk, long timeout)
>  	struct mptcp_subflow_context *subflow, *tmp;
>  	struct mptcp_sock *msk = mptcp_sk(sk);
>  
> +	mptcp_token_destroy(msk->token);
>  	inet_sk_state_store(sk, TCP_CLOSE);
>  
>  	lock_sock(sk);
> @@ -279,8 +280,10 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
>  		msk = mptcp_sk(new_mptcp_sock);
>  		msk->remote_key = subflow->remote_key;
>  		msk->local_key = subflow->local_key;
> +		msk->token = subflow->token;
>  		msk->subflow = NULL;
>  
> +		mptcp_token_update_accept(newsk, new_mptcp_sock);
>  		newsk = new_mptcp_sock;
>  		mptcp_copy_inaddrs(newsk, ssk);
>  		list_add(&subflow->node, &msk->conn_list);
> @@ -299,6 +302,10 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
>  	return newsk;
>  }
>  
> +static void mptcp_destroy(struct sock *sk)
> +{
> +}
> +
>  static int mptcp_get_port(struct sock *sk, unsigned short snum)
>  {
>  	struct mptcp_sock *msk = mptcp_sk(sk);
> @@ -331,6 +338,7 @@ void mptcp_finish_connect(struct sock *ssk)
>  	 */
>  	WRITE_ONCE(msk->remote_key, subflow->remote_key);
>  	WRITE_ONCE(msk->local_key, subflow->local_key);
> +	WRITE_ONCE(msk->token, subflow->token);
>  }
>  
>  static void mptcp_sock_graft(struct sock *sk, struct socket *parent)
> @@ -349,6 +357,7 @@ static struct proto mptcp_prot = {
>  	.close		= mptcp_close,
>  	.accept		= mptcp_accept,
>  	.shutdown	= tcp_shutdown,
> +	.destroy	= mptcp_destroy,
>  	.sendmsg	= mptcp_sendmsg,
>  	.recvmsg	= mptcp_recvmsg,
>  	.hash		= inet_hash,
> @@ -568,6 +577,12 @@ void __init mptcp_init(void)
>  static struct proto_ops mptcp_v6_stream_ops;
>  static struct proto mptcp_v6_prot;
>  
> +static void mptcp_v6_destroy(struct sock *sk)
> +{
> +	mptcp_destroy(sk);
> +	inet6_destroy_sock(sk);
> +}
> +
>  static struct inet_protosw mptcp_v6_protosw = {
>  	.type		= SOCK_STREAM,
>  	.protocol	= IPPROTO_MPTCP,
> @@ -583,6 +598,7 @@ int mptcpv6_init(void)
>  	mptcp_v6_prot = mptcp_prot;
>  	strcpy(mptcp_v6_prot.name, "MPTCPv6");
>  	mptcp_v6_prot.slab = NULL;
> +	mptcp_v6_prot.destroy = mptcp_v6_destroy;
>  	mptcp_v6_prot.obj_size = sizeof(struct mptcp_sock) +
>  				 sizeof(struct ipv6_pinfo);
>  
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index bd66e7415515..4cf9620d19ec 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -7,6 +7,10 @@
>  #ifndef __MPTCP_PROTOCOL_H
>  #define __MPTCP_PROTOCOL_H
>  
> +#include <linux/random.h>
> +#include <linux/tcp.h>
> +#include <net/inet_connection_sock.h>
> +
>  #define MPTCP_SUPPORTED_VERSION	0
>  
>  /* MPTCP option bits */
> @@ -42,6 +46,7 @@ struct mptcp_sock {
>  	struct inet_connection_sock sk;
>  	u64		local_key;
>  	u64		remote_key;
> +	u32		token;
>  	struct list_head conn_list;
>  	struct socket	*subflow; /* outgoing connect/listener/!mp_capable */
>  };
> @@ -61,6 +66,8 @@ struct mptcp_subflow_request_sock {
>  		backup : 1;
>  	u64	local_key;
>  	u64	remote_key;
> +	u64	idsn;
> +	u32	token;
>  };
>  
>  static inline struct mptcp_subflow_request_sock *
> @@ -74,6 +81,8 @@ struct mptcp_subflow_context {
>  	struct	list_head node;/* conn_list of subflows */
>  	u64	local_key;
>  	u64	remote_key;
> +	u64	idsn;
> +	u32	token;
>  	u32	request_mptcp : 1,  /* send MP_CAPABLE */
>  		mp_capable : 1,	    /* remote is MPTCP capable */
>  		fourth_ack : 1,	    /* send initial DSS */
> @@ -112,4 +121,27 @@ void mptcp_get_options(const struct sk_buff *skb,
>  
>  void mptcp_finish_connect(struct sock *sk);
>  
> +int mptcp_token_new_request(struct request_sock *req);
> +void mptcp_token_destroy_request(u32 token);
> +int mptcp_token_new_connect(struct sock *sk);
> +int mptcp_token_new_accept(u32 token);
> +void mptcp_token_update_accept(struct sock *sk, struct sock *conn);
> +void mptcp_token_destroy(u32 token);
> +
> +void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn);
> +static inline void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
> +{
> +	/* we might consider a faster version that computes the key as a
> +	 * hash of some information available in the MPTCP socket. Use
> +	 * random data at the moment, as it's probably the safest option
> +	 * in case multiple sockets are opened in different namespaces at
> +	 * the same time.
> +	 */
> +	get_random_bytes(key, sizeof(u64));
> +	mptcp_crypto_key_sha(*key, token, idsn);
> +}
> +
> +void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
> +			   u32 *hash_out);
> +
>  #endif /* __MPTCP_PROTOCOL_H */
> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
> index b9aca17b0b91..35134342fab0 100644
> --- a/net/mptcp/subflow.c
> +++ b/net/mptcp/subflow.c
> @@ -4,6 +4,8 @@
>   * Copyright (c) 2017 - 2019, Intel Corporation.
>   */
>  
> +#define pr_fmt(fmt) "MPTCP: " fmt
> +
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/netdevice.h>
> @@ -18,6 +20,33 @@
>  #include <net/mptcp.h>
>  #include "protocol.h"
>  
> +static int subflow_rebuild_header(struct sock *sk)
> +{
> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
> +	int err = 0;
> +
> +	if (subflow->request_mptcp && !subflow->token) {
> +		pr_debug("subflow=%p", sk);
> +		err = mptcp_token_new_connect(sk);
> +	}
> +
> +	if (err)
> +		return err;
> +
> +	return subflow->icsk_af_ops->rebuild_header(sk);
> +}
> +
> +static void subflow_req_destructor(struct request_sock *req)
> +{
> +	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
> +
> +	pr_debug("subflow_req=%p", subflow_req);
> +
> +	if (subflow_req->mp_capable)
> +		mptcp_token_destroy_request(subflow_req->token);
> +	tcp_request_sock_ops.destructor(req);
> +}
> +
>  static void subflow_init_req(struct request_sock *req,
>  			     const struct sock *sk_listener,
>  			     struct sk_buff *skb)
> @@ -42,7 +71,12 @@ static void subflow_init_req(struct request_sock *req,
>  #endif
>  
>  	if (rx_opt.mptcp.mp_capable && listener->request_mptcp) {
> -		subflow_req->mp_capable = 1;
> +		int err;
> +
> +		err = mptcp_token_new_request(req);
> +		if (err == 0)
> +			subflow_req->mp_capable = 1;
> +
>  		subflow_req->remote_key = rx_opt.mptcp.sndr_key;
>  	}
>  }
> @@ -124,16 +158,25 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
>  						     req_unhash, own_req);
>  
>  	if (child && *own_req) {
> -		if (!mptcp_subflow_ctx(child)) {
> -			pr_debug("Closing child socket");
> -			inet_sk_set_state(child, TCP_CLOSE);
> -			sock_set_flag(child, SOCK_DEAD);
> -			inet_csk_destroy_sock(child);
> -			child = NULL;
> +		struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(child);
> +
> +		if (!ctx)
> +			goto close_child;
> +
> +		if (ctx->mp_capable) {
> +			if (mptcp_token_new_accept(ctx->token))
> +				goto close_child;
>  		}
>  	}
>  
>  	return child;
> +
> +close_child:
> +	pr_debug("closing child socket");
> +	tcp_send_active_reset(child, GFP_ATOMIC);
> +	inet_csk_prepare_forced_close(child);
> +	tcp_done(child);
> +	return NULL;
>  }
>  
>  static struct inet_connection_sock_af_ops subflow_specific;
> @@ -186,6 +229,7 @@ int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
>  	pr_debug("subflow=%p", subflow);
>  
>  	*new_sock = sf;
> +	sock_hold(sk);
>  	subflow->conn = sk;
>  
>  	return 0;
> @@ -251,6 +295,9 @@ static void subflow_ulp_release(struct sock *sk)
>  	if (!ctx)
>  		return;
>  
> +	if (ctx->conn)
> +		sock_put(ctx->conn);
> +
>  	kfree_rcu(ctx, rcu);
>  }
>  
> @@ -276,6 +323,7 @@ static void subflow_ulp_clone(const struct request_sock *req,
>  		new_ctx->fourth_ack = 1;
>  		new_ctx->remote_key = subflow_req->remote_key;
>  		new_ctx->local_key = subflow_req->local_key;
> +		new_ctx->token = subflow_req->token;
>  	} else {
>  		tcp_sk(newsk)->is_mptcp = 0;
>  	}
> @@ -302,6 +350,8 @@ static int subflow_ops_init(struct request_sock_ops *subflow_ops)
>  	if (!subflow_ops->slab)
>  		return -ENOMEM;
>  
> +	subflow_ops->destructor = subflow_req_destructor;
> +
>  	return 0;
>  }
>  
> @@ -318,6 +368,7 @@ void mptcp_subflow_init(void)
>  	subflow_specific.conn_request = subflow_v4_conn_request;
>  	subflow_specific.syn_recv_sock = subflow_syn_recv_sock;
>  	subflow_specific.sk_rx_dst_set = subflow_finish_connect;
> +	subflow_specific.rebuild_header = subflow_rebuild_header;
>  
>  #if IS_ENABLED(CONFIG_MPTCP_IPV6)
>  	subflow_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops;
> @@ -327,6 +378,7 @@ void mptcp_subflow_init(void)
>  	subflow_v6_specific.conn_request = subflow_v6_conn_request;
>  	subflow_v6_specific.syn_recv_sock = subflow_syn_recv_sock;
>  	subflow_v6_specific.sk_rx_dst_set = subflow_finish_connect;
> +	subflow_v6_specific.rebuild_header = subflow_rebuild_header;
>  #endif
>  
>  	if (tcp_register_ulp(&subflow_ulp_ops) != 0)
> diff --git a/net/mptcp/token.c b/net/mptcp/token.c
> new file mode 100644
> index 000000000000..84d887806090
> --- /dev/null
> +++ b/net/mptcp/token.c
> @@ -0,0 +1,195 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Multipath TCP token management
> + * Copyright (c) 2017 - 2019, Intel Corporation.
> + *
> + * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org,
> + *       authored by:
> + *
> + *       Sébastien Barré <sebastien.barre@uclouvain.be>
> + *       Christoph Paasch <christoph.paasch@uclouvain.be>
> + *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
> + *       Gregory Detal <gregory.detal@uclouvain.be>
> + *       Fabien Duchêne <fabien.duchene@uclouvain.be>
> + *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
> + *       Lavkesh Lahngir <lavkesh51@gmail.com>
> + *       Andreas Ripke <ripke@neclab.eu>
> + *       Vlad Dogaru <vlad.dogaru@intel.com>
> + *       Octavian Purdila <octavian.purdila@intel.com>
> + *       John Ronan <jronan@tssg.org>
> + *       Catalin Nicutar <catalin.nicutar@gmail.com>
> + *       Brandon Heller <brandonh@stanford.edu>
> + */
> +
> +#define pr_fmt(fmt) "MPTCP: " fmt
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/radix-tree.h>
> +#include <linux/ip.h>
> +#include <linux/tcp.h>
> +#include <net/sock.h>
> +#include <net/inet_common.h>
> +#include <net/protocol.h>
> +#include <net/mptcp.h>
> +#include "protocol.h"
> +
> +static RADIX_TREE(token_tree, GFP_ATOMIC);
> +static RADIX_TREE(token_req_tree, GFP_ATOMIC);
> +static DEFINE_SPINLOCK(token_tree_lock);
> +static int token_used __read_mostly;
> +
> +/**
> + * mptcp_token_new_request - create new key/idsn/token for subflow_request
> + * @req - the request socket
> + *
> + * This function is called when a new mptcp connection is coming in.
> + *
> + * It creates a unique token to identify the new mptcp connection,
> + * a secret local key and the initial data sequence number (idsn).
> + *
> + * Returns 0 on success.
> + */
> +int mptcp_token_new_request(struct request_sock *req)
> +{
> +	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
> +	int err;
> +
> +	while (1) {
> +		u32 token;
> +
> +		mptcp_crypto_key_gen_sha(&subflow_req->local_key,
> +					 &subflow_req->token,
> +					 &subflow_req->idsn);
> +		pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
> +			 req, subflow_req->local_key, subflow_req->token,
> +			 subflow_req->idsn);
> +
> +		token = subflow_req->token;
> +		spin_lock_bh(&token_tree_lock);
> +		if (!radix_tree_lookup(&token_req_tree, token) &&
> +		    !radix_tree_lookup(&token_tree, token))
> +			break;
> +		spin_unlock_bh(&token_tree_lock);
> +	}
> +
> +	err = radix_tree_insert(&token_req_tree,
> +				subflow_req->token, &token_used);
> +	spin_unlock_bh(&token_tree_lock);
> +	return err;
> +}
> +
> +/**
> + * mptcp_token_new_connect - create new key/idsn/token for subflow
> + * @sk - the socket that will initiate a connection
> + *
> + * This function is called when a new outgoing mptcp connection is
> + * initiated.
> + *
> + * It creates a unique token to identify the new mptcp connection,
> + * a secret local key and the initial data sequence number (idsn).
> + *
> + * On success, the mptcp connection can be found again using
> + * the computed token at a later time, this is needed to process
> + * join requests.
> + *
> + * returns 0 on success.
> + */
> +int mptcp_token_new_connect(struct sock *sk)
> +{
> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
> +	struct sock *mptcp_sock = subflow->conn;
> +	int err;
> +
> +	while (1) {
> +		u32 token;
> +
> +		mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
> +					 &subflow->idsn);
> +
> +		pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
> +			 sk, subflow->local_key, subflow->token, subflow->idsn);
> +
> +		token = subflow->token;
> +		spin_lock_bh(&token_tree_lock);
> +		if (!radix_tree_lookup(&token_req_tree, token) &&
> +		    !radix_tree_lookup(&token_tree, token))
> +			break;
> +		spin_unlock_bh(&token_tree_lock);
> +	}
> +	err = radix_tree_insert(&token_tree, subflow->token, mptcp_sock);
> +	spin_unlock_bh(&token_tree_lock);
> +
> +	return err;
> +}
> +
> +/**
> + * mptcp_token_new_accept - insert token for later processing
> + * @token: the token to insert to the tree
> + *
> + * Called when a SYN packet creates a new logical connection, i.e.
> + * is not a join request.
> + *
> + * We don't have an mptcp socket yet at that point.
> + * This is paired with mptcp_token_update_accept, called on accept().
> + */
> +int mptcp_token_new_accept(u32 token)
> +{
> +	int err;
> +
> +	spin_lock_bh(&token_tree_lock);
> +	err = radix_tree_insert(&token_tree, token, &token_used);
> +	spin_unlock_bh(&token_tree_lock);
> +
> +	return err;
> +}
> +
> +/**
> + * mptcp_token_update_accept - update token to map to mptcp socket
> + * @conn: the new struct mptcp_sock
> + * @sk: the initial subflow for this mptcp socket
> + *
> + * Called when the first mptcp socket is created on accept to
> + * refresh the dummy mapping (done to reserve the token) with
> + * the mptcp_socket structure that wasn't allocated before.
> + */
> +void mptcp_token_update_accept(struct sock *sk, struct sock *conn)
> +{
> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
> +	void __rcu **slot;
> +
> +	spin_lock_bh(&token_tree_lock);
> +	slot = radix_tree_lookup_slot(&token_tree, subflow->token);
> +	WARN_ON_ONCE(!slot);
> +	if (slot) {
> +		WARN_ON_ONCE(rcu_access_pointer(*slot) != &token_used);
> +		radix_tree_replace_slot(&token_tree, slot, conn);
> +	}
> +	spin_unlock_bh(&token_tree_lock);
> +}
> +
> +/**
> + * mptcp_token_destroy_request - remove mptcp connection/token
> + * @token - token of mptcp connection to remove
> + *
> + * Remove not-yet-fully-established incoming connection identified
> + * by @token.
> + */
> +void mptcp_token_destroy_request(u32 token)
> +{
> +	spin_lock_bh(&token_tree_lock);
> +	radix_tree_delete(&token_req_tree, token);
> +	spin_unlock_bh(&token_tree_lock);
> +}
> +
> +/**
> + * mptcp_token_destroy - remove mptcp connection/token
> + * @token - token of mptcp connection to remove
> + *
> + * Remove the connection identified by @token.
> + */
> +void mptcp_token_destroy(u32 token)
> +{
> +	spin_lock_bh(&token_tree_lock);
> +	radix_tree_delete(&token_tree, token);
> +	spin_unlock_bh(&token_tree_lock);
> +}
Mat Martineau Dec. 14, 2019, 5:28 a.m. UTC | #2
On Fri, 13 Dec 2019, Peter Krystad wrote:

> On Fri, 2019-12-13 at 21:50 +0100, Matthieu Baerts wrote:
>> From: Peter Krystad <peter.krystad@linux.intel.com>
>>
>> Generate the local keys, IDSN, and token when creating a new socket.
>> Introduce the token tree to track all tokens in use using a radix tree
>> with the MPTCP token itself as the index.
>
> Add here:
>
> Override the rebuild_header callback in inet_connection_sock_af_ops for
> creating the local key on a new outgoing connection.
>
> Override the init_req callback of tcp_request_sock_ops for creating the local
> key on a new incoming connection.
>

Done, thanks.


Mat


>> Will be used to obtain the MPTCP parent socket to handle incoming joins.
>>
>> Co-developed-by: Davide Caratti <dcaratti@redhat.com>
>> Signed-off-by: Davide Caratti <dcaratti@redhat.com>
>> Co-developed-by: Florian Westphal <fw@strlen.de>
>> Signed-off-by: Florian Westphal <fw@strlen.de>
>> Co-developed-by: Paolo Abeni <pabeni@redhat.com>
>> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
>> Signed-off-by: Peter Krystad <peter.krystad@linux.intel.com>
>> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
>> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
>> ---
>>  net/mptcp/Makefile   |   2 +-
>>  net/mptcp/crypto.c   | 122 +++++++++++++++++++++++++++
>>  net/mptcp/protocol.c |  16 ++++
>>  net/mptcp/protocol.h |  32 +++++++
>>  net/mptcp/subflow.c  |  66 +++++++++++++--
>>  net/mptcp/token.c    | 195 +++++++++++++++++++++++++++++++++++++++++++
>>  6 files changed, 425 insertions(+), 8 deletions(-)
>>  create mode 100644 net/mptcp/crypto.c
>>  create mode 100644 net/mptcp/token.c
>>
>> diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile
>> index e1ee5aade8b0..178ae81d8b66 100644
>> --- a/net/mptcp/Makefile
>> +++ b/net/mptcp/Makefile
>> @@ -1,4 +1,4 @@
>>  # SPDX-License-Identifier: GPL-2.0
>>  obj-$(CONFIG_MPTCP) += mptcp.o
>>
>> -mptcp-y := protocol.o subflow.o options.o
>> +mptcp-y := protocol.o subflow.o options.o token.o crypto.o
>> diff --git a/net/mptcp/crypto.c b/net/mptcp/crypto.c
>> new file mode 100644
>> index 000000000000..bbd6d01af211
>> --- /dev/null
>> +++ b/net/mptcp/crypto.c
>> @@ -0,0 +1,122 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Multipath TCP cryptographic functions
>> + * Copyright (c) 2017 - 2019, Intel Corporation.
>> + *
>> + * Note: This code is based on mptcp_ctrl.c, mptcp_ipv4.c, and
>> + *       mptcp_ipv6 from multipath-tcp.org, authored by:
>> + *
>> + *       Sébastien Barré <sebastien.barre@uclouvain.be>
>> + *       Christoph Paasch <christoph.paasch@uclouvain.be>
>> + *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
>> + *       Gregory Detal <gregory.detal@uclouvain.be>
>> + *       Fabien Duchêne <fabien.duchene@uclouvain.be>
>> + *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
>> + *       Lavkesh Lahngir <lavkesh51@gmail.com>
>> + *       Andreas Ripke <ripke@neclab.eu>
>> + *       Vlad Dogaru <vlad.dogaru@intel.com>
>> + *       Octavian Purdila <octavian.purdila@intel.com>
>> + *       John Ronan <jronan@tssg.org>
>> + *       Catalin Nicutar <catalin.nicutar@gmail.com>
>> + *       Brandon Heller <brandonh@stanford.edu>
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/cryptohash.h>
>> +#include <asm/unaligned.h>
>> +
>> +#include "protocol.h"
>> +
>> +struct sha1_state {
>> +	u32 workspace[SHA_WORKSPACE_WORDS];
>> +	u32 digest[SHA_DIGEST_WORDS];
>> +	unsigned int count;
>> +};
>> +
>> +static void sha1_init(struct sha1_state *state)
>> +{
>> +	sha_init(state->digest);
>> +	state->count = 0;
>> +}
>> +
>> +static void sha1_update(struct sha1_state *state, u8 *input)
>> +{
>> +	sha_transform(state->digest, input, state->workspace);
>> +	state->count += SHA_MESSAGE_BYTES;
>> +}
>> +
>> +static void sha1_pad_final(struct sha1_state *state, u8 *input,
>> +			   unsigned int length, __be32 *mptcp_hashed_key)
>> +{
>> +	int i;
>> +
>> +	input[length] = 0x80;
>> +	memset(&input[length + 1], 0, SHA_MESSAGE_BYTES - length - 9);
>> +	put_unaligned_be64((length + state->count) << 3,
>> +			   &input[SHA_MESSAGE_BYTES - 8]);
>> +
>> +	sha_transform(state->digest, input, state->workspace);
>> +	for (i = 0; i < SHA_DIGEST_WORDS; ++i)
>> +		put_unaligned_be32(state->digest[i], &mptcp_hashed_key[i]);
>> +
>> +	memzero_explicit(state->workspace, SHA_WORKSPACE_WORDS << 2);
>> +}
>> +
>> +void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
>> +{
>> +	__be32 mptcp_hashed_key[SHA_DIGEST_WORDS];
>> +	u8 input[SHA_MESSAGE_BYTES];
>> +	struct sha1_state state;
>> +
>> +	sha1_init(&state);
>> +	put_unaligned_be64(key, input);
>> +	sha1_pad_final(&state, input, 8, mptcp_hashed_key);
>> +
>> +	if (token)
>> +		*token = be32_to_cpu(mptcp_hashed_key[0]);
>> +	if (idsn)
>> +		*idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[3]));
>> +}
>> +
>> +void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
>> +			   u32 *hash_out)
>> +{
>> +	u8 input[SHA_MESSAGE_BYTES * 2];
>> +	struct sha1_state state;
>> +	u8 key1be[8];
>> +	u8 key2be[8];
>> +	int i;
>> +
>> +	put_unaligned_be64(key1, key1be);
>> +	put_unaligned_be64(key2, key2be);
>> +
>> +	/* Generate key xored with ipad */
>> +	memset(input, 0x36, SHA_MESSAGE_BYTES);
>> +	for (i = 0; i < 8; i++)
>> +		input[i] ^= key1be[i];
>> +	for (i = 0; i < 8; i++)
>> +		input[i + 8] ^= key2be[i];
>> +
>> +	put_unaligned_be32(nonce1, &input[SHA_MESSAGE_BYTES]);
>> +	put_unaligned_be32(nonce2, &input[SHA_MESSAGE_BYTES + 4]);
>> +
>> +	sha1_init(&state);
>> +	sha1_update(&state, input);
>> +
>> +	/* emit sha256(K1 || msg) on the second input block, so we can
>> +	 * reuse 'input' for the last hashing
>> +	 */
>> +	sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], 8,
>> +		       (__force __be32 *)&input[SHA_MESSAGE_BYTES]);
>> +
>> +	/* Prepare second part of hmac */
>> +	memset(input, 0x5C, SHA_MESSAGE_BYTES);
>> +	for (i = 0; i < 8; i++)
>> +		input[i] ^= key1be[i];
>> +	for (i = 0; i < 8; i++)
>> +		input[i + 8] ^= key2be[i];
>> +
>> +	sha1_init(&state);
>> +	sha1_update(&state, input);
>> +	sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], SHA_DIGEST_WORDS << 2,
>> +		       (__be32 *)hash_out);
>> +}
>> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
>> index 147a3a9fdc0a..19b1250bb8cc 100644
>> --- a/net/mptcp/protocol.c
>> +++ b/net/mptcp/protocol.c
>> @@ -199,6 +199,7 @@ static void mptcp_close(struct sock *sk, long timeout)
>>  	struct mptcp_subflow_context *subflow, *tmp;
>>  	struct mptcp_sock *msk = mptcp_sk(sk);
>>
>> +	mptcp_token_destroy(msk->token);
>>  	inet_sk_state_store(sk, TCP_CLOSE);
>>
>>  	lock_sock(sk);
>> @@ -279,8 +280,10 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
>>  		msk = mptcp_sk(new_mptcp_sock);
>>  		msk->remote_key = subflow->remote_key;
>>  		msk->local_key = subflow->local_key;
>> +		msk->token = subflow->token;
>>  		msk->subflow = NULL;
>>
>> +		mptcp_token_update_accept(newsk, new_mptcp_sock);
>>  		newsk = new_mptcp_sock;
>>  		mptcp_copy_inaddrs(newsk, ssk);
>>  		list_add(&subflow->node, &msk->conn_list);
>> @@ -299,6 +302,10 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
>>  	return newsk;
>>  }
>>
>> +static void mptcp_destroy(struct sock *sk)
>> +{
>> +}
>> +
>>  static int mptcp_get_port(struct sock *sk, unsigned short snum)
>>  {
>>  	struct mptcp_sock *msk = mptcp_sk(sk);
>> @@ -331,6 +338,7 @@ void mptcp_finish_connect(struct sock *ssk)
>>  	 */
>>  	WRITE_ONCE(msk->remote_key, subflow->remote_key);
>>  	WRITE_ONCE(msk->local_key, subflow->local_key);
>> +	WRITE_ONCE(msk->token, subflow->token);
>>  }
>>
>>  static void mptcp_sock_graft(struct sock *sk, struct socket *parent)
>> @@ -349,6 +357,7 @@ static struct proto mptcp_prot = {
>>  	.close		= mptcp_close,
>>  	.accept		= mptcp_accept,
>>  	.shutdown	= tcp_shutdown,
>> +	.destroy	= mptcp_destroy,
>>  	.sendmsg	= mptcp_sendmsg,
>>  	.recvmsg	= mptcp_recvmsg,
>>  	.hash		= inet_hash,
>> @@ -568,6 +577,12 @@ void __init mptcp_init(void)
>>  static struct proto_ops mptcp_v6_stream_ops;
>>  static struct proto mptcp_v6_prot;
>>
>> +static void mptcp_v6_destroy(struct sock *sk)
>> +{
>> +	mptcp_destroy(sk);
>> +	inet6_destroy_sock(sk);
>> +}
>> +
>>  static struct inet_protosw mptcp_v6_protosw = {
>>  	.type		= SOCK_STREAM,
>>  	.protocol	= IPPROTO_MPTCP,
>> @@ -583,6 +598,7 @@ int mptcpv6_init(void)
>>  	mptcp_v6_prot = mptcp_prot;
>>  	strcpy(mptcp_v6_prot.name, "MPTCPv6");
>>  	mptcp_v6_prot.slab = NULL;
>> +	mptcp_v6_prot.destroy = mptcp_v6_destroy;
>>  	mptcp_v6_prot.obj_size = sizeof(struct mptcp_sock) +
>>  				 sizeof(struct ipv6_pinfo);
>>
>> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
>> index bd66e7415515..4cf9620d19ec 100644
>> --- a/net/mptcp/protocol.h
>> +++ b/net/mptcp/protocol.h
>> @@ -7,6 +7,10 @@
>>  #ifndef __MPTCP_PROTOCOL_H
>>  #define __MPTCP_PROTOCOL_H
>>
>> +#include <linux/random.h>
>> +#include <linux/tcp.h>
>> +#include <net/inet_connection_sock.h>
>> +
>>  #define MPTCP_SUPPORTED_VERSION	0
>>
>>  /* MPTCP option bits */
>> @@ -42,6 +46,7 @@ struct mptcp_sock {
>>  	struct inet_connection_sock sk;
>>  	u64		local_key;
>>  	u64		remote_key;
>> +	u32		token;
>>  	struct list_head conn_list;
>>  	struct socket	*subflow; /* outgoing connect/listener/!mp_capable */
>>  };
>> @@ -61,6 +66,8 @@ struct mptcp_subflow_request_sock {
>>  		backup : 1;
>>  	u64	local_key;
>>  	u64	remote_key;
>> +	u64	idsn;
>> +	u32	token;
>>  };
>>
>>  static inline struct mptcp_subflow_request_sock *
>> @@ -74,6 +81,8 @@ struct mptcp_subflow_context {
>>  	struct	list_head node;/* conn_list of subflows */
>>  	u64	local_key;
>>  	u64	remote_key;
>> +	u64	idsn;
>> +	u32	token;
>>  	u32	request_mptcp : 1,  /* send MP_CAPABLE */
>>  		mp_capable : 1,	    /* remote is MPTCP capable */
>>  		fourth_ack : 1,	    /* send initial DSS */
>> @@ -112,4 +121,27 @@ void mptcp_get_options(const struct sk_buff *skb,
>>
>>  void mptcp_finish_connect(struct sock *sk);
>>
>> +int mptcp_token_new_request(struct request_sock *req);
>> +void mptcp_token_destroy_request(u32 token);
>> +int mptcp_token_new_connect(struct sock *sk);
>> +int mptcp_token_new_accept(u32 token);
>> +void mptcp_token_update_accept(struct sock *sk, struct sock *conn);
>> +void mptcp_token_destroy(u32 token);
>> +
>> +void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn);
>> +static inline void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
>> +{
>> +	/* we might consider a faster version that computes the key as a
>> +	 * hash of some information available in the MPTCP socket. Use
>> +	 * random data at the moment, as it's probably the safest option
>> +	 * in case multiple sockets are opened in different namespaces at
>> +	 * the same time.
>> +	 */
>> +	get_random_bytes(key, sizeof(u64));
>> +	mptcp_crypto_key_sha(*key, token, idsn);
>> +}
>> +
>> +void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
>> +			   u32 *hash_out);
>> +
>>  #endif /* __MPTCP_PROTOCOL_H */
>> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
>> index b9aca17b0b91..35134342fab0 100644
>> --- a/net/mptcp/subflow.c
>> +++ b/net/mptcp/subflow.c
>> @@ -4,6 +4,8 @@
>>   * Copyright (c) 2017 - 2019, Intel Corporation.
>>   */
>>
>> +#define pr_fmt(fmt) "MPTCP: " fmt
>> +
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/netdevice.h>
>> @@ -18,6 +20,33 @@
>>  #include <net/mptcp.h>
>>  #include "protocol.h"
>>
>> +static int subflow_rebuild_header(struct sock *sk)
>> +{
>> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
>> +	int err = 0;
>> +
>> +	if (subflow->request_mptcp && !subflow->token) {
>> +		pr_debug("subflow=%p", sk);
>> +		err = mptcp_token_new_connect(sk);
>> +	}
>> +
>> +	if (err)
>> +		return err;
>> +
>> +	return subflow->icsk_af_ops->rebuild_header(sk);
>> +}
>> +
>> +static void subflow_req_destructor(struct request_sock *req)
>> +{
>> +	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
>> +
>> +	pr_debug("subflow_req=%p", subflow_req);
>> +
>> +	if (subflow_req->mp_capable)
>> +		mptcp_token_destroy_request(subflow_req->token);
>> +	tcp_request_sock_ops.destructor(req);
>> +}
>> +
>>  static void subflow_init_req(struct request_sock *req,
>>  			     const struct sock *sk_listener,
>>  			     struct sk_buff *skb)
>> @@ -42,7 +71,12 @@ static void subflow_init_req(struct request_sock *req,
>>  #endif
>>
>>  	if (rx_opt.mptcp.mp_capable && listener->request_mptcp) {
>> -		subflow_req->mp_capable = 1;
>> +		int err;
>> +
>> +		err = mptcp_token_new_request(req);
>> +		if (err == 0)
>> +			subflow_req->mp_capable = 1;
>> +
>>  		subflow_req->remote_key = rx_opt.mptcp.sndr_key;
>>  	}
>>  }
>> @@ -124,16 +158,25 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
>>  						     req_unhash, own_req);
>>
>>  	if (child && *own_req) {
>> -		if (!mptcp_subflow_ctx(child)) {
>> -			pr_debug("Closing child socket");
>> -			inet_sk_set_state(child, TCP_CLOSE);
>> -			sock_set_flag(child, SOCK_DEAD);
>> -			inet_csk_destroy_sock(child);
>> -			child = NULL;
>> +		struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(child);
>> +
>> +		if (!ctx)
>> +			goto close_child;
>> +
>> +		if (ctx->mp_capable) {
>> +			if (mptcp_token_new_accept(ctx->token))
>> +				goto close_child;
>>  		}
>>  	}
>>
>>  	return child;
>> +
>> +close_child:
>> +	pr_debug("closing child socket");
>> +	tcp_send_active_reset(child, GFP_ATOMIC);
>> +	inet_csk_prepare_forced_close(child);
>> +	tcp_done(child);
>> +	return NULL;
>>  }
>>
>>  static struct inet_connection_sock_af_ops subflow_specific;
>> @@ -186,6 +229,7 @@ int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
>>  	pr_debug("subflow=%p", subflow);
>>
>>  	*new_sock = sf;
>> +	sock_hold(sk);
>>  	subflow->conn = sk;
>>
>>  	return 0;
>> @@ -251,6 +295,9 @@ static void subflow_ulp_release(struct sock *sk)
>>  	if (!ctx)
>>  		return;
>>
>> +	if (ctx->conn)
>> +		sock_put(ctx->conn);
>> +
>>  	kfree_rcu(ctx, rcu);
>>  }
>>
>> @@ -276,6 +323,7 @@ static void subflow_ulp_clone(const struct request_sock *req,
>>  		new_ctx->fourth_ack = 1;
>>  		new_ctx->remote_key = subflow_req->remote_key;
>>  		new_ctx->local_key = subflow_req->local_key;
>> +		new_ctx->token = subflow_req->token;
>>  	} else {
>>  		tcp_sk(newsk)->is_mptcp = 0;
>>  	}
>> @@ -302,6 +350,8 @@ static int subflow_ops_init(struct request_sock_ops *subflow_ops)
>>  	if (!subflow_ops->slab)
>>  		return -ENOMEM;
>>
>> +	subflow_ops->destructor = subflow_req_destructor;
>> +
>>  	return 0;
>>  }
>>
>> @@ -318,6 +368,7 @@ void mptcp_subflow_init(void)
>>  	subflow_specific.conn_request = subflow_v4_conn_request;
>>  	subflow_specific.syn_recv_sock = subflow_syn_recv_sock;
>>  	subflow_specific.sk_rx_dst_set = subflow_finish_connect;
>> +	subflow_specific.rebuild_header = subflow_rebuild_header;
>>
>>  #if IS_ENABLED(CONFIG_MPTCP_IPV6)
>>  	subflow_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops;
>> @@ -327,6 +378,7 @@ void mptcp_subflow_init(void)
>>  	subflow_v6_specific.conn_request = subflow_v6_conn_request;
>>  	subflow_v6_specific.syn_recv_sock = subflow_syn_recv_sock;
>>  	subflow_v6_specific.sk_rx_dst_set = subflow_finish_connect;
>> +	subflow_v6_specific.rebuild_header = subflow_rebuild_header;
>>  #endif
>>
>>  	if (tcp_register_ulp(&subflow_ulp_ops) != 0)
>> diff --git a/net/mptcp/token.c b/net/mptcp/token.c
>> new file mode 100644
>> index 000000000000..84d887806090
>> --- /dev/null
>> +++ b/net/mptcp/token.c
>> @@ -0,0 +1,195 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Multipath TCP token management
>> + * Copyright (c) 2017 - 2019, Intel Corporation.
>> + *
>> + * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org,
>> + *       authored by:
>> + *
>> + *       Sébastien Barré <sebastien.barre@uclouvain.be>
>> + *       Christoph Paasch <christoph.paasch@uclouvain.be>
>> + *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
>> + *       Gregory Detal <gregory.detal@uclouvain.be>
>> + *       Fabien Duchêne <fabien.duchene@uclouvain.be>
>> + *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
>> + *       Lavkesh Lahngir <lavkesh51@gmail.com>
>> + *       Andreas Ripke <ripke@neclab.eu>
>> + *       Vlad Dogaru <vlad.dogaru@intel.com>
>> + *       Octavian Purdila <octavian.purdila@intel.com>
>> + *       John Ronan <jronan@tssg.org>
>> + *       Catalin Nicutar <catalin.nicutar@gmail.com>
>> + *       Brandon Heller <brandonh@stanford.edu>
>> + */
>> +
>> +#define pr_fmt(fmt) "MPTCP: " fmt
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/radix-tree.h>
>> +#include <linux/ip.h>
>> +#include <linux/tcp.h>
>> +#include <net/sock.h>
>> +#include <net/inet_common.h>
>> +#include <net/protocol.h>
>> +#include <net/mptcp.h>
>> +#include "protocol.h"
>> +
>> +static RADIX_TREE(token_tree, GFP_ATOMIC);
>> +static RADIX_TREE(token_req_tree, GFP_ATOMIC);
>> +static DEFINE_SPINLOCK(token_tree_lock);
>> +static int token_used __read_mostly;
>> +
>> +/**
>> + * mptcp_token_new_request - create new key/idsn/token for subflow_request
>> + * @req - the request socket
>> + *
>> + * This function is called when a new mptcp connection is coming in.
>> + *
>> + * It creates a unique token to identify the new mptcp connection,
>> + * a secret local key and the initial data sequence number (idsn).
>> + *
>> + * Returns 0 on success.
>> + */
>> +int mptcp_token_new_request(struct request_sock *req)
>> +{
>> +	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
>> +	int err;
>> +
>> +	while (1) {
>> +		u32 token;
>> +
>> +		mptcp_crypto_key_gen_sha(&subflow_req->local_key,
>> +					 &subflow_req->token,
>> +					 &subflow_req->idsn);
>> +		pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
>> +			 req, subflow_req->local_key, subflow_req->token,
>> +			 subflow_req->idsn);
>> +
>> +		token = subflow_req->token;
>> +		spin_lock_bh(&token_tree_lock);
>> +		if (!radix_tree_lookup(&token_req_tree, token) &&
>> +		    !radix_tree_lookup(&token_tree, token))
>> +			break;
>> +		spin_unlock_bh(&token_tree_lock);
>> +	}
>> +
>> +	err = radix_tree_insert(&token_req_tree,
>> +				subflow_req->token, &token_used);
>> +	spin_unlock_bh(&token_tree_lock);
>> +	return err;
>> +}
>> +
>> +/**
>> + * mptcp_token_new_connect - create new key/idsn/token for subflow
>> + * @sk - the socket that will initiate a connection
>> + *
>> + * This function is called when a new outgoing mptcp connection is
>> + * initiated.
>> + *
>> + * It creates a unique token to identify the new mptcp connection,
>> + * a secret local key and the initial data sequence number (idsn).
>> + *
>> + * On success, the mptcp connection can be found again using
>> + * the computed token at a later time, this is needed to process
>> + * join requests.
>> + *
>> + * returns 0 on success.
>> + */
>> +int mptcp_token_new_connect(struct sock *sk)
>> +{
>> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
>> +	struct sock *mptcp_sock = subflow->conn;
>> +	int err;
>> +
>> +	while (1) {
>> +		u32 token;
>> +
>> +		mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
>> +					 &subflow->idsn);
>> +
>> +		pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
>> +			 sk, subflow->local_key, subflow->token, subflow->idsn);
>> +
>> +		token = subflow->token;
>> +		spin_lock_bh(&token_tree_lock);
>> +		if (!radix_tree_lookup(&token_req_tree, token) &&
>> +		    !radix_tree_lookup(&token_tree, token))
>> +			break;
>> +		spin_unlock_bh(&token_tree_lock);
>> +	}
>> +	err = radix_tree_insert(&token_tree, subflow->token, mptcp_sock);
>> +	spin_unlock_bh(&token_tree_lock);
>> +
>> +	return err;
>> +}
>> +
>> +/**
>> + * mptcp_token_new_accept - insert token for later processing
>> + * @token: the token to insert to the tree
>> + *
>> + * Called when a SYN packet creates a new logical connection, i.e.
>> + * is not a join request.
>> + *
>> + * We don't have an mptcp socket yet at that point.
>> + * This is paired with mptcp_token_update_accept, called on accept().
>> + */
>> +int mptcp_token_new_accept(u32 token)
>> +{
>> +	int err;
>> +
>> +	spin_lock_bh(&token_tree_lock);
>> +	err = radix_tree_insert(&token_tree, token, &token_used);
>> +	spin_unlock_bh(&token_tree_lock);
>> +
>> +	return err;
>> +}
>> +
>> +/**
>> + * mptcp_token_update_accept - update token to map to mptcp socket
>> + * @conn: the new struct mptcp_sock
>> + * @sk: the initial subflow for this mptcp socket
>> + *
>> + * Called when the first mptcp socket is created on accept to
>> + * refresh the dummy mapping (done to reserve the token) with
>> + * the mptcp_socket structure that wasn't allocated before.
>> + */
>> +void mptcp_token_update_accept(struct sock *sk, struct sock *conn)
>> +{
>> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
>> +	void __rcu **slot;
>> +
>> +	spin_lock_bh(&token_tree_lock);
>> +	slot = radix_tree_lookup_slot(&token_tree, subflow->token);
>> +	WARN_ON_ONCE(!slot);
>> +	if (slot) {
>> +		WARN_ON_ONCE(rcu_access_pointer(*slot) != &token_used);
>> +		radix_tree_replace_slot(&token_tree, slot, conn);
>> +	}
>> +	spin_unlock_bh(&token_tree_lock);
>> +}
>> +
>> +/**
>> + * mptcp_token_destroy_request - remove mptcp connection/token
>> + * @token - token of mptcp connection to remove
>> + *
>> + * Remove not-yet-fully-established incoming connection identified
>> + * by @token.
>> + */
>> +void mptcp_token_destroy_request(u32 token)
>> +{
>> +	spin_lock_bh(&token_tree_lock);
>> +	radix_tree_delete(&token_req_tree, token);
>> +	spin_unlock_bh(&token_tree_lock);
>> +}
>> +
>> +/**
>> + * mptcp_token_destroy - remove mptcp connection/token
>> + * @token - token of mptcp connection to remove
>> + *
>> + * Remove the connection identified by @token.
>> + */
>> +void mptcp_token_destroy(u32 token)
>> +{
>> +	spin_lock_bh(&token_tree_lock);
>> +	radix_tree_delete(&token_tree, token);
>> +	spin_unlock_bh(&token_tree_lock);
>> +}
>
>

--
Mat Martineau
Intel
Matthieu Baerts Dec. 14, 2019, 8:11 a.m. UTC | #3
Hi Peter,

On 14/12/2019 06:14, Peter Krystad wrote:
> On Fri, 2019-12-13 at 21:50 +0100, Matthieu Baerts wrote:
>> From: Peter Krystad <peter.krystad@linux.intel.com>
>>
>> Generate the local keys, IDSN, and token when creating a new socket.
>> Introduce the token tree to track all tokens in use using a radix tree
>> with the MPTCP token itself as the index.
> 
> Add here:
> 
> Override the rebuild_header callback in inet_connection_sock_af_ops for
> creating the local key on a new outgoing connection.
> 
> Override the init_req callback of tcp_request_sock_ops for creating the local
> key on a new incoming connection.

A small detail but I see that init_req callback was already overriden 
before. Here, only the destructor callback is overriden (more extended).

Cheers,
Matt
diff mbox series

Patch

diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile
index e1ee5aade8b0..178ae81d8b66 100644
--- a/net/mptcp/Makefile
+++ b/net/mptcp/Makefile
@@ -1,4 +1,4 @@ 
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_MPTCP) += mptcp.o
 
-mptcp-y := protocol.o subflow.o options.o
+mptcp-y := protocol.o subflow.o options.o token.o crypto.o
diff --git a/net/mptcp/crypto.c b/net/mptcp/crypto.c
new file mode 100644
index 000000000000..bbd6d01af211
--- /dev/null
+++ b/net/mptcp/crypto.c
@@ -0,0 +1,122 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Multipath TCP cryptographic functions
+ * Copyright (c) 2017 - 2019, Intel Corporation.
+ *
+ * Note: This code is based on mptcp_ctrl.c, mptcp_ipv4.c, and
+ *       mptcp_ipv6 from multipath-tcp.org, authored by:
+ *
+ *       Sébastien Barré <sebastien.barre@uclouvain.be>
+ *       Christoph Paasch <christoph.paasch@uclouvain.be>
+ *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
+ *       Gregory Detal <gregory.detal@uclouvain.be>
+ *       Fabien Duchêne <fabien.duchene@uclouvain.be>
+ *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
+ *       Lavkesh Lahngir <lavkesh51@gmail.com>
+ *       Andreas Ripke <ripke@neclab.eu>
+ *       Vlad Dogaru <vlad.dogaru@intel.com>
+ *       Octavian Purdila <octavian.purdila@intel.com>
+ *       John Ronan <jronan@tssg.org>
+ *       Catalin Nicutar <catalin.nicutar@gmail.com>
+ *       Brandon Heller <brandonh@stanford.edu>
+ */
+
+#include <linux/kernel.h>
+#include <linux/cryptohash.h>
+#include <asm/unaligned.h>
+
+#include "protocol.h"
+
+struct sha1_state {
+	u32 workspace[SHA_WORKSPACE_WORDS];
+	u32 digest[SHA_DIGEST_WORDS];
+	unsigned int count;
+};
+
+static void sha1_init(struct sha1_state *state)
+{
+	sha_init(state->digest);
+	state->count = 0;
+}
+
+static void sha1_update(struct sha1_state *state, u8 *input)
+{
+	sha_transform(state->digest, input, state->workspace);
+	state->count += SHA_MESSAGE_BYTES;
+}
+
+static void sha1_pad_final(struct sha1_state *state, u8 *input,
+			   unsigned int length, __be32 *mptcp_hashed_key)
+{
+	int i;
+
+	input[length] = 0x80;
+	memset(&input[length + 1], 0, SHA_MESSAGE_BYTES - length - 9);
+	put_unaligned_be64((length + state->count) << 3,
+			   &input[SHA_MESSAGE_BYTES - 8]);
+
+	sha_transform(state->digest, input, state->workspace);
+	for (i = 0; i < SHA_DIGEST_WORDS; ++i)
+		put_unaligned_be32(state->digest[i], &mptcp_hashed_key[i]);
+
+	memzero_explicit(state->workspace, SHA_WORKSPACE_WORDS << 2);
+}
+
+void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
+{
+	__be32 mptcp_hashed_key[SHA_DIGEST_WORDS];
+	u8 input[SHA_MESSAGE_BYTES];
+	struct sha1_state state;
+
+	sha1_init(&state);
+	put_unaligned_be64(key, input);
+	sha1_pad_final(&state, input, 8, mptcp_hashed_key);
+
+	if (token)
+		*token = be32_to_cpu(mptcp_hashed_key[0]);
+	if (idsn)
+		*idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[3]));
+}
+
+void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
+			   u32 *hash_out)
+{
+	u8 input[SHA_MESSAGE_BYTES * 2];
+	struct sha1_state state;
+	u8 key1be[8];
+	u8 key2be[8];
+	int i;
+
+	put_unaligned_be64(key1, key1be);
+	put_unaligned_be64(key2, key2be);
+
+	/* Generate key xored with ipad */
+	memset(input, 0x36, SHA_MESSAGE_BYTES);
+	for (i = 0; i < 8; i++)
+		input[i] ^= key1be[i];
+	for (i = 0; i < 8; i++)
+		input[i + 8] ^= key2be[i];
+
+	put_unaligned_be32(nonce1, &input[SHA_MESSAGE_BYTES]);
+	put_unaligned_be32(nonce2, &input[SHA_MESSAGE_BYTES + 4]);
+
+	sha1_init(&state);
+	sha1_update(&state, input);
+
+	/* emit sha256(K1 || msg) on the second input block, so we can
+	 * reuse 'input' for the last hashing
+	 */
+	sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], 8,
+		       (__force __be32 *)&input[SHA_MESSAGE_BYTES]);
+
+	/* Prepare second part of hmac */
+	memset(input, 0x5C, SHA_MESSAGE_BYTES);
+	for (i = 0; i < 8; i++)
+		input[i] ^= key1be[i];
+	for (i = 0; i < 8; i++)
+		input[i + 8] ^= key2be[i];
+
+	sha1_init(&state);
+	sha1_update(&state, input);
+	sha1_pad_final(&state, &input[SHA_MESSAGE_BYTES], SHA_DIGEST_WORDS << 2,
+		       (__be32 *)hash_out);
+}
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 147a3a9fdc0a..19b1250bb8cc 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -199,6 +199,7 @@  static void mptcp_close(struct sock *sk, long timeout)
 	struct mptcp_subflow_context *subflow, *tmp;
 	struct mptcp_sock *msk = mptcp_sk(sk);
 
+	mptcp_token_destroy(msk->token);
 	inet_sk_state_store(sk, TCP_CLOSE);
 
 	lock_sock(sk);
@@ -279,8 +280,10 @@  static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
 		msk = mptcp_sk(new_mptcp_sock);
 		msk->remote_key = subflow->remote_key;
 		msk->local_key = subflow->local_key;
+		msk->token = subflow->token;
 		msk->subflow = NULL;
 
+		mptcp_token_update_accept(newsk, new_mptcp_sock);
 		newsk = new_mptcp_sock;
 		mptcp_copy_inaddrs(newsk, ssk);
 		list_add(&subflow->node, &msk->conn_list);
@@ -299,6 +302,10 @@  static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
 	return newsk;
 }
 
+static void mptcp_destroy(struct sock *sk)
+{
+}
+
 static int mptcp_get_port(struct sock *sk, unsigned short snum)
 {
 	struct mptcp_sock *msk = mptcp_sk(sk);
@@ -331,6 +338,7 @@  void mptcp_finish_connect(struct sock *ssk)
 	 */
 	WRITE_ONCE(msk->remote_key, subflow->remote_key);
 	WRITE_ONCE(msk->local_key, subflow->local_key);
+	WRITE_ONCE(msk->token, subflow->token);
 }
 
 static void mptcp_sock_graft(struct sock *sk, struct socket *parent)
@@ -349,6 +357,7 @@  static struct proto mptcp_prot = {
 	.close		= mptcp_close,
 	.accept		= mptcp_accept,
 	.shutdown	= tcp_shutdown,
+	.destroy	= mptcp_destroy,
 	.sendmsg	= mptcp_sendmsg,
 	.recvmsg	= mptcp_recvmsg,
 	.hash		= inet_hash,
@@ -568,6 +577,12 @@  void __init mptcp_init(void)
 static struct proto_ops mptcp_v6_stream_ops;
 static struct proto mptcp_v6_prot;
 
+static void mptcp_v6_destroy(struct sock *sk)
+{
+	mptcp_destroy(sk);
+	inet6_destroy_sock(sk);
+}
+
 static struct inet_protosw mptcp_v6_protosw = {
 	.type		= SOCK_STREAM,
 	.protocol	= IPPROTO_MPTCP,
@@ -583,6 +598,7 @@  int mptcpv6_init(void)
 	mptcp_v6_prot = mptcp_prot;
 	strcpy(mptcp_v6_prot.name, "MPTCPv6");
 	mptcp_v6_prot.slab = NULL;
+	mptcp_v6_prot.destroy = mptcp_v6_destroy;
 	mptcp_v6_prot.obj_size = sizeof(struct mptcp_sock) +
 				 sizeof(struct ipv6_pinfo);
 
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index bd66e7415515..4cf9620d19ec 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -7,6 +7,10 @@ 
 #ifndef __MPTCP_PROTOCOL_H
 #define __MPTCP_PROTOCOL_H
 
+#include <linux/random.h>
+#include <linux/tcp.h>
+#include <net/inet_connection_sock.h>
+
 #define MPTCP_SUPPORTED_VERSION	0
 
 /* MPTCP option bits */
@@ -42,6 +46,7 @@  struct mptcp_sock {
 	struct inet_connection_sock sk;
 	u64		local_key;
 	u64		remote_key;
+	u32		token;
 	struct list_head conn_list;
 	struct socket	*subflow; /* outgoing connect/listener/!mp_capable */
 };
@@ -61,6 +66,8 @@  struct mptcp_subflow_request_sock {
 		backup : 1;
 	u64	local_key;
 	u64	remote_key;
+	u64	idsn;
+	u32	token;
 };
 
 static inline struct mptcp_subflow_request_sock *
@@ -74,6 +81,8 @@  struct mptcp_subflow_context {
 	struct	list_head node;/* conn_list of subflows */
 	u64	local_key;
 	u64	remote_key;
+	u64	idsn;
+	u32	token;
 	u32	request_mptcp : 1,  /* send MP_CAPABLE */
 		mp_capable : 1,	    /* remote is MPTCP capable */
 		fourth_ack : 1,	    /* send initial DSS */
@@ -112,4 +121,27 @@  void mptcp_get_options(const struct sk_buff *skb,
 
 void mptcp_finish_connect(struct sock *sk);
 
+int mptcp_token_new_request(struct request_sock *req);
+void mptcp_token_destroy_request(u32 token);
+int mptcp_token_new_connect(struct sock *sk);
+int mptcp_token_new_accept(u32 token);
+void mptcp_token_update_accept(struct sock *sk, struct sock *conn);
+void mptcp_token_destroy(u32 token);
+
+void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn);
+static inline void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
+{
+	/* we might consider a faster version that computes the key as a
+	 * hash of some information available in the MPTCP socket. Use
+	 * random data at the moment, as it's probably the safest option
+	 * in case multiple sockets are opened in different namespaces at
+	 * the same time.
+	 */
+	get_random_bytes(key, sizeof(u64));
+	mptcp_crypto_key_sha(*key, token, idsn);
+}
+
+void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
+			   u32 *hash_out);
+
 #endif /* __MPTCP_PROTOCOL_H */
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index b9aca17b0b91..35134342fab0 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -4,6 +4,8 @@ 
  * Copyright (c) 2017 - 2019, Intel Corporation.
  */
 
+#define pr_fmt(fmt) "MPTCP: " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -18,6 +20,33 @@ 
 #include <net/mptcp.h>
 #include "protocol.h"
 
+static int subflow_rebuild_header(struct sock *sk)
+{
+	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+	int err = 0;
+
+	if (subflow->request_mptcp && !subflow->token) {
+		pr_debug("subflow=%p", sk);
+		err = mptcp_token_new_connect(sk);
+	}
+
+	if (err)
+		return err;
+
+	return subflow->icsk_af_ops->rebuild_header(sk);
+}
+
+static void subflow_req_destructor(struct request_sock *req)
+{
+	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+
+	pr_debug("subflow_req=%p", subflow_req);
+
+	if (subflow_req->mp_capable)
+		mptcp_token_destroy_request(subflow_req->token);
+	tcp_request_sock_ops.destructor(req);
+}
+
 static void subflow_init_req(struct request_sock *req,
 			     const struct sock *sk_listener,
 			     struct sk_buff *skb)
@@ -42,7 +71,12 @@  static void subflow_init_req(struct request_sock *req,
 #endif
 
 	if (rx_opt.mptcp.mp_capable && listener->request_mptcp) {
-		subflow_req->mp_capable = 1;
+		int err;
+
+		err = mptcp_token_new_request(req);
+		if (err == 0)
+			subflow_req->mp_capable = 1;
+
 		subflow_req->remote_key = rx_opt.mptcp.sndr_key;
 	}
 }
@@ -124,16 +158,25 @@  static struct sock *subflow_syn_recv_sock(const struct sock *sk,
 						     req_unhash, own_req);
 
 	if (child && *own_req) {
-		if (!mptcp_subflow_ctx(child)) {
-			pr_debug("Closing child socket");
-			inet_sk_set_state(child, TCP_CLOSE);
-			sock_set_flag(child, SOCK_DEAD);
-			inet_csk_destroy_sock(child);
-			child = NULL;
+		struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(child);
+
+		if (!ctx)
+			goto close_child;
+
+		if (ctx->mp_capable) {
+			if (mptcp_token_new_accept(ctx->token))
+				goto close_child;
 		}
 	}
 
 	return child;
+
+close_child:
+	pr_debug("closing child socket");
+	tcp_send_active_reset(child, GFP_ATOMIC);
+	inet_csk_prepare_forced_close(child);
+	tcp_done(child);
+	return NULL;
 }
 
 static struct inet_connection_sock_af_ops subflow_specific;
@@ -186,6 +229,7 @@  int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
 	pr_debug("subflow=%p", subflow);
 
 	*new_sock = sf;
+	sock_hold(sk);
 	subflow->conn = sk;
 
 	return 0;
@@ -251,6 +295,9 @@  static void subflow_ulp_release(struct sock *sk)
 	if (!ctx)
 		return;
 
+	if (ctx->conn)
+		sock_put(ctx->conn);
+
 	kfree_rcu(ctx, rcu);
 }
 
@@ -276,6 +323,7 @@  static void subflow_ulp_clone(const struct request_sock *req,
 		new_ctx->fourth_ack = 1;
 		new_ctx->remote_key = subflow_req->remote_key;
 		new_ctx->local_key = subflow_req->local_key;
+		new_ctx->token = subflow_req->token;
 	} else {
 		tcp_sk(newsk)->is_mptcp = 0;
 	}
@@ -302,6 +350,8 @@  static int subflow_ops_init(struct request_sock_ops *subflow_ops)
 	if (!subflow_ops->slab)
 		return -ENOMEM;
 
+	subflow_ops->destructor = subflow_req_destructor;
+
 	return 0;
 }
 
@@ -318,6 +368,7 @@  void mptcp_subflow_init(void)
 	subflow_specific.conn_request = subflow_v4_conn_request;
 	subflow_specific.syn_recv_sock = subflow_syn_recv_sock;
 	subflow_specific.sk_rx_dst_set = subflow_finish_connect;
+	subflow_specific.rebuild_header = subflow_rebuild_header;
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 	subflow_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops;
@@ -327,6 +378,7 @@  void mptcp_subflow_init(void)
 	subflow_v6_specific.conn_request = subflow_v6_conn_request;
 	subflow_v6_specific.syn_recv_sock = subflow_syn_recv_sock;
 	subflow_v6_specific.sk_rx_dst_set = subflow_finish_connect;
+	subflow_v6_specific.rebuild_header = subflow_rebuild_header;
 #endif
 
 	if (tcp_register_ulp(&subflow_ulp_ops) != 0)
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
new file mode 100644
index 000000000000..84d887806090
--- /dev/null
+++ b/net/mptcp/token.c
@@ -0,0 +1,195 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Multipath TCP token management
+ * Copyright (c) 2017 - 2019, Intel Corporation.
+ *
+ * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org,
+ *       authored by:
+ *
+ *       Sébastien Barré <sebastien.barre@uclouvain.be>
+ *       Christoph Paasch <christoph.paasch@uclouvain.be>
+ *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
+ *       Gregory Detal <gregory.detal@uclouvain.be>
+ *       Fabien Duchêne <fabien.duchene@uclouvain.be>
+ *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
+ *       Lavkesh Lahngir <lavkesh51@gmail.com>
+ *       Andreas Ripke <ripke@neclab.eu>
+ *       Vlad Dogaru <vlad.dogaru@intel.com>
+ *       Octavian Purdila <octavian.purdila@intel.com>
+ *       John Ronan <jronan@tssg.org>
+ *       Catalin Nicutar <catalin.nicutar@gmail.com>
+ *       Brandon Heller <brandonh@stanford.edu>
+ */
+
+#define pr_fmt(fmt) "MPTCP: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/radix-tree.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/sock.h>
+#include <net/inet_common.h>
+#include <net/protocol.h>
+#include <net/mptcp.h>
+#include "protocol.h"
+
+static RADIX_TREE(token_tree, GFP_ATOMIC);
+static RADIX_TREE(token_req_tree, GFP_ATOMIC);
+static DEFINE_SPINLOCK(token_tree_lock);
+static int token_used __read_mostly;
+
+/**
+ * mptcp_token_new_request - create new key/idsn/token for subflow_request
+ * @req - the request socket
+ *
+ * This function is called when a new mptcp connection is coming in.
+ *
+ * It creates a unique token to identify the new mptcp connection,
+ * a secret local key and the initial data sequence number (idsn).
+ *
+ * Returns 0 on success.
+ */
+int mptcp_token_new_request(struct request_sock *req)
+{
+	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+	int err;
+
+	while (1) {
+		u32 token;
+
+		mptcp_crypto_key_gen_sha(&subflow_req->local_key,
+					 &subflow_req->token,
+					 &subflow_req->idsn);
+		pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
+			 req, subflow_req->local_key, subflow_req->token,
+			 subflow_req->idsn);
+
+		token = subflow_req->token;
+		spin_lock_bh(&token_tree_lock);
+		if (!radix_tree_lookup(&token_req_tree, token) &&
+		    !radix_tree_lookup(&token_tree, token))
+			break;
+		spin_unlock_bh(&token_tree_lock);
+	}
+
+	err = radix_tree_insert(&token_req_tree,
+				subflow_req->token, &token_used);
+	spin_unlock_bh(&token_tree_lock);
+	return err;
+}
+
+/**
+ * mptcp_token_new_connect - create new key/idsn/token for subflow
+ * @sk - the socket that will initiate a connection
+ *
+ * This function is called when a new outgoing mptcp connection is
+ * initiated.
+ *
+ * It creates a unique token to identify the new mptcp connection,
+ * a secret local key and the initial data sequence number (idsn).
+ *
+ * On success, the mptcp connection can be found again using
+ * the computed token at a later time, this is needed to process
+ * join requests.
+ *
+ * returns 0 on success.
+ */
+int mptcp_token_new_connect(struct sock *sk)
+{
+	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+	struct sock *mptcp_sock = subflow->conn;
+	int err;
+
+	while (1) {
+		u32 token;
+
+		mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
+					 &subflow->idsn);
+
+		pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
+			 sk, subflow->local_key, subflow->token, subflow->idsn);
+
+		token = subflow->token;
+		spin_lock_bh(&token_tree_lock);
+		if (!radix_tree_lookup(&token_req_tree, token) &&
+		    !radix_tree_lookup(&token_tree, token))
+			break;
+		spin_unlock_bh(&token_tree_lock);
+	}
+	err = radix_tree_insert(&token_tree, subflow->token, mptcp_sock);
+	spin_unlock_bh(&token_tree_lock);
+
+	return err;
+}
+
+/**
+ * mptcp_token_new_accept - insert token for later processing
+ * @token: the token to insert to the tree
+ *
+ * Called when a SYN packet creates a new logical connection, i.e.
+ * is not a join request.
+ *
+ * We don't have an mptcp socket yet at that point.
+ * This is paired with mptcp_token_update_accept, called on accept().
+ */
+int mptcp_token_new_accept(u32 token)
+{
+	int err;
+
+	spin_lock_bh(&token_tree_lock);
+	err = radix_tree_insert(&token_tree, token, &token_used);
+	spin_unlock_bh(&token_tree_lock);
+
+	return err;
+}
+
+/**
+ * mptcp_token_update_accept - update token to map to mptcp socket
+ * @conn: the new struct mptcp_sock
+ * @sk: the initial subflow for this mptcp socket
+ *
+ * Called when the first mptcp socket is created on accept to
+ * refresh the dummy mapping (done to reserve the token) with
+ * the mptcp_socket structure that wasn't allocated before.
+ */
+void mptcp_token_update_accept(struct sock *sk, struct sock *conn)
+{
+	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+	void __rcu **slot;
+
+	spin_lock_bh(&token_tree_lock);
+	slot = radix_tree_lookup_slot(&token_tree, subflow->token);
+	WARN_ON_ONCE(!slot);
+	if (slot) {
+		WARN_ON_ONCE(rcu_access_pointer(*slot) != &token_used);
+		radix_tree_replace_slot(&token_tree, slot, conn);
+	}
+	spin_unlock_bh(&token_tree_lock);
+}
+
+/**
+ * mptcp_token_destroy_request - remove mptcp connection/token
+ * @token - token of mptcp connection to remove
+ *
+ * Remove not-yet-fully-established incoming connection identified
+ * by @token.
+ */
+void mptcp_token_destroy_request(u32 token)
+{
+	spin_lock_bh(&token_tree_lock);
+	radix_tree_delete(&token_req_tree, token);
+	spin_unlock_bh(&token_tree_lock);
+}
+
+/**
+ * mptcp_token_destroy - remove mptcp connection/token
+ * @token - token of mptcp connection to remove
+ *
+ * Remove the connection identified by @token.
+ */
+void mptcp_token_destroy(u32 token)
+{
+	spin_lock_bh(&token_tree_lock);
+	radix_tree_delete(&token_tree, token);
+	spin_unlock_bh(&token_tree_lock);
+}