net: ipv6: Fix UDP early demux lookup with udp_l3mdev_accept=0
Subsystems (3)
PATCH v3 1/1 net: ipv6: Fix UDP early demux lookup with udp_l3mdev_accept=0
David Ahern reported that 5425077d73e0c ("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
Fixes 5425077d73e0c ("net: ipv6: Add early demux handler for UDP unicast")
Reported-by David Ahern <[email protected]>
Signed-off-by Subash Abhinov Kasiviswanathan <[email protected]>
Cc Eric Dumazet <[email protected]>
Acked-by David Ahern <[email protected]>
Tested-by David Ahern <[email protected]>
--- net/ipv6/udp.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-)
net/ipv6/udp.c +15 -9
@@ -46,6 +46,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> #include <net/sock_reuseport.h>
@@ -864,21 +865,26 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,return 0 ; } +static struct sock *__udp6_lib_demux_lookup (struct net *net,__be16 loc_port,const struct in6_addr *loc_addr,__be16 rmt_port,const struct in6_addr *rmt_addr,int dif) { +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);struct sock *sk; -rcu_read_lock (); - sk =__udp6_lib_lookup (net, rmt_addr, rmt_port, loc_addr, loc_port, - dif, &udp_table,NULL ); -if (sk && !atomic_inc_not_zero (&sk->sk_refcnt)) - sk =NULL ; -rcu_read_unlock (); - -return sk; +udp_portaddr_for_each_entry_rcu (sk, &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)
@@ -903,7 +909,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;
Signature · 1 line
1.9.1