Commit 6c8774a9 authored by Eric Dumazet's avatar Eric Dumazet Committed by Pablo Neira Ayuso

netfilter: nftables: avoid potential overflows on 32bit arches

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: 0ed6389c ("netfilter: nf_tables: rename set implementations")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent a54754ec
...@@ -4184,6 +4184,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -4184,6 +4184,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
unsigned char *udata; unsigned char *udata;
struct nft_set *set; struct nft_set *set;
struct nft_ctx ctx; struct nft_ctx ctx;
size_t alloc_size;
u64 timeout; u64 timeout;
char *name; char *name;
int err, i; int err, i;
...@@ -4329,8 +4330,10 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -4329,8 +4330,10 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
size = 0; size = 0;
if (ops->privsize != NULL) if (ops->privsize != NULL)
size = ops->privsize(nla, &desc); size = ops->privsize(nla, &desc);
alloc_size = sizeof(*set) + size + udlen;
set = kvzalloc(sizeof(*set) + size + udlen, GFP_KERNEL); if (alloc_size < size)
return -ENOMEM;
set = kvzalloc(alloc_size, GFP_KERNEL);
if (!set) if (!set)
return -ENOMEM; return -ENOMEM;
......
...@@ -623,7 +623,7 @@ static u64 nft_hash_privsize(const struct nlattr * const nla[], ...@@ -623,7 +623,7 @@ static u64 nft_hash_privsize(const struct nlattr * const nla[],
const struct nft_set_desc *desc) const struct nft_set_desc *desc)
{ {
return sizeof(struct nft_hash) + 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, static int nft_hash_init(const struct nft_set *set,
...@@ -663,8 +663,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, ...@@ -663,8 +663,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
return false; return false;
est->size = sizeof(struct nft_hash) + est->size = sizeof(struct nft_hash) +
nft_hash_buckets(desc->size) * sizeof(struct hlist_head) + (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
desc->size * sizeof(struct nft_hash_elem); (u64)desc->size * sizeof(struct nft_hash_elem);
est->lookup = NFT_SET_CLASS_O_1; est->lookup = NFT_SET_CLASS_O_1;
est->space = NFT_SET_CLASS_O_N; est->space = NFT_SET_CLASS_O_N;
...@@ -681,8 +681,8 @@ static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features ...@@ -681,8 +681,8 @@ static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features
return false; return false;
est->size = sizeof(struct nft_hash) + est->size = sizeof(struct nft_hash) +
nft_hash_buckets(desc->size) * sizeof(struct hlist_head) + (u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
desc->size * sizeof(struct nft_hash_elem); (u64)desc->size * sizeof(struct nft_hash_elem);
est->lookup = NFT_SET_CLASS_O_1; est->lookup = NFT_SET_CLASS_O_1;
est->space = NFT_SET_CLASS_O_N; est->space = NFT_SET_CLASS_O_N;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment