From mboxrd@z Thu Jan 1 00:00:00 1970 From: Mike Manning Subject: [PATCH net-next v5 3/9] net: ensure unbound datagram socket to be chosen when not in a VRF Date: Wed, 7 Nov 2018 15:36:04 +0000 Message-ID: <20181107153610.7526-4-mmanning@vyatta.att-mail.com> References: <20181107153610.7526-1-mmanning@vyatta.att-mail.com> To: netdev@vger.kernel.org Return-path: Received: from mx0a-00191d01.pphosted.com ([67.231.149.140]:40192 "EHLO mx0a-00191d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728058AbeKHBH2 (ORCPT ); Wed, 7 Nov 2018 20:07:28 -0500 Received: from pps.filterd (m0048589.ppops.net [127.0.0.1]) by m0048589.ppops.net-00191d01. (8.16.0.22/8.16.0.22) with SMTP id wA7FJI98030900 for ; Wed, 7 Nov 2018 10:36:36 -0500 Received: from tlpd255.enaf.dadc.sbc.com (sbcsmtp3.sbc.com [144.160.112.28]) by m0048589.ppops.net-00191d01. with ESMTP id 2nm1packwu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 07 Nov 2018 10:36:35 -0500 Received: from enaf.dadc.sbc.com (localhost [127.0.0.1]) by tlpd255.enaf.dadc.sbc.com (8.14.5/8.14.5) with ESMTP id wA7FaWIj070628 for ; Wed, 7 Nov 2018 09:36:34 -0600 Received: from zlp30495.vci.att.com (zlp30495.vci.att.com [135.46.181.158]) by tlpd255.enaf.dadc.sbc.com (8.14.5/8.14.5) with ESMTP id wA7FaT9R070467 for ; Wed, 7 Nov 2018 09:36:29 -0600 Received: from zlp30495.vci.att.com (zlp30495.vci.att.com [127.0.0.1]) by zlp30495.vci.att.com (Service) with ESMTP id D545140D3C41 for ; Wed, 7 Nov 2018 15:36:29 +0000 (GMT) Received: from clpi183.sldc.sbc.com (unknown [135.41.1.46]) by zlp30495.vci.att.com (Service) with ESMTP id B366940D3C40 for ; Wed, 7 Nov 2018 15:36:29 +0000 (GMT) Received: from sldc.sbc.com (localhost [127.0.0.1]) by clpi183.sldc.sbc.com (8.14.5/8.14.5) with ESMTP id wA7FaSNQ006450 for ; Wed, 7 Nov 2018 09:36:29 -0600 Received: from mail.eng.vyatta.net (mail.eng.vyatta.net [10.156.50.82]) by clpi183.sldc.sbc.com (8.14.5/8.14.5) with ESMTP id wA7FaJWZ005677 for ; Wed, 7 Nov 2018 09:36:19 -0600 Received: from MM-7520.vyatta.net (unknown [10.156.47.119]) by mail.eng.vyatta.net (Postfix) with ESMTPA id F06A9360235 for ; Wed, 7 Nov 2018 07:36:18 -0800 (PST) In-Reply-To: <20181107153610.7526-1-mmanning@vyatta.att-mail.com> Sender: netdev-owner@vger.kernel.org List-ID: Ensure an unbound datagram skt is chosen when not in a VRF. The check for a device match in compute_score() for UDP must be performed when there is no device match. For this, a failure is returned when there is no device match. This ensures that bound sockets are never selected, even if there is no unbound socket. Allow IPv6 packets to be sent over a datagram skt bound to a VRF. These packets are currently blocked, as flowi6_oif was set to that of the master vrf device, and the ipi6_ifindex is that of the slave device. Allow these packets to be sent by checking the device with ipi6_ifindex has the same L3 scope as that of the bound device of the skt, which is the master vrf device. Note that this check always succeeds if the skt is unbound. Even though the right datagram skt is now selected by compute_score(), a different skt is being returned that is bound to the wrong vrf. The difference between these and stream sockets is the handling of the skt option for SO_REUSEPORT. While the handling when adding a skt for reuse correctly checks that the bound device of the skt is a match, the skts in the hashslot are already incorrect. So for the same hash, a skt for the wrong vrf may be selected for the required port. The root cause is that the skt is immediately placed into a slot when it is created, but when the skt is then bound using SO_BINDTODEVICE, it remains in the same slot. The solution is to move the skt to the correct slot by forcing a rehash. Signed-off-by: Mike Manning --- include/net/udp.h | 11 +++++++++++ net/core/sock.c | 2 ++ net/ipv4/udp.c | 15 ++++++--------- net/ipv6/datagram.c | 10 +++++++--- net/ipv6/udp.c | 14 +++++--------- 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/include/net/udp.h b/include/net/udp.h index 9e82cb391dea..a496e441645e 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -252,6 +252,17 @@ static inline int udp_rqueue_get(struct sock *sk) return sk_rmem_alloc_get(sk) - READ_ONCE(udp_sk(sk)->forward_deficit); } +static inline bool udp_sk_bound_dev_eq(struct net *net, int bound_dev_if, + int dif, int sdif) +{ +#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) + return inet_bound_dev_eq(!!net->ipv4.sysctl_udp_l3mdev_accept, + bound_dev_if, dif, sdif); +#else + return inet_bound_dev_eq(true, bound_dev_if, dif, sdif); +#endif +} + /* net/ipv4/udp.c */ void udp_destruct_sock(struct sock *sk); void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len); diff --git a/net/core/sock.c b/net/core/sock.c index 7e8796a6a089..2fff1796dcba 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -567,6 +567,8 @@ static int sock_setbindtodevice(struct sock *sk, char __user *optval, lock_sock(sk); sk->sk_bound_dev_if = index; + if (sk->sk_prot->rehash) + sk->sk_prot->rehash(sk); sk_dst_reset(sk); release_sock(sk); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 07d6fb80f433..2c01d52a8dd9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -371,6 +371,7 @@ static int compute_score(struct sock *sk, struct net *net, { int score; struct inet_sock *inet; + bool dev_match; if (!net_eq(sock_net(sk), net) || udp_sk(sk)->udp_port_hash != hnum || @@ -398,15 +399,11 @@ static int compute_score(struct sock *sk, struct net *net, score += 4; } - if (sk->sk_bound_dev_if || exact_dif) { - bool dev_match = (sk->sk_bound_dev_if == dif || - sk->sk_bound_dev_if == sdif); - - if (!dev_match) - return -1; - if (sk->sk_bound_dev_if) - score += 4; - } + dev_match = udp_sk_bound_dev_eq(net, sk->sk_bound_dev_if, + dif, sdif); + if (!dev_match) + return -1; + score += 4; if (sk->sk_incoming_cpu == raw_smp_processor_id()) score++; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 1ede7a16a0be..bde08aa549f3 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -772,6 +772,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk, case IPV6_2292PKTINFO: { struct net_device *dev = NULL; + int src_idx; if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { err = -EINVAL; @@ -779,12 +780,15 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk, } src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); + src_idx = src_info->ipi6_ifindex; - if (src_info->ipi6_ifindex) { + if (src_idx) { if (fl6->flowi6_oif && - src_info->ipi6_ifindex != fl6->flowi6_oif) + src_idx != fl6->flowi6_oif && + (sk->sk_bound_dev_if != fl6->flowi6_oif || + !sk_dev_equal_l3scope(sk, src_idx))) return -EINVAL; - fl6->flowi6_oif = src_info->ipi6_ifindex; + fl6->flowi6_oif = src_idx; } addr_type = __ipv6_addr_type(&src_info->ipi6_addr); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5dc6949ed956..895fa77bde90 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -117,6 +117,7 @@ static int compute_score(struct sock *sk, struct net *net, { int score; struct inet_sock *inet; + bool dev_match; if (!net_eq(sock_net(sk), net) || udp_sk(sk)->udp_port_hash != hnum || @@ -144,15 +145,10 @@ static int compute_score(struct sock *sk, struct net *net, score++; } - if (sk->sk_bound_dev_if || exact_dif) { - bool dev_match = (sk->sk_bound_dev_if == dif || - sk->sk_bound_dev_if == sdif); - - if (!dev_match) - return -1; - if (sk->sk_bound_dev_if) - score++; - } + dev_match = udp_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif); + if (!dev_match) + return -1; + score++; if (sk->sk_incoming_cpu == raw_smp_processor_id()) score++; -- 2.11.0