Skip to content

Commit

Permalink
l2tp: lock socket before checking flags in connect()
Browse files Browse the repository at this point in the history
Socket flags aren't updated atomically, so the socket must be locked
while reading the SOCK_ZAPPED flag.

This issue exists for both l2tp_ip and l2tp_ip6. For IPv6, this patch
also brings error handling for __ip6_datagram_connect() failures.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Guillaume Nault authored and David S. Miller committed Nov 30, 2016
1 parent bb83d62 commit 0382a25
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 13 deletions.
2 changes: 2 additions & 0 deletions include/net/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,8 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);

int __ip6_datagram_connect(struct sock *sk, struct sockaddr *addr,
int addr_len);
int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len);
int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *addr,
int addr_len);
Expand Down
4 changes: 3 additions & 1 deletion net/ipv6/datagram.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ void ip6_datagram_release_cb(struct sock *sk)
}
EXPORT_SYMBOL_GPL(ip6_datagram_release_cb);

static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_len)
{
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
struct inet_sock *inet = inet_sk(sk);
Expand Down Expand Up @@ -252,6 +253,7 @@ static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int a
out:
return err;
}
EXPORT_SYMBOL_GPL(__ip6_datagram_connect);

int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
Expand Down
19 changes: 12 additions & 7 deletions net/l2tp/l2tp_ip.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,29 +308,34 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len
struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
int rc;

if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
return -EINVAL;

if (addr_len < sizeof(*lsa))
return -EINVAL;

if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
return -EINVAL;

rc = ip4_datagram_connect(sk, uaddr, addr_len);
if (rc < 0)
return rc;

lock_sock(sk);

/* Must bind first - autobinding does not work */
if (sock_flag(sk, SOCK_ZAPPED)) {
rc = -EINVAL;
goto out_sk;
}

rc = __ip4_datagram_connect(sk, uaddr, addr_len);
if (rc < 0)
goto out_sk;

l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;

write_lock_bh(&l2tp_ip_lock);
hlist_del_init(&sk->sk_bind_node);
sk_add_bind_node(sk, &l2tp_ip_bind_table);
write_unlock_bh(&l2tp_ip_lock);

out_sk:
release_sock(sk);

return rc;
}

Expand Down
16 changes: 11 additions & 5 deletions net/l2tp/l2tp_ip6.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,6 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_type;
int rc;

if (sock_flag(sk, SOCK_ZAPPED)) /* Must bind first - autobinding does not work */
return -EINVAL;

if (addr_len < sizeof(*lsa))
return -EINVAL;

Expand All @@ -390,17 +387,26 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr,
return -EINVAL;
}

rc = ip6_datagram_connect(sk, uaddr, addr_len);

lock_sock(sk);

/* Must bind first - autobinding does not work */
if (sock_flag(sk, SOCK_ZAPPED)) {
rc = -EINVAL;
goto out_sk;
}

rc = __ip6_datagram_connect(sk, uaddr, addr_len);
if (rc < 0)
goto out_sk;

l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;

write_lock_bh(&l2tp_ip6_lock);
hlist_del_init(&sk->sk_bind_node);
sk_add_bind_node(sk, &l2tp_ip6_bind_table);
write_unlock_bh(&l2tp_ip6_lock);

out_sk:
release_sock(sk);

return rc;
Expand Down

0 comments on commit 0382a25

Please sign in to comment.