]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: Fix data-races around sysctl_optmem_max.
authorKuniyuki Iwashima <kuniyu@amazon.com>
Tue, 23 Aug 2022 17:46:49 +0000 (10:46 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 31 Aug 2022 15:15:20 +0000 (17:15 +0200)
[ Upstream commit 7de6d09f51917c829af2b835aba8bb5040f8e86a ]

While reading sysctl_optmem_max, it 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/bpf_sk_storage.c
net/core/filter.c
net/core/sock.c
net/ipv4/ip_sockglue.c
net/ipv6/ipv6_sockglue.c

index 39c5a059d1c2bd4f89f6a38c27b2c083267affa4..d67d06d6b817c1de924b4d7d1a86963aa6094507 100644 (file)
@@ -304,11 +304,12 @@ BPF_CALL_2(bpf_sk_storage_delete, struct bpf_map *, map, struct sock *, sk)
 static int sk_storage_charge(struct bpf_local_storage_map *smap,
                             void *owner, u32 size)
 {
+       int optmem_max = READ_ONCE(sysctl_optmem_max);
        struct sock *sk = (struct sock *)owner;
 
        /* same check as in sock_kmalloc() */
-       if (size <= sysctl_optmem_max &&
-           atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) {
+       if (size <= optmem_max &&
+           atomic_read(&sk->sk_omem_alloc) + size < optmem_max) {
                atomic_add(size, &sk->sk_omem_alloc);
                return 0;
        }
index 6a90c1eb6f67e2bc092067a675cc98dc9014decd..4c22e6d1da7466a2e45608119bce34632a899089 100644 (file)
@@ -1212,10 +1212,11 @@ void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
 static bool __sk_filter_charge(struct sock *sk, struct sk_filter *fp)
 {
        u32 filter_size = bpf_prog_size(fp->prog->len);
+       int optmem_max = READ_ONCE(sysctl_optmem_max);
 
        /* same check as in sock_kmalloc() */
-       if (filter_size <= sysctl_optmem_max &&
-           atomic_read(&sk->sk_omem_alloc) + filter_size < sysctl_optmem_max) {
+       if (filter_size <= optmem_max &&
+           atomic_read(&sk->sk_omem_alloc) + filter_size < optmem_max) {
                atomic_add(filter_size, &sk->sk_omem_alloc);
                return true;
        }
@@ -1547,7 +1548,7 @@ int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        if (IS_ERR(prog))
                return PTR_ERR(prog);
 
-       if (bpf_prog_size(prog->len) > sysctl_optmem_max)
+       if (bpf_prog_size(prog->len) > READ_ONCE(sysctl_optmem_max))
                err = -ENOMEM;
        else
                err = reuseport_attach_prog(sk, prog);
@@ -1614,7 +1615,7 @@ int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk)
                }
        } else {
                /* BPF_PROG_TYPE_SOCKET_FILTER */
-               if (bpf_prog_size(prog->len) > sysctl_optmem_max) {
+               if (bpf_prog_size(prog->len) > READ_ONCE(sysctl_optmem_max)) {
                        err = -ENOMEM;
                        goto err_prog_put;
                }
index 25d25dcd0c3dbd711e865dbda82febbdff4ef2ee..f01e71c98d5bee997817458f2d4af1e9c4460830 100644 (file)
@@ -2219,7 +2219,7 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size,
 
        /* small safe race: SKB_TRUESIZE may differ from final skb->truesize */
        if (atomic_read(&sk->sk_omem_alloc) + SKB_TRUESIZE(size) >
-           sysctl_optmem_max)
+           READ_ONCE(sysctl_optmem_max))
                return NULL;
 
        skb = alloc_skb(size, priority);
@@ -2237,8 +2237,10 @@ struct sk_buff *sock_omalloc(struct sock *sk, unsigned long size,
  */
 void *sock_kmalloc(struct sock *sk, int size, gfp_t priority)
 {
-       if ((unsigned int)size <= sysctl_optmem_max &&
-           atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) {
+       int optmem_max = READ_ONCE(sysctl_optmem_max);
+
+       if ((unsigned int)size <= optmem_max &&
+           atomic_read(&sk->sk_omem_alloc) + size < optmem_max) {
                void *mem;
                /* First do the add, to avoid the race if kmalloc
                 * might sleep.
index 22507a6a3f71c50a90a77f2efffe74771fb75602..4cc39c62af55dac53947d5653866f1d680f53956 100644 (file)
@@ -773,7 +773,7 @@ static int ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval, int optlen)
 
        if (optlen < GROUP_FILTER_SIZE(0))
                return -EINVAL;
-       if (optlen > sysctl_optmem_max)
+       if (optlen > READ_ONCE(sysctl_optmem_max))
                return -ENOBUFS;
 
        gsf = memdup_sockptr(optval, optlen);
@@ -808,7 +808,7 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        if (optlen < size0)
                return -EINVAL;
-       if (optlen > sysctl_optmem_max - 4)
+       if (optlen > READ_ONCE(sysctl_optmem_max) - 4)
                return -ENOBUFS;
 
        p = kmalloc(optlen + 4, GFP_KERNEL);
@@ -1231,7 +1231,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname,
 
                if (optlen < IP_MSFILTER_SIZE(0))
                        goto e_inval;
-               if (optlen > sysctl_optmem_max) {
+               if (optlen > READ_ONCE(sysctl_optmem_max)) {
                        err = -ENOBUFS;
                        break;
                }
index 43a894bf9a1be9ba2c31b5f8d3446a6a8dcf6387..6fa118bf40cdde1f852c6213b4b260e07c360180 100644 (file)
@@ -208,7 +208,7 @@ static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        if (optlen < GROUP_FILTER_SIZE(0))
                return -EINVAL;
-       if (optlen > sysctl_optmem_max)
+       if (optlen > READ_ONCE(sysctl_optmem_max))
                return -ENOBUFS;
 
        gsf = memdup_sockptr(optval, optlen);
@@ -242,7 +242,7 @@ static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
 
        if (optlen < size0)
                return -EINVAL;
-       if (optlen > sysctl_optmem_max - 4)
+       if (optlen > READ_ONCE(sysctl_optmem_max) - 4)
                return -ENOBUFS;
 
        p = kmalloc(optlen + 4, GFP_KERNEL);