Commit 26a5d3cc authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by David S. Miller

netfilter: ipset: fix hash size checking in kernel

The hash size must fit both into u32 (jhash) and the max value of
size_t. The missing checking could lead to kernel crash, bug reported
by Seblu.
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 769b0daf
...@@ -99,6 +99,22 @@ struct ip_set_hash { ...@@ -99,6 +99,22 @@ struct ip_set_hash {
#endif #endif
}; };
static size_t
htable_size(u8 hbits)
{
size_t hsize;
/* We must fit both into u32 in jhash and size_t */
if (hbits > 31)
return 0;
hsize = jhash_size(hbits);
if ((((size_t)-1) - sizeof(struct htable))/sizeof(struct hbucket)
< hsize)
return 0;
return hsize * sizeof(struct hbucket) + sizeof(struct htable);
}
/* Compute htable_bits from the user input parameter hashsize */ /* Compute htable_bits from the user input parameter hashsize */
static u8 static u8
htable_bits(u32 hashsize) htable_bits(u32 hashsize)
......
...@@ -364,6 +364,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -364,6 +364,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{ {
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 netmask, hbits; u8 netmask, hbits;
size_t hsize;
struct ip_set_hash *h; struct ip_set_hash *h;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
...@@ -405,9 +406,12 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -405,9 +406,12 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h->timeout = IPSET_NO_TIMEOUT; h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( hsize = htable_size(hbits);
sizeof(struct htable) if (hsize == 0) {
+ jhash_size(hbits) * sizeof(struct hbucket)); kfree(h);
return -ENOMEM;
}
h->table = ip_set_alloc(hsize);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
......
...@@ -449,6 +449,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -449,6 +449,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
struct ip_set_hash *h; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
size_t hsize;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
...@@ -476,9 +477,12 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -476,9 +477,12 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h->timeout = IPSET_NO_TIMEOUT; h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( hsize = htable_size(hbits);
sizeof(struct htable) if (hsize == 0) {
+ jhash_size(hbits) * sizeof(struct hbucket)); kfree(h);
return -ENOMEM;
}
h->table = ip_set_alloc(hsize);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
......
...@@ -467,6 +467,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -467,6 +467,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
struct ip_set_hash *h; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
size_t hsize;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
...@@ -494,9 +495,12 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -494,9 +495,12 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h->timeout = IPSET_NO_TIMEOUT; h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( hsize = htable_size(hbits);
sizeof(struct htable) if (hsize == 0) {
+ jhash_size(hbits) * sizeof(struct hbucket)); kfree(h);
return -ENOMEM;
}
h->table = ip_set_alloc(hsize);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
......
...@@ -616,6 +616,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -616,6 +616,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
struct ip_set_hash *h; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
size_t hsize;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
...@@ -645,9 +646,12 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -645,9 +646,12 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h->timeout = IPSET_NO_TIMEOUT; h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( hsize = htable_size(hbits);
sizeof(struct htable) if (hsize == 0) {
+ jhash_size(hbits) * sizeof(struct hbucket)); kfree(h);
return -ENOMEM;
}
h->table = ip_set_alloc(hsize);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
......
...@@ -460,6 +460,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -460,6 +460,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
struct ip_set_hash *h; struct ip_set_hash *h;
u8 hbits; u8 hbits;
size_t hsize;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
...@@ -489,9 +490,12 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -489,9 +490,12 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h->timeout = IPSET_NO_TIMEOUT; h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( hsize = htable_size(hbits);
sizeof(struct htable) if (hsize == 0) {
+ jhash_size(hbits) * sizeof(struct hbucket)); kfree(h);
return -ENOMEM;
}
h->table = ip_set_alloc(hsize);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
......
...@@ -722,6 +722,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -722,6 +722,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
struct ip_set_hash *h; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
size_t hsize;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
...@@ -752,9 +753,12 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -752,9 +753,12 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h->ahash_max = AHASH_MAX_SIZE; h->ahash_max = AHASH_MAX_SIZE;
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( hsize = htable_size(hbits);
sizeof(struct htable) if (hsize == 0) {
+ jhash_size(hbits) * sizeof(struct hbucket)); kfree(h);
return -ENOMEM;
}
h->table = ip_set_alloc(hsize);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
......
...@@ -572,6 +572,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -572,6 +572,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
struct ip_set_hash *h; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
size_t hsize;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
...@@ -601,9 +602,12 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -601,9 +602,12 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h->timeout = IPSET_NO_TIMEOUT; h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( hsize = htable_size(hbits);
sizeof(struct htable) if (hsize == 0) {
+ jhash_size(hbits) * sizeof(struct hbucket)); kfree(h);
return -ENOMEM;
}
h->table = ip_set_alloc(hsize);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
......
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