diff options
author | Eric Dumazet <edumazet@google.com> | 2015-07-14 02:10:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-07-15 20:25:51 -0400 |
commit | 03645a11a570d52e70631838cb786eb4253eb463 (patch) | |
tree | 8a370b57010d040b59fd7e17ba90d1d8ed1c7650 /net/ipv6 | |
parent | 14e4cec80cd05ad585c537db56a705ab61fbaff9 (diff) |
ipv6: lock socket in ip6_datagram_connect()
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: Eric Dumazet <edumazet@google.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/datagram.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 62d908e64eeb..b10a88986a98 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a) | |||
40 | return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0); | 40 | return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0); |
41 | } | 41 | } |
42 | 42 | ||
43 | int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 43 | static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
44 | { | 44 | { |
45 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; | 45 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; |
46 | struct inet_sock *inet = inet_sk(sk); | 46 | struct inet_sock *inet = inet_sk(sk); |
@@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
56 | if (usin->sin6_family == AF_INET) { | 56 | if (usin->sin6_family == AF_INET) { |
57 | if (__ipv6_only_sock(sk)) | 57 | if (__ipv6_only_sock(sk)) |
58 | return -EAFNOSUPPORT; | 58 | return -EAFNOSUPPORT; |
59 | err = ip4_datagram_connect(sk, uaddr, addr_len); | 59 | err = __ip4_datagram_connect(sk, uaddr, addr_len); |
60 | goto ipv4_connected; | 60 | goto ipv4_connected; |
61 | } | 61 | } |
62 | 62 | ||
@@ -98,9 +98,9 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
98 | sin.sin_addr.s_addr = daddr->s6_addr32[3]; | 98 | sin.sin_addr.s_addr = daddr->s6_addr32[3]; |
99 | sin.sin_port = usin->sin6_port; | 99 | sin.sin_port = usin->sin6_port; |
100 | 100 | ||
101 | err = ip4_datagram_connect(sk, | 101 | err = __ip4_datagram_connect(sk, |
102 | (struct sockaddr *) &sin, | 102 | (struct sockaddr *) &sin, |
103 | sizeof(sin)); | 103 | sizeof(sin)); |
104 | 104 | ||
105 | ipv4_connected: | 105 | ipv4_connected: |
106 | if (err) | 106 | if (err) |
@@ -204,6 +204,16 @@ out: | |||
204 | fl6_sock_release(flowlabel); | 204 | fl6_sock_release(flowlabel); |
205 | return err; | 205 | return err; |
206 | } | 206 | } |
207 | |||
208 | int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | ||
209 | { | ||
210 | int res; | ||
211 | |||
212 | lock_sock(sk); | ||
213 | res = __ip6_datagram_connect(sk, uaddr, addr_len); | ||
214 | release_sock(sk); | ||
215 | return res; | ||
216 | } | ||
207 | EXPORT_SYMBOL_GPL(ip6_datagram_connect); | 217 | EXPORT_SYMBOL_GPL(ip6_datagram_connect); |
208 | 218 | ||
209 | int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr, | 219 | int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr, |