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: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
769b0daf6e
commit
26a5d3cc0b
@@ -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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user