aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2012-05-13 21:47:01 -0400
committerDavid S. Miller <davem@davemloft.net>2012-05-16 15:38:49 -0400
commit26a5d3cc0b3d1ff23b5a94edb58226afe7f12a0c (patch)
tree046834414e20d334fc5172275a53c55d9722a714
parent769b0daf6e18a05a6d4da94baab7edd12867350c (diff)
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>
-rw-r--r--include/linux/netfilter/ipset/ip_set_ahash.h16
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c10
8 files changed, 65 insertions, 21 deletions
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h
index 05a5d72680b..230a290e197 100644
--- a/include/linux/netfilter/ipset/ip_set_ahash.h
+++ b/include/linux/netfilter/ipset/ip_set_ahash.h
@@ -99,6 +99,22 @@ struct ip_set_hash {
99#endif 99#endif
100}; 100};
101 101
102static size_t
103htable_size(u8 hbits)
104{
105 size_t hsize;
106
107 /* We must fit both into u32 in jhash and size_t */
108 if (hbits > 31)
109 return 0;
110 hsize = jhash_size(hbits);
111 if ((((size_t)-1) - sizeof(struct htable))/sizeof(struct hbucket)
112 < hsize)
113 return 0;
114
115 return hsize * sizeof(struct hbucket) + sizeof(struct htable);
116}
117
102/* Compute htable_bits from the user input parameter hashsize */ 118/* Compute htable_bits from the user input parameter hashsize */
103static u8 119static u8
104htable_bits(u32 hashsize) 120htable_bits(u32 hashsize)
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index 5139dea6019..828ce46cb34 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -364,6 +364,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
364{ 364{
365 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; 365 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
366 u8 netmask, hbits; 366 u8 netmask, hbits;
367 size_t hsize;
367 struct ip_set_hash *h; 368 struct ip_set_hash *h;
368 369
369 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) 370 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 h->timeout = IPSET_NO_TIMEOUT; 406 h->timeout = IPSET_NO_TIMEOUT;
406 407
407 hbits = htable_bits(hashsize); 408 hbits = htable_bits(hashsize);
408 h->table = ip_set_alloc( 409 hsize = htable_size(hbits);
409 sizeof(struct htable) 410 if (hsize == 0) {
410 + jhash_size(hbits) * sizeof(struct hbucket)); 411 kfree(h);
412 return -ENOMEM;
413 }
414 h->table = ip_set_alloc(hsize);
411 if (!h->table) { 415 if (!h->table) {
412 kfree(h); 416 kfree(h);
413 return -ENOMEM; 417 return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index 9c27e249c17..e8dbb498af8 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -449,6 +449,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
449 struct ip_set_hash *h; 449 struct ip_set_hash *h;
450 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; 450 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
451 u8 hbits; 451 u8 hbits;
452 size_t hsize;
452 453
453 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) 454 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
454 return -IPSET_ERR_INVALID_FAMILY; 455 return -IPSET_ERR_INVALID_FAMILY;
@@ -476,9 +477,12 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
476 h->timeout = IPSET_NO_TIMEOUT; 477 h->timeout = IPSET_NO_TIMEOUT;
477 478
478 hbits = htable_bits(hashsize); 479 hbits = htable_bits(hashsize);
479 h->table = ip_set_alloc( 480 hsize = htable_size(hbits);
480 sizeof(struct htable) 481 if (hsize == 0) {
481 + jhash_size(hbits) * sizeof(struct hbucket)); 482 kfree(h);
483 return -ENOMEM;
484 }
485 h->table = ip_set_alloc(hsize);
482 if (!h->table) { 486 if (!h->table) {
483 kfree(h); 487 kfree(h);
484 return -ENOMEM; 488 return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 9134057c072..52f79d8ef74 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -467,6 +467,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
467 struct ip_set_hash *h; 467 struct ip_set_hash *h;
468 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; 468 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
469 u8 hbits; 469 u8 hbits;
470 size_t hsize;
470 471
471 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) 472 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
472 return -IPSET_ERR_INVALID_FAMILY; 473 return -IPSET_ERR_INVALID_FAMILY;
@@ -494,9 +495,12 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
494 h->timeout = IPSET_NO_TIMEOUT; 495 h->timeout = IPSET_NO_TIMEOUT;
495 496
496 hbits = htable_bits(hashsize); 497 hbits = htable_bits(hashsize);
497 h->table = ip_set_alloc( 498 hsize = htable_size(hbits);
498 sizeof(struct htable) 499 if (hsize == 0) {
499 + jhash_size(hbits) * sizeof(struct hbucket)); 500 kfree(h);
501 return -ENOMEM;
502 }
503 h->table = ip_set_alloc(hsize);
500 if (!h->table) { 504 if (!h->table) {
501 kfree(h); 505 kfree(h);
502 return -ENOMEM; 506 return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 5d05e696986..97583f5af74 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -616,6 +616,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
616 struct ip_set_hash *h; 616 struct ip_set_hash *h;
617 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; 617 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
618 u8 hbits; 618 u8 hbits;
619 size_t hsize;
619 620
620 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) 621 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
621 return -IPSET_ERR_INVALID_FAMILY; 622 return -IPSET_ERR_INVALID_FAMILY;
@@ -645,9 +646,12 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
645 h->timeout = IPSET_NO_TIMEOUT; 646 h->timeout = IPSET_NO_TIMEOUT;
646 647
647 hbits = htable_bits(hashsize); 648 hbits = htable_bits(hashsize);
648 h->table = ip_set_alloc( 649 hsize = htable_size(hbits);
649 sizeof(struct htable) 650 if (hsize == 0) {
650 + jhash_size(hbits) * sizeof(struct hbucket)); 651 kfree(h);
652 return -ENOMEM;
653 }
654 h->table = ip_set_alloc(hsize);
651 if (!h->table) { 655 if (!h->table) {
652 kfree(h); 656 kfree(h);
653 return -ENOMEM; 657 return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
index 7c3d945517c..1721cdecc9f 100644
--- a/net/netfilter/ipset/ip_set_hash_net.c
+++ b/net/netfilter/ipset/ip_set_hash_net.c
@@ -460,6 +460,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
460 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; 460 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
461 struct ip_set_hash *h; 461 struct ip_set_hash *h;
462 u8 hbits; 462 u8 hbits;
463 size_t hsize;
463 464
464 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) 465 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
465 return -IPSET_ERR_INVALID_FAMILY; 466 return -IPSET_ERR_INVALID_FAMILY;
@@ -489,9 +490,12 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
489 h->timeout = IPSET_NO_TIMEOUT; 490 h->timeout = IPSET_NO_TIMEOUT;
490 491
491 hbits = htable_bits(hashsize); 492 hbits = htable_bits(hashsize);
492 h->table = ip_set_alloc( 493 hsize = htable_size(hbits);
493 sizeof(struct htable) 494 if (hsize == 0) {
494 + jhash_size(hbits) * sizeof(struct hbucket)); 495 kfree(h);
496 return -ENOMEM;
497 }
498 h->table = ip_set_alloc(hsize);
495 if (!h->table) { 499 if (!h->table) {
496 kfree(h); 500 kfree(h);
497 return -ENOMEM; 501 return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index f24037ff432..33bafc97ca6 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -722,6 +722,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
722 struct ip_set_hash *h; 722 struct ip_set_hash *h;
723 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; 723 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
724 u8 hbits; 724 u8 hbits;
725 size_t hsize;
725 726
726 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) 727 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
727 return -IPSET_ERR_INVALID_FAMILY; 728 return -IPSET_ERR_INVALID_FAMILY;
@@ -752,9 +753,12 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
752 h->ahash_max = AHASH_MAX_SIZE; 753 h->ahash_max = AHASH_MAX_SIZE;
753 754
754 hbits = htable_bits(hashsize); 755 hbits = htable_bits(hashsize);
755 h->table = ip_set_alloc( 756 hsize = htable_size(hbits);
756 sizeof(struct htable) 757 if (hsize == 0) {
757 + jhash_size(hbits) * sizeof(struct hbucket)); 758 kfree(h);
759 return -ENOMEM;
760 }
761 h->table = ip_set_alloc(hsize);
758 if (!h->table) { 762 if (!h->table) {
759 kfree(h); 763 kfree(h);
760 return -ENOMEM; 764 return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index ce2e77100b6..3a5e198641d 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -572,6 +572,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
572 struct ip_set_hash *h; 572 struct ip_set_hash *h;
573 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; 573 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
574 u8 hbits; 574 u8 hbits;
575 size_t hsize;
575 576
576 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) 577 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
577 return -IPSET_ERR_INVALID_FAMILY; 578 return -IPSET_ERR_INVALID_FAMILY;
@@ -601,9 +602,12 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
601 h->timeout = IPSET_NO_TIMEOUT; 602 h->timeout = IPSET_NO_TIMEOUT;
602 603
603 hbits = htable_bits(hashsize); 604 hbits = htable_bits(hashsize);
604 h->table = ip_set_alloc( 605 hsize = htable_size(hbits);
605 sizeof(struct htable) 606 if (hsize == 0) {
606 + jhash_size(hbits) * sizeof(struct hbucket)); 607 kfree(h);
608 return -ENOMEM;
609 }
610 h->table = ip_set_alloc(hsize);
607 if (!h->table) { 611 if (!h->table) {
608 kfree(h); 612 kfree(h);
609 return -ENOMEM; 613 return -ENOMEM;