mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
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>
This commit is contained in:
committed by
David S. Miller
parent
14e4cec80c
commit
03645a11a5
@@ -161,6 +161,7 @@ static inline __u8 get_rtconn_flags(struct ipcm_cookie* ipc, struct sock* sk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* datagram.c */
|
/* datagram.c */
|
||||||
|
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);
|
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
|
||||||
|
|
||||||
void ip4_datagram_release_cb(struct sock *sk);
|
void ip4_datagram_release_cb(struct sock *sk);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
#include <net/tcp_states.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 inet_sock *inet = inet_sk(sk);
|
||||||
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
|
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);
|
sk_dst_reset(sk);
|
||||||
|
|
||||||
lock_sock(sk);
|
|
||||||
|
|
||||||
oif = sk->sk_bound_dev_if;
|
oif = sk->sk_bound_dev_if;
|
||||||
saddr = inet->inet_saddr;
|
saddr = inet->inet_saddr;
|
||||||
if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
|
if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
|
||||||
@@ -82,9 +80,19 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|||||||
sk_dst_set(sk, &rt->dst);
|
sk_dst_set(sk, &rt->dst);
|
||||||
err = 0;
|
err = 0;
|
||||||
out:
|
out:
|
||||||
release_sock(sk);
|
|
||||||
return err;
|
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);
|
EXPORT_SYMBOL(ip4_datagram_connect);
|
||||||
|
|
||||||
/* Because UDP xmit path can manipulate sk_dst_cache without holding
|
/* Because UDP xmit path can manipulate sk_dst_cache without holding
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a)
|
|||||||
return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0);
|
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 sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
|
||||||
struct inet_sock *inet = inet_sk(sk);
|
struct inet_sock *inet = inet_sk(sk);
|
||||||
@@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|||||||
if (usin->sin6_family == AF_INET) {
|
if (usin->sin6_family == AF_INET) {
|
||||||
if (__ipv6_only_sock(sk))
|
if (__ipv6_only_sock(sk))
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
err = ip4_datagram_connect(sk, uaddr, addr_len);
|
err = __ip4_datagram_connect(sk, uaddr, addr_len);
|
||||||
goto ipv4_connected;
|
goto ipv4_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,9 +98,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_addr.s_addr = daddr->s6_addr32[3];
|
||||||
sin.sin_port = usin->sin6_port;
|
sin.sin_port = usin->sin6_port;
|
||||||
|
|
||||||
err = ip4_datagram_connect(sk,
|
err = __ip4_datagram_connect(sk,
|
||||||
(struct sockaddr *) &sin,
|
(struct sockaddr *) &sin,
|
||||||
sizeof(sin));
|
sizeof(sin));
|
||||||
|
|
||||||
ipv4_connected:
|
ipv4_connected:
|
||||||
if (err)
|
if (err)
|
||||||
@@ -204,6 +204,16 @@ out:
|
|||||||
fl6_sock_release(flowlabel);
|
fl6_sock_release(flowlabel);
|
||||||
return err;
|
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;
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(ip6_datagram_connect);
|
EXPORT_SYMBOL_GPL(ip6_datagram_connect);
|
||||||
|
|
||||||
int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr,
|
int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr,
|
||||||
|
|||||||
Reference in New Issue
Block a user