4.9-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Guillaume Nault <g.na...@alphalink.fr>


[ Upstream commit a9b2dff80be979432484afaf7f8d8e73f9e8838a ]

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: Guillaume Nault <g.na...@alphalink.fr>
Signed-off-by: David S. Miller <da...@davemloft.net>
Signed-off-by: Sasha Levin <alexander.le...@verizon.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>
---
 net/l2tp/l2tp_ip.c  |   19 ++++++-------------
 net/l2tp/l2tp_ip6.c |   20 ++++++--------------
 2 files changed, 12 insertions(+), 27 deletions(-)

--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -48,7 +48,8 @@ static inline struct l2tp_ip_sock *l2tp_
        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;
 
@@ -62,6 +63,7 @@ static struct sock *__l2tp_ip_bind_looku
                if ((l2tp->conn_id == tunnel_id) &&
                    net_eq(sock_net(sk), net) &&
                    !(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))
                        goto found;
@@ -72,15 +74,6 @@ found:
        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
  * consider. Data frames consist of a non-zero session-id and an
  * optional cookie. Control frames consist of a regular L2TP header
@@ -186,8 +179,8 @@ pass_up:
                struct iphdr *iph = (struct iphdr *) skb_network_header(skb);
 
                read_lock_bh(&l2tp_ip_lock);
-               sk = __l2tp_ip_bind_lookup(net, iph->daddr, inet_iif(skb),
-                                          tunnel_id);
+               sk = __l2tp_ip_bind_lookup(net, iph->daddr, iph->saddr,
+                                          inet_iif(skb), tunnel_id);
                if (!sk) {
                        read_unlock_bh(&l2tp_ip_lock);
                        goto discard;
@@ -289,7 +282,7 @@ static int l2tp_ip_bind(struct sock *sk,
                inet->inet_saddr = 0;  /* Use device */
 
        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)) {
                write_unlock_bh(&l2tp_ip_lock);
                ret = -EADDRINUSE;
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -59,12 +59,14 @@ static inline struct l2tp_ip6_sock *l2tp
 
 static struct sock *__l2tp_ip6_bind_lookup(struct net *net,
                                           struct in6_addr *laddr,
+                                          const struct in6_addr *raddr,
                                           int dif, u32 tunnel_id)
 {
        struct sock *sk;
 
        sk_for_each_bound(sk, &l2tp_ip6_bind_table) {
                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);
 
                if (l2tp == NULL)
@@ -73,6 +75,7 @@ static struct sock *__l2tp_ip6_bind_look
                if ((l2tp->conn_id == tunnel_id) &&
                    net_eq(sock_net(sk), net) &&
                    (!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))
                        goto found;
@@ -83,17 +86,6 @@ found:
        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
  * consider. Data frames consist of a non-zero session-id and an
  * optional cookie. Control frames consist of a regular L2TP header
@@ -200,8 +192,8 @@ pass_up:
                struct ipv6hdr *iph = ipv6_hdr(skb);
 
                read_lock_bh(&l2tp_ip6_lock);
-               sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, inet6_iif(skb),
-                                           tunnel_id);
+               sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, &iph->saddr,
+                                           inet6_iif(skb), tunnel_id);
                if (!sk) {
                        read_unlock_bh(&l2tp_ip6_lock);
                        goto discard;
@@ -339,7 +331,7 @@ static int l2tp_ip6_bind(struct sock *sk
        rcu_read_unlock();
 
        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)) {
                write_unlock_bh(&l2tp_ip6_lock);
                err = -EADDRINUSE;


Reply via email to