diff options
author | Eric Dumazet <edumazet@google.com> | 2015-07-14 08:10:22 +0200 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2015-10-13 03:46:12 +0100 |
commit | c1a7dedbcb0b60ecbcda0d2398ad5d2b078c9f47 (patch) | |
tree | ceeb9883d850281b835275aaa3befc7043fedbff /net/ipv6/datagram.c | |
parent | 58a5897a53d535bf95523e6f381f88116217f5ca (diff) | |
download | kernel_samsung_smdk4412-c1a7dedbcb0b60ecbcda0d2398ad5d2b078c9f47.zip kernel_samsung_smdk4412-c1a7dedbcb0b60ecbcda0d2398ad5d2b078c9f47.tar.gz kernel_samsung_smdk4412-c1a7dedbcb0b60ecbcda0d2398ad5d2b078c9f47.tar.bz2 |
ipv6: lock socket in ip6_datagram_connect()
[ Upstream commit 03645a11a570d52e70631838cb786eb4253eb463 ]
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>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'net/ipv6/datagram.c')
-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 33719b7..67f3632 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -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 @@ out: 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) { |