2020-01-22 08:56:17 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/* Multipath TCP
|
|
|
|
*
|
|
|
|
* Copyright (c) 2017 - 2019, Intel Corporation.
|
|
|
|
*/
|
|
|
|
|
2020-01-22 08:56:20 +08:00
|
|
|
#define pr_fmt(fmt) "MPTCP: " fmt
|
|
|
|
|
2020-01-22 08:56:17 +08:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/netdevice.h>
|
2020-03-28 05:48:39 +08:00
|
|
|
#include <crypto/algapi.h>
|
2020-05-22 10:10:49 +08:00
|
|
|
#include <crypto/sha.h>
|
2020-01-22 08:56:17 +08:00
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/inet_common.h>
|
|
|
|
#include <net/inet_hashtables.h>
|
|
|
|
#include <net/protocol.h>
|
|
|
|
#include <net/tcp.h>
|
2020-01-22 08:56:18 +08:00
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
#include <net/ip6_route.h>
|
|
|
|
#endif
|
2020-01-22 08:56:17 +08:00
|
|
|
#include <net/mptcp.h>
|
|
|
|
#include "protocol.h"
|
2020-03-28 05:48:50 +08:00
|
|
|
#include "mib.h"
|
|
|
|
|
|
|
|
static void SUBFLOW_REQ_INC_STATS(struct request_sock *req,
|
|
|
|
enum linux_mptcp_mib_field field)
|
|
|
|
{
|
|
|
|
MPTCP_INC_STATS(sock_net(req_to_sk(req)), field);
|
|
|
|
}
|
2020-01-22 08:56:17 +08:00
|
|
|
|
2020-01-22 08:56:20 +08:00
|
|
|
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);
|
|
|
|
|
2020-06-17 18:08:56 +08:00
|
|
|
if (subflow_req->msk)
|
|
|
|
sock_put((struct sock *)subflow_req->msk);
|
|
|
|
|
2020-06-27 01:30:00 +08:00
|
|
|
mptcp_token_destroy_request(req);
|
2020-01-22 08:56:20 +08:00
|
|
|
tcp_request_sock_ops.destructor(req);
|
|
|
|
}
|
|
|
|
|
2020-03-28 05:48:39 +08:00
|
|
|
static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
|
|
|
|
void *hmac)
|
|
|
|
{
|
|
|
|
u8 msg[8];
|
|
|
|
|
|
|
|
put_unaligned_be32(nonce1, &msg[0]);
|
|
|
|
put_unaligned_be32(nonce2, &msg[4]);
|
|
|
|
|
|
|
|
mptcp_crypto_hmac_sha(key1, key2, msg, 8, hmac);
|
|
|
|
}
|
|
|
|
|
2020-07-23 19:02:36 +08:00
|
|
|
static bool mptcp_can_accept_new_subflow(const struct mptcp_sock *msk)
|
|
|
|
{
|
|
|
|
return mptcp_is_fully_established((void *)msk) &&
|
|
|
|
READ_ONCE(msk->pm.accept_subflow);
|
|
|
|
}
|
|
|
|
|
2020-03-28 05:48:39 +08:00
|
|
|
/* validate received token and create truncated hmac and nonce for SYN-ACK */
|
2020-06-17 18:08:56 +08:00
|
|
|
static struct mptcp_sock *subflow_token_join_request(struct request_sock *req,
|
|
|
|
const struct sk_buff *skb)
|
2020-03-28 05:48:39 +08:00
|
|
|
{
|
|
|
|
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
2020-05-22 10:10:49 +08:00
|
|
|
u8 hmac[SHA256_DIGEST_SIZE];
|
2020-03-28 05:48:39 +08:00
|
|
|
struct mptcp_sock *msk;
|
|
|
|
int local_id;
|
|
|
|
|
|
|
|
msk = mptcp_token_get_sock(subflow_req->token);
|
|
|
|
if (!msk) {
|
2020-03-28 05:48:50 +08:00
|
|
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINNOTOKEN);
|
2020-06-17 18:08:56 +08:00
|
|
|
return NULL;
|
2020-03-28 05:48:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
local_id = mptcp_pm_get_local_id(msk, (struct sock_common *)req);
|
|
|
|
if (local_id < 0) {
|
|
|
|
sock_put((struct sock *)msk);
|
2020-06-17 18:08:56 +08:00
|
|
|
return NULL;
|
2020-03-28 05:48:39 +08:00
|
|
|
}
|
|
|
|
subflow_req->local_id = local_id;
|
|
|
|
|
|
|
|
get_random_bytes(&subflow_req->local_nonce, sizeof(u32));
|
|
|
|
|
|
|
|
subflow_generate_hmac(msk->local_key, msk->remote_key,
|
|
|
|
subflow_req->local_nonce,
|
|
|
|
subflow_req->remote_nonce, hmac);
|
|
|
|
|
|
|
|
subflow_req->thmac = get_unaligned_be64(hmac);
|
2020-06-17 18:08:56 +08:00
|
|
|
return msk;
|
2020-03-28 05:48:39 +08:00
|
|
|
}
|
|
|
|
|
2020-07-31 03:25:52 +08:00
|
|
|
static int __subflow_init_req(struct request_sock *req, const struct sock *sk_listener)
|
2020-01-22 08:56:18 +08:00
|
|
|
{
|
|
|
|
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
|
|
|
|
|
|
|
subflow_req->mp_capable = 0;
|
2020-03-28 05:48:39 +08:00
|
|
|
subflow_req->mp_join = 0;
|
2020-06-17 18:08:56 +08:00
|
|
|
subflow_req->msk = NULL;
|
2020-06-27 01:30:00 +08:00
|
|
|
mptcp_token_init_request(req);
|
2020-01-22 08:56:18 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
|
|
/* no MPTCP if MD5SIG is enabled on this socket or we may run out of
|
|
|
|
* TCP option space.
|
|
|
|
*/
|
|
|
|
if (rcu_access_pointer(tcp_sk(sk_listener)->md5sig_info))
|
2020-07-31 03:25:52 +08:00
|
|
|
return -EINVAL;
|
2020-01-22 08:56:18 +08:00
|
|
|
#endif
|
|
|
|
|
2020-07-31 03:25:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subflow_init_req(struct request_sock *req,
|
|
|
|
const struct sock *sk_listener,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
|
|
|
|
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
|
|
|
struct mptcp_options_received mp_opt;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
pr_debug("subflow_req=%p, listener=%p", subflow_req, listener);
|
|
|
|
|
|
|
|
ret = __subflow_init_req(req, sk_listener);
|
|
|
|
if (ret)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mptcp_get_options(skb, &mp_opt);
|
|
|
|
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
if (mp_opt.mp_capable) {
|
2020-03-28 05:48:50 +08:00
|
|
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPCAPABLEPASSIVE);
|
|
|
|
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
if (mp_opt.mp_join)
|
2020-03-28 05:48:50 +08:00
|
|
|
return;
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
} else if (mp_opt.mp_join) {
|
2020-03-28 05:48:50 +08:00
|
|
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX);
|
|
|
|
}
|
2020-03-28 05:48:39 +08:00
|
|
|
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
if (mp_opt.mp_capable && listener->request_mptcp) {
|
2020-07-31 03:25:51 +08:00
|
|
|
int err, retries = 4;
|
|
|
|
|
2020-07-31 03:25:54 +08:00
|
|
|
subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
|
2020-07-31 03:25:51 +08:00
|
|
|
again:
|
|
|
|
do {
|
|
|
|
get_random_bytes(&subflow_req->local_key, sizeof(subflow_req->local_key));
|
|
|
|
} while (subflow_req->local_key == 0);
|
2020-01-22 08:56:20 +08:00
|
|
|
|
2020-07-31 03:25:54 +08:00
|
|
|
if (unlikely(req->syncookie)) {
|
|
|
|
mptcp_crypto_key_sha(subflow_req->local_key,
|
|
|
|
&subflow_req->token,
|
|
|
|
&subflow_req->idsn);
|
|
|
|
if (mptcp_token_exists(subflow_req->token)) {
|
|
|
|
if (retries-- > 0)
|
|
|
|
goto again;
|
|
|
|
} else {
|
|
|
|
subflow_req->mp_capable = 1;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:20 +08:00
|
|
|
err = mptcp_token_new_request(req);
|
|
|
|
if (err == 0)
|
|
|
|
subflow_req->mp_capable = 1;
|
2020-07-31 03:25:51 +08:00
|
|
|
else if (retries-- > 0)
|
|
|
|
goto again;
|
2020-01-22 08:56:20 +08:00
|
|
|
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
} else if (mp_opt.mp_join && listener->request_mptcp) {
|
2020-03-28 05:48:40 +08:00
|
|
|
subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
|
2020-03-28 05:48:39 +08:00
|
|
|
subflow_req->mp_join = 1;
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
subflow_req->backup = mp_opt.backup;
|
|
|
|
subflow_req->remote_id = mp_opt.join_id;
|
|
|
|
subflow_req->token = mp_opt.token;
|
|
|
|
subflow_req->remote_nonce = mp_opt.nonce;
|
2020-06-17 18:08:56 +08:00
|
|
|
subflow_req->msk = subflow_token_join_request(req, skb);
|
2020-07-31 03:25:56 +08:00
|
|
|
|
|
|
|
if (unlikely(req->syncookie) && subflow_req->msk) {
|
|
|
|
if (mptcp_can_accept_new_subflow(subflow_req->msk))
|
|
|
|
subflow_init_req_cookie_join_save(subflow_req, skb);
|
|
|
|
}
|
|
|
|
|
2020-06-17 18:08:56 +08:00
|
|
|
pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token,
|
|
|
|
subflow_req->remote_nonce, subflow_req->msk);
|
2020-01-22 08:56:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 03:25:54 +08:00
|
|
|
int mptcp_subflow_init_cookie_req(struct request_sock *req,
|
|
|
|
const struct sock *sk_listener,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
|
|
|
|
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
|
|
|
struct mptcp_options_received mp_opt;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = __subflow_init_req(req, sk_listener);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
mptcp_get_options(skb, &mp_opt);
|
|
|
|
|
|
|
|
if (mp_opt.mp_capable && mp_opt.mp_join)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (mp_opt.mp_capable && listener->request_mptcp) {
|
|
|
|
if (mp_opt.sndr_key == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
subflow_req->local_key = mp_opt.rcvr_key;
|
|
|
|
err = mptcp_token_new_request(req);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
subflow_req->mp_capable = 1;
|
|
|
|
subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq - 1;
|
2020-07-31 03:25:56 +08:00
|
|
|
} else if (mp_opt.mp_join && listener->request_mptcp) {
|
|
|
|
if (!mptcp_token_join_cookie_init_state(subflow_req, skb))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (mptcp_can_accept_new_subflow(subflow_req->msk))
|
|
|
|
subflow_req->mp_join = 1;
|
|
|
|
|
|
|
|
subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq - 1;
|
2020-07-31 03:25:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(mptcp_subflow_init_cookie_req);
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
static void subflow_v4_init_req(struct request_sock *req,
|
|
|
|
const struct sock *sk_listener,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
tcp_rsk(req)->is_mptcp = 1;
|
|
|
|
|
|
|
|
tcp_request_sock_ipv4_ops.init_req(req, sk_listener, skb);
|
|
|
|
|
|
|
|
subflow_init_req(req, sk_listener, skb);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
static void subflow_v6_init_req(struct request_sock *req,
|
|
|
|
const struct sock *sk_listener,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
tcp_rsk(req)->is_mptcp = 1;
|
|
|
|
|
|
|
|
tcp_request_sock_ipv6_ops.init_req(req, sk_listener, skb);
|
|
|
|
|
|
|
|
subflow_init_req(req, sk_listener, skb);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-03-28 05:48:40 +08:00
|
|
|
/* validate received truncated hmac and create hmac for third ACK */
|
|
|
|
static bool subflow_thmac_valid(struct mptcp_subflow_context *subflow)
|
|
|
|
{
|
2020-05-22 10:10:49 +08:00
|
|
|
u8 hmac[SHA256_DIGEST_SIZE];
|
2020-03-28 05:48:40 +08:00
|
|
|
u64 thmac;
|
|
|
|
|
|
|
|
subflow_generate_hmac(subflow->remote_key, subflow->local_key,
|
|
|
|
subflow->remote_nonce, subflow->local_nonce,
|
|
|
|
hmac);
|
|
|
|
|
|
|
|
thmac = get_unaligned_be64(hmac);
|
|
|
|
pr_debug("subflow=%p, token=%u, thmac=%llu, subflow->thmac=%llu\n",
|
|
|
|
subflow, subflow->token,
|
|
|
|
(unsigned long long)thmac,
|
|
|
|
(unsigned long long)subflow->thmac);
|
|
|
|
|
|
|
|
return thmac == subflow->thmac;
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
struct mptcp_options_received mp_opt;
|
2020-03-20 05:45:37 +08:00
|
|
|
struct sock *parent = subflow->conn;
|
2020-01-22 08:56:18 +08:00
|
|
|
|
|
|
|
subflow->icsk_af_ops->sk_rx_dst_set(sk, skb);
|
|
|
|
|
2020-04-24 19:15:21 +08:00
|
|
|
if (inet_sk_state_load(parent) == TCP_SYN_SENT) {
|
2020-03-20 05:45:37 +08:00
|
|
|
inet_sk_state_store(parent, TCP_ESTABLISHED);
|
|
|
|
parent->sk_state_change(parent);
|
|
|
|
}
|
|
|
|
|
2020-04-30 21:01:51 +08:00
|
|
|
/* be sure no special action on any packet other than syn-ack */
|
|
|
|
if (subflow->conn_finished)
|
|
|
|
return;
|
|
|
|
|
2020-07-23 19:02:29 +08:00
|
|
|
subflow->rel_write_seq = 1;
|
2020-04-30 21:01:51 +08:00
|
|
|
subflow->conn_finished = 1;
|
2020-06-30 04:26:20 +08:00
|
|
|
subflow->ssn_offset = TCP_SKB_CB(skb)->seq;
|
|
|
|
pr_debug("subflow=%p synack seq=%x", subflow, subflow->ssn_offset);
|
2020-04-30 21:01:51 +08:00
|
|
|
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
mptcp_get_options(skb, &mp_opt);
|
2020-07-23 19:02:33 +08:00
|
|
|
if (subflow->request_mptcp) {
|
|
|
|
if (!mp_opt.mp_capable) {
|
|
|
|
MPTCP_INC_STATS(sock_net(sk),
|
|
|
|
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK);
|
|
|
|
mptcp_do_fallback(sk);
|
|
|
|
pr_fallback(mptcp_sk(subflow->conn));
|
|
|
|
goto fallback;
|
|
|
|
}
|
|
|
|
|
2020-04-30 21:01:51 +08:00
|
|
|
subflow->mp_capable = 1;
|
|
|
|
subflow->can_ack = 1;
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
subflow->remote_key = mp_opt.sndr_key;
|
2020-04-30 21:01:51 +08:00
|
|
|
pr_debug("subflow=%p, remote_key=%llu", subflow,
|
|
|
|
subflow->remote_key);
|
2020-07-23 19:02:33 +08:00
|
|
|
mptcp_finish_connect(sk);
|
|
|
|
} else if (subflow->request_join) {
|
|
|
|
u8 hmac[SHA256_DIGEST_SIZE];
|
|
|
|
|
|
|
|
if (!mp_opt.mp_join)
|
|
|
|
goto do_reset;
|
|
|
|
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
subflow->thmac = mp_opt.thmac;
|
|
|
|
subflow->remote_nonce = mp_opt.nonce;
|
2020-04-30 21:01:51 +08:00
|
|
|
pr_debug("subflow=%p, thmac=%llu, remote_nonce=%u", subflow,
|
|
|
|
subflow->thmac, subflow->remote_nonce);
|
|
|
|
|
2020-03-28 05:48:40 +08:00
|
|
|
if (!subflow_thmac_valid(subflow)) {
|
2020-03-28 05:48:50 +08:00
|
|
|
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKMAC);
|
2020-03-28 05:48:40 +08:00
|
|
|
goto do_reset;
|
|
|
|
}
|
|
|
|
|
|
|
|
subflow_generate_hmac(subflow->local_key, subflow->remote_key,
|
|
|
|
subflow->local_nonce,
|
|
|
|
subflow->remote_nonce,
|
2020-05-22 10:10:49 +08:00
|
|
|
hmac);
|
|
|
|
memcpy(subflow->hmac, hmac, MPTCPOPT_HMAC_LEN);
|
2020-03-28 05:48:40 +08:00
|
|
|
|
|
|
|
if (!mptcp_finish_join(sk))
|
|
|
|
goto do_reset;
|
|
|
|
|
2020-07-23 19:02:33 +08:00
|
|
|
subflow->mp_join = 1;
|
2020-03-28 05:48:50 +08:00
|
|
|
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX);
|
2020-07-23 19:02:33 +08:00
|
|
|
} else if (mptcp_check_fallback(sk)) {
|
|
|
|
fallback:
|
|
|
|
mptcp_rcv_space_init(mptcp_sk(parent), sk);
|
2020-01-22 08:56:18 +08:00
|
|
|
}
|
2020-07-23 19:02:33 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
do_reset:
|
|
|
|
tcp_send_active_reset(sk, GFP_ATOMIC);
|
|
|
|
tcp_done(sk);
|
2020-01-22 08:56:18 +08:00
|
|
|
}
|
|
|
|
|
2020-07-31 03:25:53 +08:00
|
|
|
struct request_sock_ops mptcp_subflow_request_sock_ops;
|
|
|
|
EXPORT_SYMBOL_GPL(mptcp_subflow_request_sock_ops);
|
2020-01-22 08:56:18 +08:00
|
|
|
static struct tcp_request_sock_ops subflow_request_sock_ipv4_ops;
|
|
|
|
|
|
|
|
static int subflow_v4_conn_request(struct sock *sk, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
|
|
|
|
|
|
|
pr_debug("subflow=%p", subflow);
|
|
|
|
|
|
|
|
/* Never answer to SYNs sent to broadcast or multicast */
|
|
|
|
if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
|
|
|
|
goto drop;
|
|
|
|
|
2020-07-31 03:25:53 +08:00
|
|
|
return tcp_conn_request(&mptcp_subflow_request_sock_ops,
|
2020-01-22 08:56:18 +08:00
|
|
|
&subflow_request_sock_ipv4_ops,
|
|
|
|
sk, skb);
|
|
|
|
drop:
|
|
|
|
tcp_listendrop(sk);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
static struct tcp_request_sock_ops subflow_request_sock_ipv6_ops;
|
|
|
|
static struct inet_connection_sock_af_ops subflow_v6_specific;
|
|
|
|
static struct inet_connection_sock_af_ops subflow_v6m_specific;
|
|
|
|
|
|
|
|
static int subflow_v6_conn_request(struct sock *sk, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
|
|
|
|
|
|
|
pr_debug("subflow=%p", subflow);
|
|
|
|
|
|
|
|
if (skb->protocol == htons(ETH_P_IP))
|
|
|
|
return subflow_v4_conn_request(sk, skb);
|
|
|
|
|
|
|
|
if (!ipv6_unicast_destination(skb))
|
|
|
|
goto drop;
|
|
|
|
|
2020-07-31 03:25:53 +08:00
|
|
|
return tcp_conn_request(&mptcp_subflow_request_sock_ops,
|
2020-01-22 08:56:18 +08:00
|
|
|
&subflow_request_sock_ipv6_ops, sk, skb);
|
|
|
|
|
|
|
|
drop:
|
|
|
|
tcp_listendrop(sk);
|
|
|
|
return 0; /* don't send reset */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-03-28 05:48:39 +08:00
|
|
|
/* validate hmac received in third ACK */
|
|
|
|
static bool subflow_hmac_valid(const struct request_sock *req,
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
const struct mptcp_options_received *mp_opt)
|
2020-03-28 05:48:39 +08:00
|
|
|
{
|
|
|
|
const struct mptcp_subflow_request_sock *subflow_req;
|
2020-05-22 10:10:49 +08:00
|
|
|
u8 hmac[SHA256_DIGEST_SIZE];
|
2020-03-28 05:48:39 +08:00
|
|
|
struct mptcp_sock *msk;
|
|
|
|
|
|
|
|
subflow_req = mptcp_subflow_rsk(req);
|
2020-06-17 18:08:56 +08:00
|
|
|
msk = subflow_req->msk;
|
2020-03-28 05:48:39 +08:00
|
|
|
if (!msk)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
subflow_generate_hmac(msk->remote_key, msk->local_key,
|
|
|
|
subflow_req->remote_nonce,
|
|
|
|
subflow_req->local_nonce, hmac);
|
|
|
|
|
2020-06-17 18:08:56 +08:00
|
|
|
return !crypto_memneq(hmac, mp_opt->hmac, MPTCPOPT_HMAC_LEN);
|
2020-03-28 05:48:39 +08:00
|
|
|
}
|
|
|
|
|
mptcp: fix splat when incoming connection is never accepted before exit/close
Following snippet (replicated from syzkaller reproducer) generates
warning: "IPv4: Attempt to release TCP socket in state 1".
int main(void) {
struct sockaddr_in sin1 = { .sin_family = 2, .sin_port = 0x4e20,
.sin_addr.s_addr = 0x010000e0, };
struct sockaddr_in sin2 = { .sin_family = 2,
.sin_addr.s_addr = 0x0100007f, };
struct sockaddr_in sin3 = { .sin_family = 2, .sin_port = 0x4e20,
.sin_addr.s_addr = 0x0100007f, };
int r0 = socket(0x2, 0x1, 0x106);
int r1 = socket(0x2, 0x1, 0x106);
bind(r1, (void *)&sin1, sizeof(sin1));
connect(r1, (void *)&sin2, sizeof(sin2));
listen(r1, 3);
return connect(r0, (void *)&sin3, 0x4d);
}
Reason is that the newly generated mptcp socket is closed via the ulp
release of the tcp listener socket when its accept backlog gets purged.
To fix this, delay setting the ESTABLISHED state until after userspace
calls accept and via mptcp specific destructor.
Fixes: 58b09919626bf ("mptcp: create msk early")
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/9
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-17 15:28:22 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-06-27 01:30:00 +08:00
|
|
|
mptcp_token_destroy(mptcp_sk(sk));
|
mptcp: fix splat when incoming connection is never accepted before exit/close
Following snippet (replicated from syzkaller reproducer) generates
warning: "IPv4: Attempt to release TCP socket in state 1".
int main(void) {
struct sockaddr_in sin1 = { .sin_family = 2, .sin_port = 0x4e20,
.sin_addr.s_addr = 0x010000e0, };
struct sockaddr_in sin2 = { .sin_family = 2,
.sin_addr.s_addr = 0x0100007f, };
struct sockaddr_in sin3 = { .sin_family = 2, .sin_port = 0x4e20,
.sin_addr.s_addr = 0x0100007f, };
int r0 = socket(0x2, 0x1, 0x106);
int r1 = socket(0x2, 0x1, 0x106);
bind(r1, (void *)&sin1, sizeof(sin1));
connect(r1, (void *)&sin2, sizeof(sin2));
listen(r1, 3);
return connect(r0, (void *)&sin3, 0x4d);
}
Reason is that the newly generated mptcp socket is closed via the ulp
release of the tcp listener socket when its accept backlog gets purged.
To fix this, delay setting the ESTABLISHED state until after userspace
calls accept and via mptcp specific destructor.
Fixes: 58b09919626bf ("mptcp: create msk early")
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/9
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-17 15:28:22 +08:00
|
|
|
inet_sock_destruct(sk);
|
|
|
|
}
|
|
|
|
|
2020-04-17 15:28:23 +08:00
|
|
|
static void mptcp_force_close(struct sock *sk)
|
|
|
|
{
|
|
|
|
inet_sk_state_store(sk, TCP_CLOSE);
|
|
|
|
sk_common_release(sk);
|
|
|
|
}
|
|
|
|
|
2020-04-20 22:25:05 +08:00
|
|
|
static void subflow_ulp_fallback(struct sock *sk,
|
|
|
|
struct mptcp_subflow_context *old_ctx)
|
|
|
|
{
|
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
|
|
|
|
mptcp_subflow_tcp_fallback(sk, old_ctx);
|
|
|
|
icsk->icsk_ulp_ops = NULL;
|
|
|
|
rcu_assign_pointer(icsk->icsk_ulp_data, NULL);
|
|
|
|
tcp_sk(sk)->is_mptcp = 0;
|
|
|
|
}
|
|
|
|
|
2020-05-29 23:49:18 +08:00
|
|
|
static void subflow_drop_ctx(struct sock *ssk)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(ssk);
|
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
subflow_ulp_fallback(ssk, ctx);
|
|
|
|
if (ctx->conn)
|
|
|
|
sock_put(ctx->conn);
|
|
|
|
|
|
|
|
kfree_rcu(ctx, rcu);
|
|
|
|
}
|
|
|
|
|
2020-07-23 19:02:32 +08:00
|
|
|
void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
|
|
|
|
struct mptcp_options_received *mp_opt)
|
|
|
|
{
|
|
|
|
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
|
|
|
|
|
|
|
|
subflow->remote_key = mp_opt->sndr_key;
|
|
|
|
subflow->fully_established = 1;
|
|
|
|
subflow->can_ack = 1;
|
|
|
|
WRITE_ONCE(msk->fully_established, true);
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
static struct sock *subflow_syn_recv_sock(const struct sock *sk,
|
|
|
|
struct sk_buff *skb,
|
|
|
|
struct request_sock *req,
|
|
|
|
struct dst_entry *dst,
|
|
|
|
struct request_sock *req_unhash,
|
|
|
|
bool *own_req)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk);
|
2020-01-22 08:56:31 +08:00
|
|
|
struct mptcp_subflow_request_sock *subflow_req;
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
struct mptcp_options_received mp_opt;
|
2020-06-17 18:08:57 +08:00
|
|
|
bool fallback, fallback_is_fatal;
|
2020-03-13 23:52:41 +08:00
|
|
|
struct sock *new_msk = NULL;
|
2020-01-22 08:56:18 +08:00
|
|
|
struct sock *child;
|
|
|
|
|
|
|
|
pr_debug("listener=%p, req=%p, conn=%p", listener, req, listener->conn);
|
|
|
|
|
2020-06-17 18:08:57 +08:00
|
|
|
/* After child creation we must look for 'mp_capable' even when options
|
|
|
|
* are not parsed
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
*/
|
|
|
|
mp_opt.mp_capable = 0;
|
2020-06-17 18:08:57 +08:00
|
|
|
|
|
|
|
/* hopefully temporary handling for MP_JOIN+syncookie */
|
|
|
|
subflow_req = mptcp_subflow_rsk(req);
|
2020-07-23 19:02:34 +08:00
|
|
|
fallback_is_fatal = tcp_rsk(req)->is_mptcp && subflow_req->mp_join;
|
2020-06-17 18:08:57 +08:00
|
|
|
fallback = !tcp_rsk(req)->is_mptcp;
|
|
|
|
if (fallback)
|
2020-01-29 22:54:46 +08:00
|
|
|
goto create_child;
|
|
|
|
|
2020-01-22 08:56:32 +08:00
|
|
|
/* if the sk is MP_CAPABLE, we try to fetch the client key */
|
2020-01-22 08:56:31 +08:00
|
|
|
if (subflow_req->mp_capable) {
|
2020-01-22 08:56:32 +08:00
|
|
|
if (TCP_SKB_CB(skb)->seq != subflow_req->ssn_offset + 1) {
|
|
|
|
/* here we can receive and accept an in-window,
|
|
|
|
* out-of-order pkt, which will not carry the MP_CAPABLE
|
|
|
|
* opt even on mptcp enabled paths
|
|
|
|
*/
|
2020-03-13 23:52:41 +08:00
|
|
|
goto create_msk;
|
2020-01-22 08:56:32 +08:00
|
|
|
}
|
|
|
|
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
mptcp_get_options(skb, &mp_opt);
|
|
|
|
if (!mp_opt.mp_capable) {
|
2020-04-20 22:25:05 +08:00
|
|
|
fallback = true;
|
2020-03-13 23:52:41 +08:00
|
|
|
goto create_child;
|
2020-01-22 08:56:32 +08:00
|
|
|
}
|
2020-03-13 23:52:41 +08:00
|
|
|
|
|
|
|
create_msk:
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
new_msk = mptcp_sk_clone(listener->conn, &mp_opt, req);
|
2020-03-13 23:52:41 +08:00
|
|
|
if (!new_msk)
|
2020-04-20 22:25:05 +08:00
|
|
|
fallback = true;
|
2020-03-28 05:48:39 +08:00
|
|
|
} else if (subflow_req->mp_join) {
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
mptcp_get_options(skb, &mp_opt);
|
|
|
|
if (!mp_opt.mp_join ||
|
2020-07-23 19:02:36 +08:00
|
|
|
!mptcp_can_accept_new_subflow(subflow_req->msk) ||
|
mptcp: move option parsing into mptcp_incoming_options()
The mptcp_options_received structure carries several per
packet flags (mp_capable, mp_join, etc.). Such fields must
be cleared on each packet, even on dropped ones or packet
not carrying any MPTCP options, but the current mptcp
code clears them only on TCP option reset.
On several races/corner cases we end-up with stray bits in
incoming options, leading to WARN_ON splats. e.g.:
[ 171.164906] Bad mapping: ssn=32714 map_seq=1 map_data_len=32713
[ 171.165006] WARNING: CPU: 1 PID: 5026 at net/mptcp/subflow.c:533 warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.167632] Modules linked in: ip6_vti ip_vti ip_gre ipip sit tunnel4 ip_tunnel geneve ip6_udp_tunnel udp_tunnel macsec macvtap tap ipvlan macvlan 8021q garp mrp xfrm_interface veth netdevsim nlmon dummy team bonding vcan bridge stp llc ip6_gre gre ip6_tunnel tunnel6 tun binfmt_misc intel_rapl_msr intel_rapl_common rfkill kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel joydev virtio_balloon pcspkr i2c_piix4 sunrpc ip_tables xfs libcrc32c crc32c_intel serio_raw virtio_console ata_generic virtio_blk virtio_net net_failover failover ata_piix libata
[ 171.199464] CPU: 1 PID: 5026 Comm: repro Not tainted 5.7.0-rc1.mptcp_f227fdf5d388+ #95
[ 171.200886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-2.fc30 04/01/2014
[ 171.202546] RIP: 0010:warn_bad_map (linux-mptcp/net/mptcp/subflow.c:533 linux-mptcp/net/mptcp/subflow.c:531)
[ 171.206537] Code: c1 ea 03 0f b6 14 02 48 89 f8 83 e0 07 83 c0 03 38 d0 7c 04 84 d2 75 1d 8b 55 3c 44 89 e6 48 c7 c7 20 51 13 95 e8 37 8b 22 fe <0f> 0b 48 83 c4 08 5b 5d 41 5c c3 89 4c 24 04 e8 db d6 94 fe 8b 4c
[ 171.220473] RSP: 0018:ffffc90000150560 EFLAGS: 00010282
[ 171.221639] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
[ 171.223108] RDX: 0000000000000000 RSI: 0000000000000008 RDI: fffff5200002a09e
[ 171.224388] RBP: ffff8880aa6e3c00 R08: 0000000000000001 R09: fffffbfff2ec9955
[ 171.225706] R10: ffffffff9764caa7 R11: fffffbfff2ec9954 R12: 0000000000007fca
[ 171.227211] R13: ffff8881066f4a7f R14: ffff8880aa6e3c00 R15: 0000000000000020
[ 171.228460] FS: 00007f8623719740(0000) GS:ffff88810be00000(0000) knlGS:0000000000000000
[ 171.230065] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 171.231303] CR2: 00007ffdab190a50 CR3: 00000001038ea006 CR4: 0000000000160ee0
[ 171.232586] Call Trace:
[ 171.233109] <IRQ>
[ 171.233531] get_mapping_status (linux-mptcp/net/mptcp/subflow.c:691)
[ 171.234371] mptcp_subflow_data_available (linux-mptcp/net/mptcp/subflow.c:736 linux-mptcp/net/mptcp/subflow.c:832)
[ 171.238181] subflow_state_change (linux-mptcp/net/mptcp/subflow.c:1085 (discriminator 1))
[ 171.239066] tcp_fin (linux-mptcp/net/ipv4/tcp_input.c:4217)
[ 171.240123] tcp_data_queue (linux-mptcp/./include/linux/compiler.h:199 linux-mptcp/net/ipv4/tcp_input.c:4822)
[ 171.245083] tcp_rcv_established (linux-mptcp/./include/linux/skbuff.h:1785 linux-mptcp/./include/net/tcp.h:1774 linux-mptcp/./include/net/tcp.h:1847 linux-mptcp/net/ipv4/tcp_input.c:5238 linux-mptcp/net/ipv4/tcp_input.c:5730)
[ 171.254089] tcp_v4_rcv (linux-mptcp/./include/linux/spinlock.h:393 linux-mptcp/net/ipv4/tcp_ipv4.c:2009)
[ 171.258969] ip_protocol_deliver_rcu (linux-mptcp/net/ipv4/ip_input.c:204 (discriminator 1))
[ 171.260214] ip_local_deliver_finish (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/ipv4/ip_input.c:232)
[ 171.261389] ip_local_deliver (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:252)
[ 171.265884] ip_rcv (linux-mptcp/./include/linux/netfilter.h:307 linux-mptcp/./include/linux/netfilter.h:301 linux-mptcp/net/ipv4/ip_input.c:539)
[ 171.273666] process_backlog (linux-mptcp/./include/linux/rcupdate.h:651 linux-mptcp/net/core/dev.c:6135)
[ 171.275328] net_rx_action (linux-mptcp/net/core/dev.c:6572 linux-mptcp/net/core/dev.c:6640)
[ 171.280472] __do_softirq (linux-mptcp/./arch/x86/include/asm/jump_label.h:25 linux-mptcp/./include/linux/jump_label.h:200 linux-mptcp/./include/trace/events/irq.h:142 linux-mptcp/kernel/softirq.c:293)
[ 171.281379] do_softirq_own_stack (linux-mptcp/arch/x86/entry/entry_64.S:1083)
[ 171.282358] </IRQ>
We could address the issue clearing explicitly the relevant fields
in several places - tcp_parse_option, tcp_fast_parse_options,
possibly others.
Instead we move the MPTCP option parsing into the already existing
mptcp ingress hook, so that we need to clear the fields in a single
place.
This allows us dropping an MPTCP hook from the TCP code and
removing the quite large mptcp_options_received from the tcp_sock
struct. On the flip side, the MPTCP sockets will traverse the
option space twice (in tcp_parse_option() and in
mptcp_incoming_options(). That looks acceptable: we already
do that for syn and 3rd ack packets, plain TCP socket will
benefit from it, and even MPTCP sockets will experience better
code locality, reducing the jumps between TCP and MPTCP code.
v1 -> v2:
- rebased on current '-net' tree
Fixes: 648ef4b88673 ("mptcp: Implement MPTCP receive path")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-30 21:01:52 +08:00
|
|
|
!subflow_hmac_valid(req, &mp_opt)) {
|
2020-03-28 05:48:50 +08:00
|
|
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC);
|
2020-06-17 18:08:57 +08:00
|
|
|
fallback = true;
|
2020-03-28 05:48:50 +08:00
|
|
|
}
|
2020-01-22 08:56:31 +08:00
|
|
|
}
|
2020-01-22 08:56:18 +08:00
|
|
|
|
2020-01-22 08:56:32 +08:00
|
|
|
create_child:
|
2020-01-22 08:56:18 +08:00
|
|
|
child = listener->icsk_af_ops->syn_recv_sock(sk, skb, req, dst,
|
|
|
|
req_unhash, own_req);
|
|
|
|
|
|
|
|
if (child && *own_req) {
|
2020-01-22 08:56:20 +08:00
|
|
|
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(child);
|
|
|
|
|
2020-05-16 01:22:15 +08:00
|
|
|
tcp_rsk(req)->drop_req = false;
|
|
|
|
|
2020-04-20 22:25:05 +08:00
|
|
|
/* we need to fallback on ctx allocation failure and on pre-reqs
|
|
|
|
* checking above. In the latter scenario we additionally need
|
|
|
|
* to reset the context to non MPTCP status.
|
2020-01-22 08:56:20 +08:00
|
|
|
*/
|
2020-04-20 22:25:05 +08:00
|
|
|
if (!ctx || fallback) {
|
2020-03-28 05:48:39 +08:00
|
|
|
if (fallback_is_fatal)
|
2020-05-16 01:22:17 +08:00
|
|
|
goto dispose_child;
|
2020-04-20 22:25:05 +08:00
|
|
|
|
2020-05-29 23:49:18 +08:00
|
|
|
subflow_drop_ctx(child);
|
2020-03-13 23:52:41 +08:00
|
|
|
goto out;
|
2020-03-28 05:48:39 +08:00
|
|
|
}
|
2020-01-22 08:56:20 +08:00
|
|
|
|
|
|
|
if (ctx->mp_capable) {
|
2020-07-23 19:02:32 +08:00
|
|
|
/* this can't race with mptcp_close(), as the msk is
|
|
|
|
* not yet exposted to user-space
|
|
|
|
*/
|
|
|
|
inet_sk_state_store((void *)new_msk, TCP_ESTABLISHED);
|
|
|
|
|
2020-03-13 23:52:41 +08:00
|
|
|
/* new mpc subflow takes ownership of the newly
|
|
|
|
* created mptcp socket
|
|
|
|
*/
|
mptcp: fix splat when incoming connection is never accepted before exit/close
Following snippet (replicated from syzkaller reproducer) generates
warning: "IPv4: Attempt to release TCP socket in state 1".
int main(void) {
struct sockaddr_in sin1 = { .sin_family = 2, .sin_port = 0x4e20,
.sin_addr.s_addr = 0x010000e0, };
struct sockaddr_in sin2 = { .sin_family = 2,
.sin_addr.s_addr = 0x0100007f, };
struct sockaddr_in sin3 = { .sin_family = 2, .sin_port = 0x4e20,
.sin_addr.s_addr = 0x0100007f, };
int r0 = socket(0x2, 0x1, 0x106);
int r1 = socket(0x2, 0x1, 0x106);
bind(r1, (void *)&sin1, sizeof(sin1));
connect(r1, (void *)&sin2, sizeof(sin2));
listen(r1, 3);
return connect(r0, (void *)&sin3, 0x4d);
}
Reason is that the newly generated mptcp socket is closed via the ulp
release of the tcp listener socket when its accept backlog gets purged.
To fix this, delay setting the ESTABLISHED state until after userspace
calls accept and via mptcp specific destructor.
Fixes: 58b09919626bf ("mptcp: create msk early")
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/9
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-04-17 15:28:22 +08:00
|
|
|
new_msk->sk_destruct = mptcp_sock_destruct;
|
2020-03-28 05:48:38 +08:00
|
|
|
mptcp_pm_new_connection(mptcp_sk(new_msk), 1);
|
2020-06-27 01:30:00 +08:00
|
|
|
mptcp_token_accept(subflow_req, mptcp_sk(new_msk));
|
2020-03-13 23:52:41 +08:00
|
|
|
ctx->conn = new_msk;
|
|
|
|
new_msk = NULL;
|
2020-04-20 22:25:06 +08:00
|
|
|
|
|
|
|
/* with OoO packets we can reach here without ingress
|
|
|
|
* mpc option
|
|
|
|
*/
|
2020-07-23 19:02:32 +08:00
|
|
|
if (mp_opt.mp_capable)
|
|
|
|
mptcp_subflow_fully_established(ctx, &mp_opt);
|
2020-03-28 05:48:39 +08:00
|
|
|
} else if (ctx->mp_join) {
|
|
|
|
struct mptcp_sock *owner;
|
|
|
|
|
2020-06-17 18:08:56 +08:00
|
|
|
owner = subflow_req->msk;
|
2020-03-28 05:48:39 +08:00
|
|
|
if (!owner)
|
2020-05-16 01:22:17 +08:00
|
|
|
goto dispose_child;
|
2020-03-28 05:48:39 +08:00
|
|
|
|
2020-06-17 18:08:56 +08:00
|
|
|
/* move the msk reference ownership to the subflow */
|
|
|
|
subflow_req->msk = NULL;
|
2020-03-28 05:48:39 +08:00
|
|
|
ctx->conn = (struct sock *)owner;
|
|
|
|
if (!mptcp_finish_join(child))
|
2020-05-16 01:22:17 +08:00
|
|
|
goto dispose_child;
|
2020-03-28 05:48:50 +08:00
|
|
|
|
|
|
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKRX);
|
2020-05-16 01:22:15 +08:00
|
|
|
tcp_rsk(req)->drop_req = true;
|
2020-01-22 08:56:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-13 23:52:41 +08:00
|
|
|
out:
|
|
|
|
/* dispose of the left over mptcp master, if any */
|
|
|
|
if (unlikely(new_msk))
|
2020-04-17 15:28:23 +08:00
|
|
|
mptcp_force_close(new_msk);
|
2020-04-20 22:25:05 +08:00
|
|
|
|
|
|
|
/* check for expected invariant - should never trigger, just help
|
|
|
|
* catching eariler subtle bugs
|
|
|
|
*/
|
2020-04-30 21:03:22 +08:00
|
|
|
WARN_ON_ONCE(child && *own_req && tcp_sk(child)->is_mptcp &&
|
2020-04-20 22:25:05 +08:00
|
|
|
(!mptcp_subflow_ctx(child) ||
|
|
|
|
!mptcp_subflow_ctx(child)->conn));
|
2020-01-22 08:56:18 +08:00
|
|
|
return child;
|
2020-03-28 05:48:39 +08:00
|
|
|
|
2020-05-16 01:22:17 +08:00
|
|
|
dispose_child:
|
2020-05-29 23:49:18 +08:00
|
|
|
subflow_drop_ctx(child);
|
2020-05-16 01:22:17 +08:00
|
|
|
tcp_rsk(req)->drop_req = true;
|
|
|
|
inet_csk_prepare_for_destroy_sock(child);
|
2020-03-28 05:48:39 +08:00
|
|
|
tcp_done(child);
|
2020-07-23 19:02:35 +08:00
|
|
|
req->rsk_ops->send_reset(sk, skb);
|
2020-05-16 01:22:17 +08:00
|
|
|
|
|
|
|
/* The last child reference will be released by the caller */
|
|
|
|
return child;
|
2020-01-22 08:56:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct inet_connection_sock_af_ops subflow_specific;
|
|
|
|
|
2020-01-22 08:56:24 +08:00
|
|
|
enum mapping_status {
|
|
|
|
MAPPING_OK,
|
|
|
|
MAPPING_INVALID,
|
|
|
|
MAPPING_EMPTY,
|
2020-06-30 04:26:20 +08:00
|
|
|
MAPPING_DATA_FIN,
|
|
|
|
MAPPING_DUMMY
|
2020-01-22 08:56:24 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static u64 expand_seq(u64 old_seq, u16 old_data_len, u64 seq)
|
|
|
|
{
|
|
|
|
if ((u32)seq == (u32)old_seq)
|
|
|
|
return old_seq;
|
|
|
|
|
|
|
|
/* Assume map covers data not mapped yet. */
|
|
|
|
return seq | ((old_seq + old_data_len + 1) & GENMASK_ULL(63, 32));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void warn_bad_map(struct mptcp_subflow_context *subflow, u32 ssn)
|
|
|
|
{
|
|
|
|
WARN_ONCE(1, "Bad mapping: ssn=%d map_seq=%d map_data_len=%d",
|
|
|
|
ssn, subflow->map_subflow_seq, subflow->map_data_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool skb_is_fully_mapped(struct sock *ssk, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
|
|
|
|
unsigned int skb_consumed;
|
|
|
|
|
|
|
|
skb_consumed = tcp_sk(ssk)->copied_seq - TCP_SKB_CB(skb)->seq;
|
|
|
|
if (WARN_ON_ONCE(skb_consumed >= skb->len))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return skb->len - skb_consumed <= subflow->map_data_len -
|
|
|
|
mptcp_subflow_get_map_offset(subflow);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool validate_mapping(struct sock *ssk, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
|
|
|
|
u32 ssn = tcp_sk(ssk)->copied_seq - subflow->ssn_offset;
|
|
|
|
|
|
|
|
if (unlikely(before(ssn, subflow->map_subflow_seq))) {
|
|
|
|
/* Mapping covers data later in the subflow stream,
|
|
|
|
* currently unsupported.
|
|
|
|
*/
|
|
|
|
warn_bad_map(subflow, ssn);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (unlikely(!before(ssn, subflow->map_subflow_seq +
|
|
|
|
subflow->map_data_len))) {
|
|
|
|
/* Mapping does covers past subflow data, invalid */
|
|
|
|
warn_bad_map(subflow, ssn + skb->len);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-29 06:12:06 +08:00
|
|
|
static enum mapping_status get_mapping_status(struct sock *ssk,
|
|
|
|
struct mptcp_sock *msk)
|
2020-01-22 08:56:24 +08:00
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
|
|
|
|
struct mptcp_ext *mpext;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
u16 data_len;
|
|
|
|
u64 map_seq;
|
|
|
|
|
|
|
|
skb = skb_peek(&ssk->sk_receive_queue);
|
|
|
|
if (!skb)
|
|
|
|
return MAPPING_EMPTY;
|
|
|
|
|
2020-06-30 04:26:20 +08:00
|
|
|
if (mptcp_check_fallback(ssk))
|
|
|
|
return MAPPING_DUMMY;
|
|
|
|
|
2020-01-22 08:56:24 +08:00
|
|
|
mpext = mptcp_get_ext(skb);
|
|
|
|
if (!mpext || !mpext->use_map) {
|
|
|
|
if (!subflow->map_valid && !skb->len) {
|
|
|
|
/* the TCP stack deliver 0 len FIN pkt to the receive
|
|
|
|
* queue, that is the only 0len pkts ever expected here,
|
|
|
|
* and we can admit no mapping only for 0 len pkts
|
|
|
|
*/
|
|
|
|
if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN))
|
|
|
|
WARN_ONCE(1, "0len seq %d:%d flags %x",
|
|
|
|
TCP_SKB_CB(skb)->seq,
|
|
|
|
TCP_SKB_CB(skb)->end_seq,
|
|
|
|
TCP_SKB_CB(skb)->tcp_flags);
|
|
|
|
sk_eat_skb(ssk, skb);
|
|
|
|
return MAPPING_EMPTY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!subflow->map_valid)
|
|
|
|
return MAPPING_INVALID;
|
|
|
|
|
|
|
|
goto validate_seq;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("seq=%llu is64=%d ssn=%u data_len=%u data_fin=%d",
|
|
|
|
mpext->data_seq, mpext->dsn64, mpext->subflow_seq,
|
|
|
|
mpext->data_len, mpext->data_fin);
|
|
|
|
|
|
|
|
data_len = mpext->data_len;
|
|
|
|
if (data_len == 0) {
|
|
|
|
pr_err("Infinite mapping not handled");
|
2020-03-28 05:48:50 +08:00
|
|
|
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPRX);
|
2020-01-22 08:56:24 +08:00
|
|
|
return MAPPING_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mpext->data_fin == 1) {
|
|
|
|
if (data_len == 1) {
|
2020-07-29 06:12:06 +08:00
|
|
|
mptcp_update_rcv_data_fin(msk, mpext->data_seq);
|
|
|
|
pr_debug("DATA_FIN with no payload seq=%llu", mpext->data_seq);
|
2020-01-22 08:56:24 +08:00
|
|
|
if (subflow->map_valid) {
|
|
|
|
/* A DATA_FIN might arrive in a DSS
|
|
|
|
* option before the previous mapping
|
|
|
|
* has been fully consumed. Continue
|
|
|
|
* handling the existing mapping.
|
|
|
|
*/
|
|
|
|
skb_ext_del(skb, SKB_EXT_MPTCP);
|
|
|
|
return MAPPING_OK;
|
|
|
|
} else {
|
|
|
|
return MAPPING_DATA_FIN;
|
|
|
|
}
|
2020-07-29 06:12:06 +08:00
|
|
|
} else {
|
|
|
|
mptcp_update_rcv_data_fin(msk, mpext->data_seq + data_len);
|
|
|
|
pr_debug("DATA_FIN with mapping seq=%llu", mpext->data_seq + data_len);
|
2020-01-22 08:56:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Adjust for DATA_FIN using 1 byte of sequence space */
|
|
|
|
data_len--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mpext->dsn64) {
|
|
|
|
map_seq = expand_seq(subflow->map_seq, subflow->map_data_len,
|
|
|
|
mpext->data_seq);
|
2020-05-14 23:53:03 +08:00
|
|
|
subflow->use_64bit_ack = 0;
|
2020-01-22 08:56:24 +08:00
|
|
|
pr_debug("expanded seq=%llu", subflow->map_seq);
|
|
|
|
} else {
|
|
|
|
map_seq = mpext->data_seq;
|
2020-05-14 23:53:03 +08:00
|
|
|
subflow->use_64bit_ack = 1;
|
2020-01-22 08:56:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (subflow->map_valid) {
|
|
|
|
/* Allow replacing only with an identical map */
|
|
|
|
if (subflow->map_seq == map_seq &&
|
|
|
|
subflow->map_subflow_seq == mpext->subflow_seq &&
|
|
|
|
subflow->map_data_len == data_len) {
|
|
|
|
skb_ext_del(skb, SKB_EXT_MPTCP);
|
|
|
|
return MAPPING_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If this skb data are fully covered by the current mapping,
|
|
|
|
* the new map would need caching, which is not supported
|
|
|
|
*/
|
2020-03-28 05:48:50 +08:00
|
|
|
if (skb_is_fully_mapped(ssk, skb)) {
|
|
|
|
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DSSNOMATCH);
|
2020-01-22 08:56:24 +08:00
|
|
|
return MAPPING_INVALID;
|
2020-03-28 05:48:50 +08:00
|
|
|
}
|
2020-01-22 08:56:24 +08:00
|
|
|
|
|
|
|
/* will validate the next map after consuming the current one */
|
|
|
|
return MAPPING_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
subflow->map_seq = map_seq;
|
|
|
|
subflow->map_subflow_seq = mpext->subflow_seq;
|
|
|
|
subflow->map_data_len = data_len;
|
|
|
|
subflow->map_valid = 1;
|
2020-01-22 08:56:32 +08:00
|
|
|
subflow->mpc_map = mpext->mpc_map;
|
2020-01-22 08:56:24 +08:00
|
|
|
pr_debug("new map seq=%llu subflow_seq=%u data_len=%u",
|
|
|
|
subflow->map_seq, subflow->map_subflow_seq,
|
|
|
|
subflow->map_data_len);
|
|
|
|
|
|
|
|
validate_seq:
|
|
|
|
/* we revalidate valid mapping on new skb, because we must ensure
|
|
|
|
* the current skb is completely covered by the available mapping
|
|
|
|
*/
|
|
|
|
if (!validate_mapping(ssk, skb))
|
|
|
|
return MAPPING_INVALID;
|
|
|
|
|
|
|
|
skb_ext_del(skb, SKB_EXT_MPTCP);
|
|
|
|
return MAPPING_OK;
|
|
|
|
}
|
|
|
|
|
2020-02-26 17:14:50 +08:00
|
|
|
static int subflow_read_actor(read_descriptor_t *desc,
|
|
|
|
struct sk_buff *skb,
|
|
|
|
unsigned int offset, size_t len)
|
|
|
|
{
|
|
|
|
size_t copy_len = min(desc->count, len);
|
|
|
|
|
|
|
|
desc->count -= copy_len;
|
|
|
|
|
|
|
|
pr_debug("flushed %zu bytes, %zu left", copy_len, desc->count);
|
|
|
|
return copy_len;
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:24 +08:00
|
|
|
static bool subflow_check_data_avail(struct sock *ssk)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
|
|
|
|
enum mapping_status status;
|
|
|
|
struct mptcp_sock *msk;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
pr_debug("msk=%p ssk=%p data_avail=%d skb=%p", subflow->conn, ssk,
|
|
|
|
subflow->data_avail, skb_peek(&ssk->sk_receive_queue));
|
|
|
|
if (subflow->data_avail)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
msk = mptcp_sk(subflow->conn);
|
|
|
|
for (;;) {
|
|
|
|
u32 map_remaining;
|
|
|
|
size_t delta;
|
|
|
|
u64 ack_seq;
|
|
|
|
u64 old_ack;
|
|
|
|
|
2020-07-29 06:12:06 +08:00
|
|
|
status = get_mapping_status(ssk, msk);
|
2020-01-22 08:56:24 +08:00
|
|
|
pr_debug("msk=%p ssk=%p status=%d", msk, ssk, status);
|
|
|
|
if (status == MAPPING_INVALID) {
|
|
|
|
ssk->sk_err = EBADMSG;
|
|
|
|
goto fatal;
|
|
|
|
}
|
2020-06-30 04:26:20 +08:00
|
|
|
if (status == MAPPING_DUMMY) {
|
|
|
|
__mptcp_do_fallback(msk);
|
|
|
|
skb = skb_peek(&ssk->sk_receive_queue);
|
|
|
|
subflow->map_valid = 1;
|
|
|
|
subflow->map_seq = READ_ONCE(msk->ack_seq);
|
|
|
|
subflow->map_data_len = skb->len;
|
|
|
|
subflow->map_subflow_seq = tcp_sk(ssk)->copied_seq -
|
|
|
|
subflow->ssn_offset;
|
|
|
|
return true;
|
|
|
|
}
|
2020-01-22 08:56:24 +08:00
|
|
|
|
|
|
|
if (status != MAPPING_OK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
skb = skb_peek(&ssk->sk_receive_queue);
|
|
|
|
if (WARN_ON_ONCE(!skb))
|
|
|
|
return false;
|
|
|
|
|
2020-01-22 08:56:32 +08:00
|
|
|
/* if msk lacks the remote key, this subflow must provide an
|
|
|
|
* MP_CAPABLE-based mapping
|
|
|
|
*/
|
|
|
|
if (unlikely(!READ_ONCE(msk->can_ack))) {
|
|
|
|
if (!subflow->mpc_map) {
|
|
|
|
ssk->sk_err = EBADMSG;
|
|
|
|
goto fatal;
|
|
|
|
}
|
|
|
|
WRITE_ONCE(msk->remote_key, subflow->remote_key);
|
|
|
|
WRITE_ONCE(msk->ack_seq, subflow->map_seq);
|
|
|
|
WRITE_ONCE(msk->can_ack, true);
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:24 +08:00
|
|
|
old_ack = READ_ONCE(msk->ack_seq);
|
|
|
|
ack_seq = mptcp_subflow_get_mapped_dsn(subflow);
|
|
|
|
pr_debug("msk ack_seq=%llx subflow ack_seq=%llx", old_ack,
|
|
|
|
ack_seq);
|
|
|
|
if (ack_seq == old_ack)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* only accept in-sequence mapping. Old values are spurious
|
|
|
|
* retransmission; we can hit "future" values on active backup
|
|
|
|
* subflow switch, we relay on retransmissions to get
|
|
|
|
* in-sequence data.
|
|
|
|
* Cuncurrent subflows support will require subflow data
|
|
|
|
* reordering
|
|
|
|
*/
|
|
|
|
map_remaining = subflow->map_data_len -
|
|
|
|
mptcp_subflow_get_map_offset(subflow);
|
|
|
|
if (before64(ack_seq, old_ack))
|
|
|
|
delta = min_t(size_t, old_ack - ack_seq, map_remaining);
|
|
|
|
else
|
|
|
|
delta = min_t(size_t, ack_seq - old_ack, map_remaining);
|
|
|
|
|
|
|
|
/* discard mapped data */
|
|
|
|
pr_debug("discarding %zu bytes, current map len=%d", delta,
|
|
|
|
map_remaining);
|
|
|
|
if (delta) {
|
|
|
|
read_descriptor_t desc = {
|
|
|
|
.count = delta,
|
|
|
|
};
|
|
|
|
int ret;
|
|
|
|
|
2020-02-26 17:14:50 +08:00
|
|
|
ret = tcp_read_sock(ssk, &desc, subflow_read_actor);
|
2020-01-22 08:56:24 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
ssk->sk_err = -ret;
|
|
|
|
goto fatal;
|
|
|
|
}
|
|
|
|
if (ret < delta)
|
|
|
|
return false;
|
|
|
|
if (delta == map_remaining)
|
|
|
|
subflow->map_valid = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
|
|
|
fatal:
|
|
|
|
/* fatal protocol error, close the socket */
|
|
|
|
/* This barrier is coupled with smp_rmb() in tcp_poll() */
|
|
|
|
smp_wmb();
|
|
|
|
ssk->sk_error_report(ssk);
|
|
|
|
tcp_set_state(ssk, TCP_CLOSE);
|
|
|
|
tcp_send_active_reset(ssk, GFP_ATOMIC);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mptcp_subflow_data_available(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
/* check if current mapping is still valid */
|
|
|
|
if (subflow->map_valid &&
|
|
|
|
mptcp_subflow_get_map_offset(subflow) >= subflow->map_data_len) {
|
|
|
|
subflow->map_valid = 0;
|
|
|
|
subflow->data_avail = 0;
|
|
|
|
|
|
|
|
pr_debug("Done with mapping: seq=%u data_len=%u",
|
|
|
|
subflow->map_subflow_seq,
|
|
|
|
subflow->map_data_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!subflow_check_data_avail(sk)) {
|
|
|
|
subflow->data_avail = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
skb = skb_peek(&sk->sk_receive_queue);
|
|
|
|
subflow->data_avail = skb &&
|
|
|
|
before(tcp_sk(sk)->copied_seq, TCP_SKB_CB(skb)->end_seq);
|
|
|
|
return subflow->data_avail;
|
|
|
|
}
|
|
|
|
|
2020-04-24 18:31:50 +08:00
|
|
|
/* If ssk has an mptcp parent socket, use the mptcp rcvbuf occupancy,
|
|
|
|
* not the ssk one.
|
|
|
|
*
|
|
|
|
* In mptcp, rwin is about the mptcp-level connection data.
|
|
|
|
*
|
|
|
|
* Data that is still on the ssk rx queue can thus be ignored,
|
|
|
|
* as far as mptcp peer is concerened that data is still inflight.
|
|
|
|
* DSS ACK is updated when skb is moved to the mptcp rx queue.
|
|
|
|
*/
|
|
|
|
void mptcp_space(const struct sock *ssk, int *space, int *full_space)
|
|
|
|
{
|
|
|
|
const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
|
|
|
|
const struct sock *sk = subflow->conn;
|
|
|
|
|
|
|
|
*space = tcp_space(sk);
|
|
|
|
*full_space = tcp_full_space(sk);
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:24 +08:00
|
|
|
static void subflow_data_ready(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
2020-07-16 04:27:05 +08:00
|
|
|
u16 state = 1 << inet_sk_state_load(sk);
|
2020-01-22 08:56:24 +08:00
|
|
|
struct sock *parent = subflow->conn;
|
2020-06-30 04:26:20 +08:00
|
|
|
struct mptcp_sock *msk;
|
2020-01-22 08:56:24 +08:00
|
|
|
|
2020-06-30 04:26:20 +08:00
|
|
|
msk = mptcp_sk(parent);
|
2020-07-16 04:27:05 +08:00
|
|
|
if (state & TCPF_LISTEN) {
|
2020-06-30 04:26:20 +08:00
|
|
|
set_bit(MPTCP_DATA_READY, &msk->flags);
|
2020-03-13 23:52:42 +08:00
|
|
|
parent->sk_data_ready(parent);
|
2020-01-22 08:56:24 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-30 04:26:20 +08:00
|
|
|
WARN_ON_ONCE(!__mptcp_check_fallback(msk) && !subflow->mp_capable &&
|
2020-07-16 04:27:05 +08:00
|
|
|
!subflow->mp_join && !(state & TCPF_CLOSE));
|
2020-06-30 04:26:20 +08:00
|
|
|
|
2020-02-26 17:14:46 +08:00
|
|
|
if (mptcp_subflow_data_available(sk))
|
2020-02-26 17:14:51 +08:00
|
|
|
mptcp_data_ready(parent, sk);
|
2020-01-22 08:56:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void subflow_write_space(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
|
|
|
struct sock *parent = subflow->conn;
|
|
|
|
|
|
|
|
sk_stream_write_space(sk);
|
2020-03-13 23:52:42 +08:00
|
|
|
if (sk_stream_is_writeable(sk)) {
|
2020-01-22 08:56:25 +08:00
|
|
|
set_bit(MPTCP_SEND_SPACE, &mptcp_sk(parent)->flags);
|
|
|
|
smp_mb__after_atomic();
|
|
|
|
/* set SEND_SPACE before sk_stream_write_space clears NOSPACE */
|
2020-01-22 08:56:24 +08:00
|
|
|
sk_stream_write_space(parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
static struct inet_connection_sock_af_ops *
|
|
|
|
subflow_default_af_ops(struct sock *sk)
|
|
|
|
{
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
if (sk->sk_family == AF_INET6)
|
|
|
|
return &subflow_v6_specific;
|
|
|
|
#endif
|
|
|
|
return &subflow_specific;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
2020-01-30 17:45:26 +08:00
|
|
|
void mptcpv6_handle_mapped(struct sock *sk, bool mapped)
|
|
|
|
{
|
2020-01-22 08:56:18 +08:00
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
struct inet_connection_sock_af_ops *target;
|
|
|
|
|
|
|
|
target = mapped ? &subflow_v6m_specific : subflow_default_af_ops(sk);
|
|
|
|
|
|
|
|
pr_debug("subflow=%p family=%d ops=%p target=%p mapped=%d",
|
2020-01-25 08:04:03 +08:00
|
|
|
subflow, sk->sk_family, icsk->icsk_af_ops, target, mapped);
|
2020-01-22 08:56:18 +08:00
|
|
|
|
|
|
|
if (likely(icsk->icsk_af_ops == target))
|
|
|
|
return;
|
|
|
|
|
|
|
|
subflow->icsk_af_ops = icsk->icsk_af_ops;
|
|
|
|
icsk->icsk_af_ops = target;
|
|
|
|
}
|
2020-01-30 17:45:26 +08:00
|
|
|
#endif
|
2020-01-22 08:56:18 +08:00
|
|
|
|
2020-03-28 05:48:40 +08:00
|
|
|
static void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
|
|
|
|
struct sockaddr_storage *addr)
|
|
|
|
{
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
addr->ss_family = info->family;
|
|
|
|
if (addr->ss_family == AF_INET) {
|
|
|
|
struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
|
|
|
|
|
|
|
|
in_addr->sin_addr = info->addr;
|
|
|
|
in_addr->sin_port = info->port;
|
|
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
else if (addr->ss_family == AF_INET6) {
|
|
|
|
struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)addr;
|
|
|
|
|
|
|
|
in6_addr->sin6_addr = info->addr6;
|
|
|
|
in6_addr->sin6_port = info->port;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int __mptcp_subflow_connect(struct sock *sk, int ifindex,
|
|
|
|
const struct mptcp_addr_info *loc,
|
|
|
|
const struct mptcp_addr_info *remote)
|
|
|
|
{
|
|
|
|
struct mptcp_sock *msk = mptcp_sk(sk);
|
|
|
|
struct mptcp_subflow_context *subflow;
|
|
|
|
struct sockaddr_storage addr;
|
2020-06-30 22:38:26 +08:00
|
|
|
int local_id = loc->id;
|
2020-03-28 05:48:40 +08:00
|
|
|
struct socket *sf;
|
2020-06-30 22:38:26 +08:00
|
|
|
struct sock *ssk;
|
2020-03-28 05:48:40 +08:00
|
|
|
u32 remote_token;
|
|
|
|
int addrlen;
|
|
|
|
int err;
|
|
|
|
|
2020-07-23 19:02:32 +08:00
|
|
|
if (!mptcp_is_fully_established(sk))
|
2020-03-28 05:48:40 +08:00
|
|
|
return -ENOTCONN;
|
|
|
|
|
|
|
|
err = mptcp_subflow_create_socket(sk, &sf);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2020-06-30 22:38:26 +08:00
|
|
|
ssk = sf->sk;
|
|
|
|
subflow = mptcp_subflow_ctx(ssk);
|
|
|
|
do {
|
|
|
|
get_random_bytes(&subflow->local_nonce, sizeof(u32));
|
|
|
|
} while (!subflow->local_nonce);
|
|
|
|
|
|
|
|
if (!local_id) {
|
|
|
|
err = mptcp_pm_get_local_id(msk, (struct sock_common *)ssk);
|
|
|
|
if (err < 0)
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
local_id = err;
|
|
|
|
}
|
|
|
|
|
2020-03-28 05:48:40 +08:00
|
|
|
subflow->remote_key = msk->remote_key;
|
|
|
|
subflow->local_key = msk->local_key;
|
|
|
|
subflow->token = msk->token;
|
|
|
|
mptcp_info2sockaddr(loc, &addr);
|
|
|
|
|
|
|
|
addrlen = sizeof(struct sockaddr_in);
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
if (loc->family == AF_INET6)
|
|
|
|
addrlen = sizeof(struct sockaddr_in6);
|
|
|
|
#endif
|
2020-06-30 22:38:26 +08:00
|
|
|
ssk->sk_bound_dev_if = ifindex;
|
2020-03-28 05:48:40 +08:00
|
|
|
err = kernel_bind(sf, (struct sockaddr *)&addr, addrlen);
|
|
|
|
if (err)
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
mptcp_crypto_key_sha(subflow->remote_key, &remote_token, NULL);
|
2020-06-30 22:38:26 +08:00
|
|
|
pr_debug("msk=%p remote_token=%u local_id=%d", msk, remote_token,
|
|
|
|
local_id);
|
2020-03-28 05:48:40 +08:00
|
|
|
subflow->remote_token = remote_token;
|
2020-06-30 22:38:26 +08:00
|
|
|
subflow->local_id = local_id;
|
2020-03-28 05:48:40 +08:00
|
|
|
subflow->request_join = 1;
|
|
|
|
subflow->request_bkup = 1;
|
|
|
|
mptcp_info2sockaddr(remote, &addr);
|
|
|
|
|
|
|
|
err = kernel_connect(sf, (struct sockaddr *)&addr, addrlen, O_NONBLOCK);
|
|
|
|
if (err && err != -EINPROGRESS)
|
|
|
|
goto failed;
|
|
|
|
|
|
|
|
spin_lock_bh(&msk->join_list_lock);
|
|
|
|
list_add_tail(&subflow->node, &msk->join_list);
|
|
|
|
spin_unlock_bh(&msk->join_list_lock);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
failed:
|
|
|
|
sock_release(sf);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:17 +08:00
|
|
|
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow;
|
|
|
|
struct net *net = sock_net(sk);
|
|
|
|
struct socket *sf;
|
|
|
|
int err;
|
|
|
|
|
2020-08-05 00:31:06 +08:00
|
|
|
/* un-accepted server sockets can reach here - on bad configuration
|
|
|
|
* bail early to avoid greater trouble later
|
|
|
|
*/
|
|
|
|
if (unlikely(!sk->sk_socket))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
err = sock_create_kern(net, sk->sk_family, SOCK_STREAM, IPPROTO_TCP,
|
|
|
|
&sf);
|
2020-01-22 08:56:17 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
lock_sock(sf->sk);
|
|
|
|
|
|
|
|
/* kernel sockets do not by default acquire net ref, but TCP timer
|
|
|
|
* needs it.
|
|
|
|
*/
|
|
|
|
sf->sk->sk_net_refcnt = 1;
|
|
|
|
get_net(net);
|
2020-01-29 17:39:23 +08:00
|
|
|
#ifdef CONFIG_PROC_FS
|
2020-01-22 08:56:17 +08:00
|
|
|
this_cpu_add(*net->core.sock_inuse, 1);
|
2020-01-29 17:39:23 +08:00
|
|
|
#endif
|
2020-01-22 08:56:17 +08:00
|
|
|
err = tcp_set_ulp(sf->sk, "mptcp");
|
|
|
|
release_sock(sf->sk);
|
|
|
|
|
2020-06-15 09:35:22 +08:00
|
|
|
if (err) {
|
|
|
|
sock_release(sf);
|
2020-01-22 08:56:17 +08:00
|
|
|
return err;
|
2020-06-15 09:35:22 +08:00
|
|
|
}
|
2020-01-22 08:56:17 +08:00
|
|
|
|
2020-05-08 00:53:24 +08:00
|
|
|
/* the newly created socket really belongs to the owning MPTCP master
|
|
|
|
* socket, even if for additional subflows the allocation is performed
|
|
|
|
* by a kernel workqueue. Adjust inode references, so that the
|
|
|
|
* procfs/diag interaces really show this one belonging to the correct
|
|
|
|
* user.
|
|
|
|
*/
|
|
|
|
SOCK_INODE(sf)->i_ino = SOCK_INODE(sk->sk_socket)->i_ino;
|
|
|
|
SOCK_INODE(sf)->i_uid = SOCK_INODE(sk->sk_socket)->i_uid;
|
|
|
|
SOCK_INODE(sf)->i_gid = SOCK_INODE(sk->sk_socket)->i_gid;
|
|
|
|
|
2020-01-22 08:56:17 +08:00
|
|
|
subflow = mptcp_subflow_ctx(sf->sk);
|
|
|
|
pr_debug("subflow=%p", subflow);
|
|
|
|
|
|
|
|
*new_sock = sf;
|
2020-01-22 08:56:20 +08:00
|
|
|
sock_hold(sk);
|
2020-01-22 08:56:17 +08:00
|
|
|
subflow->conn = sk;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct mptcp_subflow_context *subflow_create_ctx(struct sock *sk,
|
|
|
|
gfp_t priority)
|
|
|
|
{
|
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
struct mptcp_subflow_context *ctx;
|
|
|
|
|
|
|
|
ctx = kzalloc(sizeof(*ctx), priority);
|
|
|
|
if (!ctx)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
rcu_assign_pointer(icsk->icsk_ulp_data, ctx);
|
2020-01-22 08:56:18 +08:00
|
|
|
INIT_LIST_HEAD(&ctx->node);
|
2020-01-22 08:56:17 +08:00
|
|
|
|
|
|
|
pr_debug("subflow=%p", ctx);
|
|
|
|
|
|
|
|
ctx->tcp_sock = sk;
|
|
|
|
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:24 +08:00
|
|
|
static void __subflow_state_change(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct socket_wq *wq;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
wq = rcu_dereference(sk->sk_wq);
|
|
|
|
if (skwq_has_sleeper(wq))
|
|
|
|
wake_up_interruptible_all(&wq->wait);
|
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool subflow_is_done(const struct sock *sk)
|
|
|
|
{
|
|
|
|
return sk->sk_shutdown & RCV_SHUTDOWN || sk->sk_state == TCP_CLOSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subflow_state_change(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
2020-03-13 23:52:42 +08:00
|
|
|
struct sock *parent = subflow->conn;
|
2020-01-22 08:56:24 +08:00
|
|
|
|
|
|
|
__subflow_state_change(sk);
|
|
|
|
|
mptcp: fallback in case of simultaneous connect
when a MPTCP client tries to connect to itself, tcp_finish_connect() is
never reached. Because of this, depending on the socket current state,
multiple faulty behaviours can be observed:
1) a WARN_ON() in subflow_data_ready() is hit
WARNING: CPU: 2 PID: 882 at net/mptcp/subflow.c:911 subflow_data_ready+0x18b/0x230
[...]
CPU: 2 PID: 882 Comm: gh35 Not tainted 5.7.0+ #187
[...]
RIP: 0010:subflow_data_ready+0x18b/0x230
[...]
Call Trace:
tcp_data_queue+0xd2f/0x4250
tcp_rcv_state_process+0xb1c/0x49d3
tcp_v4_do_rcv+0x2bc/0x790
__release_sock+0x153/0x2d0
release_sock+0x4f/0x170
mptcp_shutdown+0x167/0x4e0
__sys_shutdown+0xe6/0x180
__x64_sys_shutdown+0x50/0x70
do_syscall_64+0x9a/0x370
entry_SYSCALL_64_after_hwframe+0x44/0xa9
2) client is stuck forever in mptcp_sendmsg() because the socket is not
TCP_ESTABLISHED
crash> bt 4847
PID: 4847 TASK: ffff88814b2fb100 CPU: 1 COMMAND: "gh35"
#0 [ffff8881376ff680] __schedule at ffffffff97248da4
#1 [ffff8881376ff778] schedule at ffffffff9724a34f
#2 [ffff8881376ff7a0] schedule_timeout at ffffffff97252ba0
#3 [ffff8881376ff8a8] wait_woken at ffffffff958ab4ba
#4 [ffff8881376ff940] sk_stream_wait_connect at ffffffff96c2d859
#5 [ffff8881376ffa28] mptcp_sendmsg at ffffffff97207fca
#6 [ffff8881376ffbc0] sock_sendmsg at ffffffff96be1b5b
#7 [ffff8881376ffbe8] sock_write_iter at ffffffff96be1daa
#8 [ffff8881376ffce8] new_sync_write at ffffffff95e5cb52
#9 [ffff8881376ffe50] vfs_write at ffffffff95e6547f
#10 [ffff8881376ffe90] ksys_write at ffffffff95e65d26
#11 [ffff8881376fff28] do_syscall_64 at ffffffff956088ba
#12 [ffff8881376fff50] entry_SYSCALL_64_after_hwframe at ffffffff9740008c
RIP: 00007f126f6956ed RSP: 00007ffc2a320278 RFLAGS: 00000217
RAX: ffffffffffffffda RBX: 0000000020000044 RCX: 00007f126f6956ed
RDX: 0000000000000004 RSI: 00000000004007b8 RDI: 0000000000000003
RBP: 00007ffc2a3202a0 R8: 0000000000400720 R9: 0000000000400720
R10: 0000000000400720 R11: 0000000000000217 R12: 00000000004004b0
R13: 00007ffc2a320380 R14: 0000000000000000 R15: 0000000000000000
ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b
3) tcpdump captures show that DSS is exchanged even when MP_CAPABLE handshake
didn't complete.
$ tcpdump -tnnr bad.pcap
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [S], seq 3208913911, win 65483, options [mss 65495,sackOK,TS val 3291706876 ecr 3291694721,nop,wscale 7,mptcp capable v1], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [S.], seq 3208913911, ack 3208913912, win 65483, options [mss 65495,sackOK,TS val 3291706876 ecr 3291706876,nop,wscale 7,mptcp capable v1], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [.], ack 1, win 512, options [nop,nop,TS val 3291706876 ecr 3291706876], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [F.], seq 1, ack 1, win 512, options [nop,nop,TS val 3291707876 ecr 3291706876,mptcp dss fin seq 0 subseq 0 len 1,nop,nop], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [.], ack 2, win 512, options [nop,nop,TS val 3291707876 ecr 3291707876], length 0
force a fallback to TCP in these cases, and adjust the main socket
state to avoid hanging in mptcp_sendmsg().
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/35
Reported-by: Christoph Paasch <cpaasch@apple.com>
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-06-30 04:26:21 +08:00
|
|
|
if (subflow_simultaneous_connect(sk)) {
|
|
|
|
mptcp_do_fallback(sk);
|
2020-07-01 03:24:45 +08:00
|
|
|
mptcp_rcv_space_init(mptcp_sk(parent), sk);
|
mptcp: fallback in case of simultaneous connect
when a MPTCP client tries to connect to itself, tcp_finish_connect() is
never reached. Because of this, depending on the socket current state,
multiple faulty behaviours can be observed:
1) a WARN_ON() in subflow_data_ready() is hit
WARNING: CPU: 2 PID: 882 at net/mptcp/subflow.c:911 subflow_data_ready+0x18b/0x230
[...]
CPU: 2 PID: 882 Comm: gh35 Not tainted 5.7.0+ #187
[...]
RIP: 0010:subflow_data_ready+0x18b/0x230
[...]
Call Trace:
tcp_data_queue+0xd2f/0x4250
tcp_rcv_state_process+0xb1c/0x49d3
tcp_v4_do_rcv+0x2bc/0x790
__release_sock+0x153/0x2d0
release_sock+0x4f/0x170
mptcp_shutdown+0x167/0x4e0
__sys_shutdown+0xe6/0x180
__x64_sys_shutdown+0x50/0x70
do_syscall_64+0x9a/0x370
entry_SYSCALL_64_after_hwframe+0x44/0xa9
2) client is stuck forever in mptcp_sendmsg() because the socket is not
TCP_ESTABLISHED
crash> bt 4847
PID: 4847 TASK: ffff88814b2fb100 CPU: 1 COMMAND: "gh35"
#0 [ffff8881376ff680] __schedule at ffffffff97248da4
#1 [ffff8881376ff778] schedule at ffffffff9724a34f
#2 [ffff8881376ff7a0] schedule_timeout at ffffffff97252ba0
#3 [ffff8881376ff8a8] wait_woken at ffffffff958ab4ba
#4 [ffff8881376ff940] sk_stream_wait_connect at ffffffff96c2d859
#5 [ffff8881376ffa28] mptcp_sendmsg at ffffffff97207fca
#6 [ffff8881376ffbc0] sock_sendmsg at ffffffff96be1b5b
#7 [ffff8881376ffbe8] sock_write_iter at ffffffff96be1daa
#8 [ffff8881376ffce8] new_sync_write at ffffffff95e5cb52
#9 [ffff8881376ffe50] vfs_write at ffffffff95e6547f
#10 [ffff8881376ffe90] ksys_write at ffffffff95e65d26
#11 [ffff8881376fff28] do_syscall_64 at ffffffff956088ba
#12 [ffff8881376fff50] entry_SYSCALL_64_after_hwframe at ffffffff9740008c
RIP: 00007f126f6956ed RSP: 00007ffc2a320278 RFLAGS: 00000217
RAX: ffffffffffffffda RBX: 0000000020000044 RCX: 00007f126f6956ed
RDX: 0000000000000004 RSI: 00000000004007b8 RDI: 0000000000000003
RBP: 00007ffc2a3202a0 R8: 0000000000400720 R9: 0000000000400720
R10: 0000000000400720 R11: 0000000000000217 R12: 00000000004004b0
R13: 00007ffc2a320380 R14: 0000000000000000 R15: 0000000000000000
ORIG_RAX: 0000000000000001 CS: 0033 SS: 002b
3) tcpdump captures show that DSS is exchanged even when MP_CAPABLE handshake
didn't complete.
$ tcpdump -tnnr bad.pcap
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [S], seq 3208913911, win 65483, options [mss 65495,sackOK,TS val 3291706876 ecr 3291694721,nop,wscale 7,mptcp capable v1], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [S.], seq 3208913911, ack 3208913912, win 65483, options [mss 65495,sackOK,TS val 3291706876 ecr 3291706876,nop,wscale 7,mptcp capable v1], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [.], ack 1, win 512, options [nop,nop,TS val 3291706876 ecr 3291706876], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [F.], seq 1, ack 1, win 512, options [nop,nop,TS val 3291707876 ecr 3291706876,mptcp dss fin seq 0 subseq 0 len 1,nop,nop], length 0
IP 127.0.0.1.20000 > 127.0.0.1.20000: Flags [.], ack 2, win 512, options [nop,nop,TS val 3291707876 ecr 3291707876], length 0
force a fallback to TCP in these cases, and adjust the main socket
state to avoid hanging in mptcp_sendmsg().
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/35
Reported-by: Christoph Paasch <cpaasch@apple.com>
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-06-30 04:26:21 +08:00
|
|
|
pr_fallback(mptcp_sk(parent));
|
|
|
|
subflow->conn_finished = 1;
|
|
|
|
if (inet_sk_state_load(parent) == TCP_SYN_SENT) {
|
|
|
|
inet_sk_state_store(parent, TCP_ESTABLISHED);
|
|
|
|
parent->sk_state_change(parent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:24 +08:00
|
|
|
/* as recvmsg() does not acquire the subflow socket for ssk selection
|
|
|
|
* a fin packet carrying a DSS can be unnoticed if we don't trigger
|
|
|
|
* the data available machinery here.
|
|
|
|
*/
|
2020-06-30 04:26:20 +08:00
|
|
|
if (mptcp_subflow_data_available(sk))
|
2020-02-26 17:14:51 +08:00
|
|
|
mptcp_data_ready(parent, sk);
|
2020-01-22 08:56:24 +08:00
|
|
|
|
2020-07-29 06:12:07 +08:00
|
|
|
if (__mptcp_check_fallback(mptcp_sk(parent)) &&
|
|
|
|
!(parent->sk_shutdown & RCV_SHUTDOWN) &&
|
2020-01-22 08:56:24 +08:00
|
|
|
!subflow->rx_eof && subflow_is_done(sk)) {
|
|
|
|
subflow->rx_eof = 1;
|
2020-04-02 19:44:52 +08:00
|
|
|
mptcp_subflow_eof(parent);
|
2020-01-22 08:56:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:17 +08:00
|
|
|
static int subflow_ulp_init(struct sock *sk)
|
|
|
|
{
|
2020-01-22 08:56:18 +08:00
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
2020-01-22 08:56:17 +08:00
|
|
|
struct mptcp_subflow_context *ctx;
|
|
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
/* disallow attaching ULP to a socket unless it has been
|
|
|
|
* created with sock_create_kern()
|
|
|
|
*/
|
|
|
|
if (!sk->sk_kern_sock) {
|
|
|
|
err = -EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = subflow_create_ctx(sk, GFP_KERNEL);
|
|
|
|
if (!ctx) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("subflow=%p, family=%d", ctx, sk->sk_family);
|
|
|
|
|
|
|
|
tp->is_mptcp = 1;
|
2020-01-22 08:56:18 +08:00
|
|
|
ctx->icsk_af_ops = icsk->icsk_af_ops;
|
|
|
|
icsk->icsk_af_ops = subflow_default_af_ops(sk);
|
2020-01-22 08:56:24 +08:00
|
|
|
ctx->tcp_data_ready = sk->sk_data_ready;
|
|
|
|
ctx->tcp_state_change = sk->sk_state_change;
|
|
|
|
ctx->tcp_write_space = sk->sk_write_space;
|
|
|
|
sk->sk_data_ready = subflow_data_ready;
|
|
|
|
sk->sk_write_space = subflow_write_space;
|
|
|
|
sk->sk_state_change = subflow_state_change;
|
2020-01-22 08:56:17 +08:00
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void subflow_ulp_release(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(sk);
|
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
return;
|
|
|
|
|
2020-01-22 08:56:20 +08:00
|
|
|
if (ctx->conn)
|
|
|
|
sock_put(ctx->conn);
|
|
|
|
|
2020-01-22 08:56:17 +08:00
|
|
|
kfree_rcu(ctx, rcu);
|
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
static void subflow_ulp_clone(const struct request_sock *req,
|
|
|
|
struct sock *newsk,
|
|
|
|
const gfp_t priority)
|
|
|
|
{
|
|
|
|
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
|
|
|
struct mptcp_subflow_context *old_ctx = mptcp_subflow_ctx(newsk);
|
|
|
|
struct mptcp_subflow_context *new_ctx;
|
|
|
|
|
2020-03-28 05:48:39 +08:00
|
|
|
if (!tcp_rsk(req)->is_mptcp ||
|
|
|
|
(!subflow_req->mp_capable && !subflow_req->mp_join)) {
|
2020-01-22 08:56:24 +08:00
|
|
|
subflow_ulp_fallback(newsk, old_ctx);
|
2020-01-22 08:56:18 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_ctx = subflow_create_ctx(newsk, priority);
|
2020-01-25 08:04:03 +08:00
|
|
|
if (!new_ctx) {
|
2020-01-22 08:56:24 +08:00
|
|
|
subflow_ulp_fallback(newsk, old_ctx);
|
2020-01-22 08:56:18 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_ctx->conn_finished = 1;
|
|
|
|
new_ctx->icsk_af_ops = old_ctx->icsk_af_ops;
|
2020-01-22 08:56:24 +08:00
|
|
|
new_ctx->tcp_data_ready = old_ctx->tcp_data_ready;
|
|
|
|
new_ctx->tcp_state_change = old_ctx->tcp_state_change;
|
|
|
|
new_ctx->tcp_write_space = old_ctx->tcp_write_space;
|
2020-03-13 23:52:41 +08:00
|
|
|
new_ctx->rel_write_seq = 1;
|
|
|
|
new_ctx->tcp_sock = newsk;
|
|
|
|
|
2020-03-28 05:48:39 +08:00
|
|
|
if (subflow_req->mp_capable) {
|
|
|
|
/* see comments in subflow_syn_recv_sock(), MPTCP connection
|
|
|
|
* is fully established only after we receive the remote key
|
|
|
|
*/
|
|
|
|
new_ctx->mp_capable = 1;
|
|
|
|
new_ctx->local_key = subflow_req->local_key;
|
|
|
|
new_ctx->token = subflow_req->token;
|
|
|
|
new_ctx->ssn_offset = subflow_req->ssn_offset;
|
|
|
|
new_ctx->idsn = subflow_req->idsn;
|
|
|
|
} else if (subflow_req->mp_join) {
|
2020-03-28 05:48:40 +08:00
|
|
|
new_ctx->ssn_offset = subflow_req->ssn_offset;
|
2020-03-28 05:48:39 +08:00
|
|
|
new_ctx->mp_join = 1;
|
|
|
|
new_ctx->fully_established = 1;
|
|
|
|
new_ctx->backup = subflow_req->backup;
|
|
|
|
new_ctx->local_id = subflow_req->local_id;
|
|
|
|
new_ctx->token = subflow_req->token;
|
|
|
|
new_ctx->thmac = subflow_req->thmac;
|
|
|
|
}
|
2020-01-22 08:56:18 +08:00
|
|
|
}
|
|
|
|
|
2020-01-22 08:56:17 +08:00
|
|
|
static struct tcp_ulp_ops subflow_ulp_ops __read_mostly = {
|
|
|
|
.name = "mptcp",
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.init = subflow_ulp_init,
|
|
|
|
.release = subflow_ulp_release,
|
2020-01-22 08:56:18 +08:00
|
|
|
.clone = subflow_ulp_clone,
|
2020-01-22 08:56:17 +08:00
|
|
|
};
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
static int subflow_ops_init(struct request_sock_ops *subflow_ops)
|
|
|
|
{
|
|
|
|
subflow_ops->obj_size = sizeof(struct mptcp_subflow_request_sock);
|
|
|
|
subflow_ops->slab_name = "request_sock_subflow";
|
|
|
|
|
|
|
|
subflow_ops->slab = kmem_cache_create(subflow_ops->slab_name,
|
|
|
|
subflow_ops->obj_size, 0,
|
|
|
|
SLAB_ACCOUNT |
|
|
|
|
SLAB_TYPESAFE_BY_RCU,
|
|
|
|
NULL);
|
|
|
|
if (!subflow_ops->slab)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-01-22 08:56:20 +08:00
|
|
|
subflow_ops->destructor = subflow_req_destructor;
|
|
|
|
|
2020-01-22 08:56:18 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-27 01:29:59 +08:00
|
|
|
void __init mptcp_subflow_init(void)
|
2020-01-22 08:56:17 +08:00
|
|
|
{
|
2020-07-31 03:25:53 +08:00
|
|
|
mptcp_subflow_request_sock_ops = tcp_request_sock_ops;
|
|
|
|
if (subflow_ops_init(&mptcp_subflow_request_sock_ops) != 0)
|
2020-01-22 08:56:18 +08:00
|
|
|
panic("MPTCP: failed to init subflow request sock ops\n");
|
|
|
|
|
|
|
|
subflow_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops;
|
|
|
|
subflow_request_sock_ipv4_ops.init_req = subflow_v4_init_req;
|
|
|
|
|
|
|
|
subflow_specific = ipv4_specific;
|
|
|
|
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;
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
|
|
|
subflow_request_sock_ipv6_ops = tcp_request_sock_ipv6_ops;
|
|
|
|
subflow_request_sock_ipv6_ops.init_req = subflow_v6_init_req;
|
|
|
|
|
|
|
|
subflow_v6_specific = ipv6_specific;
|
|
|
|
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_v6m_specific = subflow_v6_specific;
|
|
|
|
subflow_v6m_specific.queue_xmit = ipv4_specific.queue_xmit;
|
|
|
|
subflow_v6m_specific.send_check = ipv4_specific.send_check;
|
|
|
|
subflow_v6m_specific.net_header_len = ipv4_specific.net_header_len;
|
|
|
|
subflow_v6m_specific.mtu_reduced = ipv4_specific.mtu_reduced;
|
|
|
|
subflow_v6m_specific.net_frag_header_len = 0;
|
|
|
|
#endif
|
|
|
|
|
2020-03-28 05:48:49 +08:00
|
|
|
mptcp_diag_subflow_init(&subflow_ulp_ops);
|
|
|
|
|
2020-01-22 08:56:17 +08:00
|
|
|
if (tcp_register_ulp(&subflow_ulp_ops) != 0)
|
|
|
|
panic("MPTCP: failed to register subflows to ULP\n");
|
|
|
|
}
|