]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 31 Aug 2022 15:18:08 +0000 (17:18 +0200)
[ Upstream commit 1227c1771dd2ad44318aa3ab9e3a293b3f34ff2a ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
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 74f05ed6aff29a8197e1135daf6d7ab5f2bea560..60c854e7d98ba9cc071035d6e5b68f8d68f1c3bb 100644 (file)
@@ -5036,14 +5036,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 2ff40dd0a7a652029cca1743109286b50c2a17f3..62f69bc3a0e6e0b70a301cea5024ee6c213be3b6 100644 (file)
@@ -1100,7 +1100,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.
@@ -1132,7 +1132,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:
@@ -3307,8 +3307,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 00b4bf26fd932b5043b23ca3bbc32823dd5c74c7..da8b3cc67234d891be8ec39b7db44c809a1a101c 100644 (file)
@@ -1712,7 +1712,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 aed0c5f828bef3a9916d729300c814413142e211..84314de754f875b3e9a58093296c6dd1961f1066 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 9d43277b8b4fec1bb3da9993c33a3605f966ae38..a56fd0b5a430af283d02e25a365a49edfd0e4d65 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;
        }