net: Fix data-races around sysctl_[rw]mem_(max|default).
authorKuniyuki Iwashima <kuniyu@amazon.com>
Tue, 23 Aug 2022 17:46:44 +0000 (10:46 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 24 Aug 2022 12:46:57 +0000 (13:46 +0100)
While reading sysctl_[rw]mem_(max|default), they can be changed
concurrently.  Thus, we need to add READ_ONCE() to its readers.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/filter.c
net/core/sock.c
net/ipv4/ip_output.c
net/ipv4/tcp_output.c
net/netfilter/ipvs/ip_vs_sync.c

index e8508aa..c4f14ad 100644 (file)
@@ -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,
index 4cb957d..303af52 100644 (file)
@@ -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);
 
index d7bd1da..04e2034 100644 (file)
@@ -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);
index 78b654f..290019d 100644 (file)
@@ -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);
index 9d43277..a56fd0b 100644 (file)
@@ -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;
        }