Commit a9b2dff8 authored by Guillaume Nault's avatar Guillaume Nault Committed by David S. Miller

l2tp: take remote address into account in l2tp_ip and l2tp_ip6 socket lookups

For connected sockets, __l2tp_ip{,6}_bind_lookup() needs to check the
remote IP when looking for a matching socket. Otherwise a connected
socket can receive traffic not originating from its peer.

Drop l2tp_ip_bind_lookup() and l2tp_ip6_bind_lookup() instead of
updating their prototype, as these functions aren't used.
Signed-off-by: default avatarGuillaume Nault <g.nault@alphalink.fr>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 97b84fd6
...@@ -47,7 +47,8 @@ static inline struct l2tp_ip_sock *l2tp_ip_sk(const struct sock *sk) ...@@ -47,7 +47,8 @@ static inline struct l2tp_ip_sock *l2tp_ip_sk(const struct sock *sk)
return (struct l2tp_ip_sock *)sk; return (struct l2tp_ip_sock *)sk;
} }
static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif, u32 tunnel_id) static struct sock *__l2tp_ip_bind_lookup(const struct net *net, __be32 laddr,
__be32 raddr, int dif, u32 tunnel_id)
{ {
struct sock *sk; struct sock *sk;
...@@ -61,6 +62,7 @@ static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif ...@@ -61,6 +62,7 @@ static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif
if ((l2tp->conn_id == tunnel_id) && if ((l2tp->conn_id == tunnel_id) &&
net_eq(sock_net(sk), net) && net_eq(sock_net(sk), net) &&
!(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
(!inet->inet_daddr || !raddr || inet->inet_daddr == raddr) &&
(!sk->sk_bound_dev_if || !dif || (!sk->sk_bound_dev_if || !dif ||
sk->sk_bound_dev_if == dif)) sk->sk_bound_dev_if == dif))
goto found; goto found;
...@@ -71,15 +73,6 @@ static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif ...@@ -71,15 +73,6 @@ static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif
return sk; return sk;
} }
static inline struct sock *l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif, u32 tunnel_id)
{
struct sock *sk = __l2tp_ip_bind_lookup(net, laddr, dif, tunnel_id);
if (sk)
sock_hold(sk);
return sk;
}
/* When processing receive frames, there are two cases to /* When processing receive frames, there are two cases to
* consider. Data frames consist of a non-zero session-id and an * consider. Data frames consist of a non-zero session-id and an
* optional cookie. Control frames consist of a regular L2TP header * optional cookie. Control frames consist of a regular L2TP header
...@@ -183,8 +176,8 @@ static int l2tp_ip_recv(struct sk_buff *skb) ...@@ -183,8 +176,8 @@ static int l2tp_ip_recv(struct sk_buff *skb)
struct iphdr *iph = (struct iphdr *) skb_network_header(skb); struct iphdr *iph = (struct iphdr *) skb_network_header(skb);
read_lock_bh(&l2tp_ip_lock); read_lock_bh(&l2tp_ip_lock);
sk = __l2tp_ip_bind_lookup(net, iph->daddr, inet_iif(skb), sk = __l2tp_ip_bind_lookup(net, iph->daddr, iph->saddr,
tunnel_id); inet_iif(skb), tunnel_id);
if (!sk) { if (!sk) {
read_unlock_bh(&l2tp_ip_lock); read_unlock_bh(&l2tp_ip_lock);
goto discard; goto discard;
...@@ -280,7 +273,7 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -280,7 +273,7 @@ static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
inet->inet_saddr = 0; /* Use device */ inet->inet_saddr = 0; /* Use device */
write_lock_bh(&l2tp_ip_lock); write_lock_bh(&l2tp_ip_lock);
if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr, if (__l2tp_ip_bind_lookup(net, addr->l2tp_addr.s_addr, 0,
sk->sk_bound_dev_if, addr->l2tp_conn_id)) { sk->sk_bound_dev_if, addr->l2tp_conn_id)) {
write_unlock_bh(&l2tp_ip_lock); write_unlock_bh(&l2tp_ip_lock);
ret = -EADDRINUSE; ret = -EADDRINUSE;
......
...@@ -59,12 +59,14 @@ static inline struct l2tp_ip6_sock *l2tp_ip6_sk(const struct sock *sk) ...@@ -59,12 +59,14 @@ static inline struct l2tp_ip6_sock *l2tp_ip6_sk(const struct sock *sk)
static struct sock *__l2tp_ip6_bind_lookup(struct net *net, static struct sock *__l2tp_ip6_bind_lookup(struct net *net,
struct in6_addr *laddr, struct in6_addr *laddr,
const struct in6_addr *raddr,
int dif, u32 tunnel_id) int dif, u32 tunnel_id)
{ {
struct sock *sk; struct sock *sk;
sk_for_each_bound(sk, &l2tp_ip6_bind_table) { sk_for_each_bound(sk, &l2tp_ip6_bind_table) {
const struct in6_addr *sk_laddr = inet6_rcv_saddr(sk); const struct in6_addr *sk_laddr = inet6_rcv_saddr(sk);
const struct in6_addr *sk_raddr = &sk->sk_v6_daddr;
struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk); struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk);
if (l2tp == NULL) if (l2tp == NULL)
...@@ -73,6 +75,7 @@ static struct sock *__l2tp_ip6_bind_lookup(struct net *net, ...@@ -73,6 +75,7 @@ static struct sock *__l2tp_ip6_bind_lookup(struct net *net,
if ((l2tp->conn_id == tunnel_id) && if ((l2tp->conn_id == tunnel_id) &&
net_eq(sock_net(sk), net) && net_eq(sock_net(sk), net) &&
(!sk_laddr || ipv6_addr_any(sk_laddr) || ipv6_addr_equal(sk_laddr, laddr)) && (!sk_laddr || ipv6_addr_any(sk_laddr) || ipv6_addr_equal(sk_laddr, laddr)) &&
(!raddr || ipv6_addr_any(sk_raddr) || ipv6_addr_equal(sk_raddr, raddr)) &&
(!sk->sk_bound_dev_if || !dif || (!sk->sk_bound_dev_if || !dif ||
sk->sk_bound_dev_if == dif)) sk->sk_bound_dev_if == dif))
goto found; goto found;
...@@ -83,17 +86,6 @@ static struct sock *__l2tp_ip6_bind_lookup(struct net *net, ...@@ -83,17 +86,6 @@ static struct sock *__l2tp_ip6_bind_lookup(struct net *net,
return sk; return sk;
} }
static inline struct sock *l2tp_ip6_bind_lookup(struct net *net,
struct in6_addr *laddr,
int dif, u32 tunnel_id)
{
struct sock *sk = __l2tp_ip6_bind_lookup(net, laddr, dif, tunnel_id);
if (sk)
sock_hold(sk);
return sk;
}
/* When processing receive frames, there are two cases to /* When processing receive frames, there are two cases to
* consider. Data frames consist of a non-zero session-id and an * consider. Data frames consist of a non-zero session-id and an
* optional cookie. Control frames consist of a regular L2TP header * optional cookie. Control frames consist of a regular L2TP header
...@@ -197,8 +189,8 @@ static int l2tp_ip6_recv(struct sk_buff *skb) ...@@ -197,8 +189,8 @@ static int l2tp_ip6_recv(struct sk_buff *skb)
struct ipv6hdr *iph = ipv6_hdr(skb); struct ipv6hdr *iph = ipv6_hdr(skb);
read_lock_bh(&l2tp_ip6_lock); read_lock_bh(&l2tp_ip6_lock);
sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, inet6_iif(skb), sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, &iph->saddr,
tunnel_id); inet6_iif(skb), tunnel_id);
if (!sk) { if (!sk) {
read_unlock_bh(&l2tp_ip6_lock); read_unlock_bh(&l2tp_ip6_lock);
goto discard; goto discard;
...@@ -330,7 +322,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -330,7 +322,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
rcu_read_unlock(); rcu_read_unlock();
write_lock_bh(&l2tp_ip6_lock); write_lock_bh(&l2tp_ip6_lock);
if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr, bound_dev_if, if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr, NULL, bound_dev_if,
addr->l2tp_conn_id)) { addr->l2tp_conn_id)) {
write_unlock_bh(&l2tp_ip6_lock); write_unlock_bh(&l2tp_ip6_lock);
err = -EADDRINUSE; err = -EADDRINUSE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment