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:
Родитель
769b0daf6e
Коммит
26a5d3cc0b
|
@ -99,6 +99,22 @@ struct ip_set_hash {
|
|||
#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 */
|
||||
static u8
|
||||
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;
|
||||
u8 netmask, hbits;
|
||||
size_t hsize;
|
||||
struct ip_set_hash *h;
|
||||
|
||||
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;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
hsize = htable_size(hbits);
|
||||
if (hsize == 0) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -449,6 +449,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
size_t hsize;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
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;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
hsize = htable_size(hbits);
|
||||
if (hsize == 0) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -467,6 +467,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
size_t hsize;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
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;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
hsize = htable_size(hbits);
|
||||
if (hsize == 0) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -616,6 +616,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
size_t hsize;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
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;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
hsize = htable_size(hbits);
|
||||
if (hsize == 0) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
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;
|
||||
struct ip_set_hash *h;
|
||||
u8 hbits;
|
||||
size_t hsize;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
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;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
hsize = htable_size(hbits);
|
||||
if (hsize == 0) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -722,6 +722,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
size_t hsize;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
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;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
hsize = htable_size(hbits);
|
||||
if (hsize == 0) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -572,6 +572,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
size_t hsize;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
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;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
hsize = htable_size(hbits);
|
||||
if (hsize == 0) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
|
|
Загрузка…
Ссылка в новой задаче