]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
netfilter: nftables: avoid potential overflows on 32bit arches
authorEric Dumazet <edumazet@google.com>
Thu, 9 Sep 2021 14:03:35 +0000 (16:03 +0200)
committerStefan Bader <stefan.bader@canonical.com>
Fri, 15 Oct 2021 09:26:02 +0000 (11:26 +0200)
BugLink: https://bugs.launchpad.net/bugs/1945353
commit 6c8774a94e6ad26f29ef103c8671f55c255c6201 upstream.

User space could ask for very large hash tables, we need to make sure
our size computations wont overflow.

nf_tables_newset() needs to double check the u64 size
will fit into size_t field.

Fixes: 0ed6389c483d ("netfilter: nf_tables: rename set implementations")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
net/netfilter/nf_tables_api.c
net/netfilter/nft_set_hash.c

index 9861a0312ddf7a68d34dd8671ef9a7651c6de9ba..3493423e44dc8f9648907b0442419d1f00e8fa10 100644 (file)
@@ -4129,6 +4129,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
        struct nft_table *table;
        struct nft_set *set;
        struct nft_ctx ctx;
+       size_t alloc_size;
        char *name;
        u64 size;
        u64 timeout;
@@ -4277,8 +4278,10 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
        size = 0;
        if (ops->privsize != NULL)
                size = ops->privsize(nla, &desc);
-
-       set = kvzalloc(sizeof(*set) + size + udlen, GFP_KERNEL);
+       alloc_size = sizeof(*set) + size + udlen;
+       if (alloc_size < size)
+               return -ENOMEM;
+       set = kvzalloc(alloc_size, GFP_KERNEL);
        if (!set)
                return -ENOMEM;
 
index 560c2cda52ee373d1d069193f03aaa6fa3059abc..2a05d2ebc766661975d86710ad4367f61954f432 100644 (file)
@@ -617,7 +617,7 @@ static u64 nft_hash_privsize(const struct nlattr * const nla[],
                             const struct nft_set_desc *desc)
 {
        return sizeof(struct nft_hash) +
-              nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
+              (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
 }
 
 static int nft_hash_init(const struct nft_set *set,
@@ -657,8 +657,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
                return false;
 
        est->size   = sizeof(struct nft_hash) +
-                     nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
-                     desc->size * sizeof(struct nft_hash_elem);
+                     (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
+                     (u64)desc->size * sizeof(struct nft_hash_elem);
        est->lookup = NFT_SET_CLASS_O_1;
        est->space  = NFT_SET_CLASS_O_N;
 
@@ -675,8 +675,8 @@ static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features
                return false;
 
        est->size   = sizeof(struct nft_hash) +
-                     nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
-                     desc->size * sizeof(struct nft_hash_elem);
+                     (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
+                     (u64)desc->size * sizeof(struct nft_hash_elem);
        est->lookup = NFT_SET_CLASS_O_1;
        est->space  = NFT_SET_CLASS_O_N;