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: 1da177e4c3
("Linux-2.6.12-rc2")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c624c58e08
commit
1227c1771d
@ -5034,14 +5034,14 @@ static int __bpf_setsockopt(struct sock *sk, int level, int optname,
|
||||
/* Only some socketops are supported */
|
||||
switch (optname) {
|
||||
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);
|
||||
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
|
||||
WRITE_ONCE(sk->sk_rcvbuf,
|
||||
max_t(int, val * 2, SOCK_MIN_RCVBUF));
|
||||
break;
|
||||
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);
|
||||
sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
|
||||
WRITE_ONCE(sk->sk_sndbuf,
|
||||
|
@ -1101,7 +1101,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
* play 'guess the biggest size' games. RCVBUF/SNDBUF
|
||||
* 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:
|
||||
/* Ensure val * 2 fits into an int, to prevent max_t()
|
||||
* from treating it as a negative value.
|
||||
@ -1133,7 +1133,7 @@ set_sndbuf:
|
||||
* play 'guess the biggest size' games. RCVBUF/SNDBUF
|
||||
* 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;
|
||||
|
||||
case SO_RCVBUFFORCE:
|
||||
@ -3309,8 +3309,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
|
||||
timer_setup(&sk->sk_timer, NULL, 0);
|
||||
|
||||
sk->sk_allocation = GFP_KERNEL;
|
||||
sk->sk_rcvbuf = sysctl_rmem_default;
|
||||
sk->sk_sndbuf = sysctl_wmem_default;
|
||||
sk->sk_rcvbuf = READ_ONCE(sysctl_rmem_default);
|
||||
sk->sk_sndbuf = READ_ONCE(sysctl_wmem_default);
|
||||
sk->sk_state = TCP_CLOSE;
|
||||
sk_set_socket(sk, sock);
|
||||
|
||||
|
@ -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_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;
|
||||
err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
|
||||
len, 0, &ipc, &rt, MSG_DONTWAIT);
|
||||
|
@ -239,7 +239,7 @@ void tcp_select_initial_window(const struct sock *sk, int __space, __u32 mss,
|
||||
if (wscale_ok) {
|
||||
/* 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, sysctl_rmem_max);
|
||||
space = max_t(u32, space, READ_ONCE(sysctl_rmem_max));
|
||||
space = min_t(u32, space, *window_clamp);
|
||||
*rcv_wscale = clamp_t(int, ilog2(space) - 15,
|
||||
0, TCP_MAX_WSCALE);
|
||||
|
@ -1280,12 +1280,12 @@ static void set_sock_size(struct sock *sk, int mode, int val)
|
||||
lock_sock(sk);
|
||||
if (mode) {
|
||||
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_userlocks |= SOCK_SNDBUF_LOCK;
|
||||
} else {
|
||||
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_userlocks |= SOCK_RCVBUF_LOCK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user