diff options
author | Guillaume Nault <g.nault@alphalink.fr> | 2016-11-29 07:09:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-30 14:14:08 -0500 |
commit | df90e6886146dd744eb3929782e6df9749cd4a69 (patch) | |
tree | b9e1e821b3f0b3572724ba9e4817f36d8c23a420 /net | |
parent | d5e3a190937a1e386671266202c62565741f0f1a (diff) |
l2tp: fix lookup for sockets not bound to a device in l2tp_ip
When looking up an l2tp socket, we must consider a null netdevice id as
wild card. There are currently two problems caused by
__l2tp_ip_bind_lookup() not considering 'dif' as wild card when set to 0:
* A socket bound to a device (i.e. with sk->sk_bound_dev_if != 0)
never receives any packet. Since __l2tp_ip_bind_lookup() is called
with dif == 0 in l2tp_ip_recv(), sk->sk_bound_dev_if is always
different from 'dif' so the socket doesn't match.
* Two sockets, one bound to a device but not the other, can be bound
to the same address. If the first socket binding to the address is
the one that is also bound to a device, the second socket can bind
to the same address without __l2tp_ip_bind_lookup() noticing the
overlap.
To fix this issue, we need to consider that any null device index, be
it 'sk->sk_bound_dev_if' or 'dif', matches with any other value.
We also need to pass the input device index to __l2tp_ip_bind_lookup()
on reception so that sockets bound to a device never receive packets
from other devices.
This patch fixes l2tp_ip6 in the same way.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/l2tp/l2tp_ip.c | 6 | ||||
-rw-r--r-- | net/l2tp/l2tp_ip6.c | 7 |
2 files changed, 8 insertions, 5 deletions
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index b517c3366922..8938b6ba57a0 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -61,7 +61,8 @@ static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif | |||
61 | if ((l2tp->conn_id == tunnel_id) && | 61 | if ((l2tp->conn_id == tunnel_id) && |
62 | net_eq(sock_net(sk), net) && | 62 | net_eq(sock_net(sk), net) && |
63 | !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && | 63 | !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && |
64 | !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) | 64 | (!sk->sk_bound_dev_if || !dif || |
65 | sk->sk_bound_dev_if == dif)) | ||
65 | goto found; | 66 | goto found; |
66 | } | 67 | } |
67 | 68 | ||
@@ -182,7 +183,8 @@ pass_up: | |||
182 | struct iphdr *iph = (struct iphdr *) skb_network_header(skb); | 183 | struct iphdr *iph = (struct iphdr *) skb_network_header(skb); |
183 | 184 | ||
184 | read_lock_bh(&l2tp_ip_lock); | 185 | read_lock_bh(&l2tp_ip_lock); |
185 | sk = __l2tp_ip_bind_lookup(net, iph->daddr, 0, tunnel_id); | 186 | sk = __l2tp_ip_bind_lookup(net, iph->daddr, inet_iif(skb), |
187 | tunnel_id); | ||
186 | if (!sk) { | 188 | if (!sk) { |
187 | read_unlock_bh(&l2tp_ip_lock); | 189 | read_unlock_bh(&l2tp_ip_lock); |
188 | goto discard; | 190 | goto discard; |
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 5f2ae615c5f9..4a8644001d09 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c | |||
@@ -73,7 +73,8 @@ static struct sock *__l2tp_ip6_bind_lookup(struct net *net, | |||
73 | if ((l2tp->conn_id == tunnel_id) && | 73 | if ((l2tp->conn_id == tunnel_id) && |
74 | net_eq(sock_net(sk), net) && | 74 | net_eq(sock_net(sk), net) && |
75 | !(addr && ipv6_addr_equal(addr, laddr)) && | 75 | !(addr && ipv6_addr_equal(addr, laddr)) && |
76 | !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) | 76 | (!sk->sk_bound_dev_if || !dif || |
77 | sk->sk_bound_dev_if == dif)) | ||
77 | goto found; | 78 | goto found; |
78 | } | 79 | } |
79 | 80 | ||
@@ -196,8 +197,8 @@ pass_up: | |||
196 | struct ipv6hdr *iph = ipv6_hdr(skb); | 197 | struct ipv6hdr *iph = ipv6_hdr(skb); |
197 | 198 | ||
198 | read_lock_bh(&l2tp_ip6_lock); | 199 | read_lock_bh(&l2tp_ip6_lock); |
199 | sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, | 200 | sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, inet6_iif(skb), |
200 | 0, tunnel_id); | 201 | tunnel_id); |
201 | if (!sk) { | 202 | if (!sk) { |
202 | read_unlock_bh(&l2tp_ip6_lock); | 203 | read_unlock_bh(&l2tp_ip6_lock); |
203 | goto discard; | 204 | goto discard; |