Commit c1a7dedb authored by Eric Dumazet's avatar Eric Dumazet Committed by Ben Hutchings

ipv6: lock socket in ip6_datagram_connect()

[ Upstream commit 03645a11 ]

ip6_datagram_connect() is doing a lot of socket changes without
socket being locked.

This looks wrong, at least for udp_lib_rehash() which could corrupt
lists because of concurrent udp_sk(sk)->udp_portaddr_hash accesses.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 58a5897a
......@@ -138,6 +138,7 @@ static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4)
}
/* datagram.c */
int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
extern int ip4_datagram_connect(struct sock *sk,
struct sockaddr *uaddr, int addr_len);
......
......@@ -20,7 +20,7 @@
#include <net/route.h>
#include <net/tcp_states.h>
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct inet_sock *inet = inet_sk(sk);
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
......@@ -39,8 +39,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk_dst_reset(sk);
lock_sock(sk);
oif = sk->sk_bound_dev_if;
saddr = inet->inet_saddr;
if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
......@@ -81,7 +79,17 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sk_dst_set(sk, &rt->dst);
err = 0;
out:
release_sock(sk);
return err;
}
EXPORT_SYMBOL(__ip4_datagram_connect);
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
int res;
lock_sock(sk);
res = __ip4_datagram_connect(sk, uaddr, addr_len);
release_sock(sk);
return res;
}
EXPORT_SYMBOL(ip4_datagram_connect);
......@@ -38,7 +38,7 @@ static inline int ipv6_mapped_addr_any(const struct in6_addr *a)
return (ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0));
}
int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
static 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);
......@@ -54,7 +54,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (usin->sin6_family == AF_INET) {
if (__ipv6_only_sock(sk))
return -EAFNOSUPPORT;
err = ip4_datagram_connect(sk, uaddr, addr_len);
err = __ip4_datagram_connect(sk, uaddr, addr_len);
goto ipv4_connected;
}
......@@ -97,9 +97,9 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
sin.sin_addr.s_addr = daddr->s6_addr32[3];
sin.sin_port = usin->sin6_port;
err = ip4_datagram_connect(sk,
(struct sockaddr*) &sin,
sizeof(sin));
err = __ip4_datagram_connect(sk,
(struct sockaddr *) &sin,
sizeof(sin));
ipv4_connected:
if (err)
......@@ -203,6 +203,16 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return err;
}
int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
int res;
lock_sock(sk);
res = __ip6_datagram_connect(sk, uaddr, addr_len);
release_sock(sk);
return res;
}
void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
__be16 port, u32 info, u8 *payload)
{
......
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