summaryrefslogtreecommitdiff
path: root/net/ipv6/udp.c
diff options
context:
space:
mode:
authorSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2017-07-06 19:50:19 -0600
committerSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2017-07-12 15:02:18 -0600
commitc4a69905373742f0e5b1a26fdabe5899055aa3db (patch)
treed8a7ec02c13b08fdc64133a794115975f19f4d4d /net/ipv6/udp.c
parent92ccb2945524adff73b9fda04ecaffd1bce1d43c (diff)
net: ipv6: Fix UDP early demux lookup with udp_l3mdev_accept=0"
David Ahern reported that "net: ipv6: Add early demux handler for UDP unicast" breaks udp_l3mdev_accept=0 since early demux for IPv6 UDP was doing a generic socket lookup which does not require an exact match. Fix this by making UDPv6 early demux match connected sockets only. v1->v2: Take reference to socket after match as suggested by Eric v2->v3: Add comment before break CRs-Fixed: 2057820 Change-Id: Ief9fd4a51561b7a49efa3780ebe8dc3632bdfa1c Fixes: 5425077d73e0c ("net: ipv6: Add early demux handler for UDP unicast") Reported-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> Cc: Eric Dumazet <edumazet@google.com> Acked-by: David Ahern <dsa@cumulusnetworks.com> Tested-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net> Git-commit: 0bd84065b19bca12f07f288c8ea470e2c1b2de7a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [subashab@codeaurora.org: resolve trivial merge conflicts]
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r--net/ipv6/udp.c27
1 files changed, 17 insertions, 10 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 8a07c63ddccd..a48a8faa401c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -45,6 +45,7 @@
#include <net/tcp_states.h>
#include <net/ip6_checksum.h>
#include <net/xfrm.h>
+#include <net/inet_hashtables.h>
#include <net/inet6_hashtables.h>
#include <net/busy_poll.h>
@@ -964,15 +965,21 @@ static struct sock *__udp6_lib_demux_lookup(struct net *net,
int dif)
{
struct sock *sk;
-
- rcu_read_lock();
- sk = __udp6_lib_lookup(net, rmt_addr, rmt_port, loc_addr, loc_port,
- dif, &udp_table);
- if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
- sk = NULL;
- rcu_read_unlock();
-
- return sk;
+ struct hlist_nulls_node *hnode;
+ unsigned short hnum = ntohs(loc_port);
+ unsigned int hash2 = udp6_portaddr_hash(net, loc_addr, hnum);
+ unsigned int slot2 = hash2 & udp_table.mask;
+ struct udp_hslot *hslot2 = &udp_table.hash2[slot2];
+
+ const __portpair ports = INET_COMBINED_PORTS(rmt_port, hnum);
+
+ udp_portaddr_for_each_entry_rcu(sk, hnode, &hslot2->head) {
+ if (INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif))
+ return sk;
+ /* Only check first socket in chain */
+ break;
+ }
+ return NULL;
}
static void udp_v6_early_demux(struct sk_buff *skb)
@@ -997,7 +1004,7 @@ static void udp_v6_early_demux(struct sk_buff *skb)
else
return;
- if (!sk)
+ if (!sk || !atomic_inc_not_zero_hint(&sk->sk_refcnt, 2))
return;
skb->sk = sk;