Commit 1227c177 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by David S. Miller

net: Fix data-races around sysctl_[rw]mem_(max|default).

While reading sysctl_[rw]mem_(max|default), they can be changed
concurrently.  Thus, we need to add READ_ONCE() to its readers.

Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c624c58e
...@@ -5034,14 +5034,14 @@ static int __bpf_setsockopt(struct sock *sk, int level, int optname, ...@@ -5034,14 +5034,14 @@ static int __bpf_setsockopt(struct sock *sk, int level, int optname,
/* Only some socketops are supported */ /* Only some socketops are supported */
switch (optname) { switch (optname) {
case SO_RCVBUF: case SO_RCVBUF:
val = min_t(u32, val, sysctl_rmem_max); val = min_t(u32, val, READ_ONCE(sysctl_rmem_max));
val = min_t(int, val, INT_MAX / 2); val = min_t(int, val, INT_MAX / 2);
sk->sk_userlocks |= SOCK_RCVBUF_LOCK; sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
WRITE_ONCE(sk->sk_rcvbuf, WRITE_ONCE(sk->sk_rcvbuf,
max_t(int, val * 2, SOCK_MIN_RCVBUF)); max_t(int, val * 2, SOCK_MIN_RCVBUF));
break; break;
case SO_SNDBUF: case SO_SNDBUF:
val = min_t(u32, val, sysctl_wmem_max); val = min_t(u32, val, READ_ONCE(sysctl_wmem_max));
val = min_t(int, val, INT_MAX / 2); val = min_t(int, val, INT_MAX / 2);
sk->sk_userlocks |= SOCK_SNDBUF_LOCK; sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
WRITE_ONCE(sk->sk_sndbuf, WRITE_ONCE(sk->sk_sndbuf,
......
...@@ -1101,7 +1101,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -1101,7 +1101,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
* play 'guess the biggest size' games. RCVBUF/SNDBUF * play 'guess the biggest size' games. RCVBUF/SNDBUF
* are treated in BSD as hints * are treated in BSD as hints
*/ */
val = min_t(u32, val, sysctl_wmem_max); val = min_t(u32, val, READ_ONCE(sysctl_wmem_max));
set_sndbuf: set_sndbuf:
/* Ensure val * 2 fits into an int, to prevent max_t() /* Ensure val * 2 fits into an int, to prevent max_t()
* from treating it as a negative value. * from treating it as a negative value.
...@@ -1133,7 +1133,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -1133,7 +1133,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
* play 'guess the biggest size' games. RCVBUF/SNDBUF * play 'guess the biggest size' games. RCVBUF/SNDBUF
* are treated in BSD as hints * are treated in BSD as hints
*/ */
__sock_set_rcvbuf(sk, min_t(u32, val, sysctl_rmem_max)); __sock_set_rcvbuf(sk, min_t(u32, val, READ_ONCE(sysctl_rmem_max)));
break; break;
case SO_RCVBUFFORCE: case SO_RCVBUFFORCE:
...@@ -3309,8 +3309,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) ...@@ -3309,8 +3309,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
timer_setup(&sk->sk_timer, NULL, 0); timer_setup(&sk->sk_timer, NULL, 0);
sk->sk_allocation = GFP_KERNEL; sk->sk_allocation = GFP_KERNEL;
sk->sk_rcvbuf = sysctl_rmem_default; sk->sk_rcvbuf = READ_ONCE(sysctl_rmem_default);
sk->sk_sndbuf = sysctl_wmem_default; sk->sk_sndbuf = READ_ONCE(sysctl_wmem_default);
sk->sk_state = TCP_CLOSE; sk->sk_state = TCP_CLOSE;
sk_set_socket(sk, sock); sk_set_socket(sk, sock);
......
...@@ -1730,7 +1730,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, ...@@ -1730,7 +1730,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
sk->sk_protocol = ip_hdr(skb)->protocol; sk->sk_protocol = ip_hdr(skb)->protocol;
sk->sk_bound_dev_if = arg->bound_dev_if; sk->sk_bound_dev_if = arg->bound_dev_if;
sk->sk_sndbuf = sysctl_wmem_default; sk->sk_sndbuf = READ_ONCE(sysctl_wmem_default);
ipc.sockc.mark = fl4.flowi4_mark; ipc.sockc.mark = fl4.flowi4_mark;
err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
len, 0, &ipc, &rt, MSG_DONTWAIT); len, 0, &ipc, &rt, MSG_DONTWAIT);
......
...@@ -239,7 +239,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss, ...@@ -239,7 +239,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss,
if (wscale_ok) { if (wscale_ok) {
/* Set window scaling on max possible window */ /* Set window scaling on max possible window */
space = max_t(u32, space, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2])); space = max_t(u32, space, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
space = max_t(u32, space, sysctl_rmem_max); space = max_t(u32, space, READ_ONCE(sysctl_rmem_max));
space = min_t(u32, space, *window_clamp); space = min_t(u32, space, *window_clamp);
*rcv_wscale = clamp_t(int, ilog2(space) - 15, *rcv_wscale = clamp_t(int, ilog2(space) - 15,
0, TCP_MAX_WSCALE); 0, TCP_MAX_WSCALE);
......
...@@ -1280,12 +1280,12 @@ static void set_sock_size(struct sock *sk, int mode, int val) ...@@ -1280,12 +1280,12 @@ static void set_sock_size(struct sock *sk, int mode, int val)
lock_sock(sk); lock_sock(sk);
if (mode) { if (mode) {
val = clamp_t(int, val, (SOCK_MIN_SNDBUF + 1) / 2, val = clamp_t(int, val, (SOCK_MIN_SNDBUF + 1) / 2,
sysctl_wmem_max); READ_ONCE(sysctl_wmem_max));
sk->sk_sndbuf = val * 2; sk->sk_sndbuf = val * 2;
sk->sk_userlocks |= SOCK_SNDBUF_LOCK; sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
} else { } else {
val = clamp_t(int, val, (SOCK_MIN_RCVBUF + 1) / 2, val = clamp_t(int, val, (SOCK_MIN_RCVBUF + 1) / 2,
sysctl_rmem_max); READ_ONCE(sysctl_rmem_max));
sk->sk_rcvbuf = val * 2; sk->sk_rcvbuf = val * 2;
sk->sk_userlocks |= SOCK_RCVBUF_LOCK; sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
} }
......
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