diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2013-04-30 15:23:18 -0400 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2013-09-30 15:33:25 -0400 |
commit | a0f28dc754bb6e78158eb41bf729342f7c2bcd70 (patch) | |
tree | b8ccf07c6f87131c35705a19a0161f5ebbb2edfc | |
parent | b3aabd149c201a7c2a5f9ee673376948ae0724d8 (diff) |
netfilter: ipset: Fix sparse warnings due to missing rcu annotations
Reported-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_gen.h | 87 |
1 files changed, 55 insertions, 32 deletions
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 7ff20ecbe185..09a21dd5f120 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h | |||
@@ -15,6 +15,8 @@ | |||
15 | #define rcu_dereference_bh(p) rcu_dereference(p) | 15 | #define rcu_dereference_bh(p) rcu_dereference(p) |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | #define rcu_dereference_bh_nfnl(p) rcu_dereference_bh_check(p, 1) | ||
19 | |||
18 | #define CONCAT(a, b) a##b | 20 | #define CONCAT(a, b) a##b |
19 | #define TOKEN(a, b) CONCAT(a, b) | 21 | #define TOKEN(a, b) CONCAT(a, b) |
20 | 22 | ||
@@ -269,7 +271,7 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) | |||
269 | 271 | ||
270 | /* The generic hash structure */ | 272 | /* The generic hash structure */ |
271 | struct htype { | 273 | struct htype { |
272 | struct htable *table; /* the hash table */ | 274 | struct htable __rcu *table; /* the hash table */ |
273 | u32 maxelem; /* max elements in the hash */ | 275 | u32 maxelem; /* max elements in the hash */ |
274 | u32 elements; /* current element (vs timeout) */ | 276 | u32 elements; /* current element (vs timeout) */ |
275 | u32 initval; /* random jhash init value */ | 277 | u32 initval; /* random jhash init value */ |
@@ -347,10 +349,10 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length) | |||
347 | 349 | ||
348 | /* Calculate the actual memory size of the set data */ | 350 | /* Calculate the actual memory size of the set data */ |
349 | static size_t | 351 | static size_t |
350 | mtype_ahash_memsize(const struct htype *h, u8 nets_length) | 352 | mtype_ahash_memsize(const struct htype *h, const struct htable *t, |
353 | u8 nets_length) | ||
351 | { | 354 | { |
352 | u32 i; | 355 | u32 i; |
353 | struct htable *t = h->table; | ||
354 | size_t memsize = sizeof(*h) | 356 | size_t memsize = sizeof(*h) |
355 | + sizeof(*t) | 357 | + sizeof(*t) |
356 | #ifdef IP_SET_HASH_WITH_NETS | 358 | #ifdef IP_SET_HASH_WITH_NETS |
@@ -369,10 +371,11 @@ static void | |||
369 | mtype_flush(struct ip_set *set) | 371 | mtype_flush(struct ip_set *set) |
370 | { | 372 | { |
371 | struct htype *h = set->data; | 373 | struct htype *h = set->data; |
372 | struct htable *t = h->table; | 374 | struct htable *t; |
373 | struct hbucket *n; | 375 | struct hbucket *n; |
374 | u32 i; | 376 | u32 i; |
375 | 377 | ||
378 | t = rcu_dereference_bh_nfnl(h->table); | ||
376 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | 379 | for (i = 0; i < jhash_size(t->htable_bits); i++) { |
377 | n = hbucket(t, i); | 380 | n = hbucket(t, i); |
378 | if (n->size) { | 381 | if (n->size) { |
@@ -397,7 +400,7 @@ mtype_destroy(struct ip_set *set) | |||
397 | if (set->extensions & IPSET_EXT_TIMEOUT) | 400 | if (set->extensions & IPSET_EXT_TIMEOUT) |
398 | del_timer_sync(&h->gc); | 401 | del_timer_sync(&h->gc); |
399 | 402 | ||
400 | ahash_destroy(h->table); | 403 | ahash_destroy(rcu_dereference_bh_nfnl(h->table)); |
401 | #ifdef IP_SET_HASH_WITH_RBTREE | 404 | #ifdef IP_SET_HASH_WITH_RBTREE |
402 | rbtree_destroy(&h->rbtree); | 405 | rbtree_destroy(&h->rbtree); |
403 | #endif | 406 | #endif |
@@ -443,12 +446,14 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b) | |||
443 | static void | 446 | static void |
444 | mtype_expire(struct htype *h, u8 nets_length, size_t dsize) | 447 | mtype_expire(struct htype *h, u8 nets_length, size_t dsize) |
445 | { | 448 | { |
446 | struct htable *t = h->table; | 449 | struct htable *t; |
447 | struct hbucket *n; | 450 | struct hbucket *n; |
448 | struct mtype_elem *data; | 451 | struct mtype_elem *data; |
449 | u32 i; | 452 | u32 i; |
450 | int j; | 453 | int j; |
451 | 454 | ||
455 | rcu_read_lock_bh(); | ||
456 | t = rcu_dereference_bh(h->table); | ||
452 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | 457 | for (i = 0; i < jhash_size(t->htable_bits); i++) { |
453 | n = hbucket(t, i); | 458 | n = hbucket(t, i); |
454 | for (j = 0; j < n->pos; j++) { | 459 | for (j = 0; j < n->pos; j++) { |
@@ -481,6 +486,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize) | |||
481 | n->value = tmp; | 486 | n->value = tmp; |
482 | } | 487 | } |
483 | } | 488 | } |
489 | rcu_read_unlock_bh(); | ||
484 | } | 490 | } |
485 | 491 | ||
486 | static void | 492 | static void |
@@ -505,7 +511,7 @@ static int | |||
505 | mtype_resize(struct ip_set *set, bool retried) | 511 | mtype_resize(struct ip_set *set, bool retried) |
506 | { | 512 | { |
507 | struct htype *h = set->data; | 513 | struct htype *h = set->data; |
508 | struct htable *t, *orig = h->table; | 514 | struct htable *t, *orig = rcu_dereference_bh_nfnl(h->table); |
509 | u8 htable_bits = orig->htable_bits; | 515 | u8 htable_bits = orig->htable_bits; |
510 | #ifdef IP_SET_HASH_WITH_NETS | 516 | #ifdef IP_SET_HASH_WITH_NETS |
511 | u8 flags; | 517 | u8 flags; |
@@ -682,13 +688,15 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
682 | struct ip_set_ext *mext, u32 flags) | 688 | struct ip_set_ext *mext, u32 flags) |
683 | { | 689 | { |
684 | struct htype *h = set->data; | 690 | struct htype *h = set->data; |
685 | struct htable *t = h->table; | 691 | struct htable *t; |
686 | const struct mtype_elem *d = value; | 692 | const struct mtype_elem *d = value; |
687 | struct mtype_elem *data; | 693 | struct mtype_elem *data; |
688 | struct hbucket *n; | 694 | struct hbucket *n; |
689 | int i; | 695 | int i, ret = -IPSET_ERR_EXIST; |
690 | u32 key, multi = 0; | 696 | u32 key, multi = 0; |
691 | 697 | ||
698 | rcu_read_lock_bh(); | ||
699 | t = rcu_dereference_bh(h->table); | ||
692 | key = HKEY(value, h->initval, t->htable_bits); | 700 | key = HKEY(value, h->initval, t->htable_bits); |
693 | n = hbucket(t, key); | 701 | n = hbucket(t, key); |
694 | for (i = 0; i < n->pos; i++) { | 702 | for (i = 0; i < n->pos; i++) { |
@@ -697,7 +705,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
697 | continue; | 705 | continue; |
698 | if (SET_WITH_TIMEOUT(set) && | 706 | if (SET_WITH_TIMEOUT(set) && |
699 | ip_set_timeout_expired(ext_timeout(data, h))) | 707 | ip_set_timeout_expired(ext_timeout(data, h))) |
700 | return -IPSET_ERR_EXIST; | 708 | goto out; |
701 | if (i != n->pos - 1) | 709 | if (i != n->pos - 1) |
702 | /* Not last one */ | 710 | /* Not last one */ |
703 | memcpy(data, ahash_data(n, n->pos - 1, h->dsize), | 711 | memcpy(data, ahash_data(n, n->pos - 1, h->dsize), |
@@ -712,17 +720,22 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
712 | void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) | 720 | void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) |
713 | * h->dsize, | 721 | * h->dsize, |
714 | GFP_ATOMIC); | 722 | GFP_ATOMIC); |
715 | if (!tmp) | 723 | if (!tmp) { |
716 | return 0; | 724 | ret = 0; |
725 | goto out; | ||
726 | } | ||
717 | n->size -= AHASH_INIT_SIZE; | 727 | n->size -= AHASH_INIT_SIZE; |
718 | memcpy(tmp, n->value, n->size * h->dsize); | 728 | memcpy(tmp, n->value, n->size * h->dsize); |
719 | kfree(n->value); | 729 | kfree(n->value); |
720 | n->value = tmp; | 730 | n->value = tmp; |
721 | } | 731 | } |
722 | return 0; | 732 | ret = 0; |
733 | goto out; | ||
723 | } | 734 | } |
724 | 735 | ||
725 | return -IPSET_ERR_EXIST; | 736 | out: |
737 | rcu_read_unlock_bh(); | ||
738 | return ret; | ||
726 | } | 739 | } |
727 | 740 | ||
728 | static inline int | 741 | static inline int |
@@ -745,7 +758,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, | |||
745 | struct ip_set_ext *mext, u32 flags) | 758 | struct ip_set_ext *mext, u32 flags) |
746 | { | 759 | { |
747 | struct htype *h = set->data; | 760 | struct htype *h = set->data; |
748 | struct htable *t = h->table; | 761 | struct htable *t = rcu_dereference_bh(h->table); |
749 | struct hbucket *n; | 762 | struct hbucket *n; |
750 | struct mtype_elem *data; | 763 | struct mtype_elem *data; |
751 | int i, j = 0; | 764 | int i, j = 0; |
@@ -785,18 +798,22 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
785 | struct ip_set_ext *mext, u32 flags) | 798 | struct ip_set_ext *mext, u32 flags) |
786 | { | 799 | { |
787 | struct htype *h = set->data; | 800 | struct htype *h = set->data; |
788 | struct htable *t = h->table; | 801 | struct htable *t; |
789 | struct mtype_elem *d = value; | 802 | struct mtype_elem *d = value; |
790 | struct hbucket *n; | 803 | struct hbucket *n; |
791 | struct mtype_elem *data; | 804 | struct mtype_elem *data; |
792 | int i; | 805 | int i, ret = 0; |
793 | u32 key, multi = 0; | 806 | u32 key, multi = 0; |
794 | 807 | ||
808 | rcu_read_lock_bh(); | ||
809 | t = rcu_dereference_bh(h->table); | ||
795 | #ifdef IP_SET_HASH_WITH_NETS | 810 | #ifdef IP_SET_HASH_WITH_NETS |
796 | /* If we test an IP address and not a network address, | 811 | /* If we test an IP address and not a network address, |
797 | * try all possible network sizes */ | 812 | * try all possible network sizes */ |
798 | if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) | 813 | if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) { |
799 | return mtype_test_cidrs(set, d, ext, mext, flags); | 814 | ret = mtype_test_cidrs(set, d, ext, mext, flags); |
815 | goto out; | ||
816 | } | ||
800 | #endif | 817 | #endif |
801 | 818 | ||
802 | key = HKEY(d, h->initval, t->htable_bits); | 819 | key = HKEY(d, h->initval, t->htable_bits); |
@@ -805,10 +822,14 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
805 | data = ahash_data(n, i, h->dsize); | 822 | data = ahash_data(n, i, h->dsize); |
806 | if (mtype_data_equal(data, d, &multi) && | 823 | if (mtype_data_equal(data, d, &multi) && |
807 | !(SET_WITH_TIMEOUT(set) && | 824 | !(SET_WITH_TIMEOUT(set) && |
808 | ip_set_timeout_expired(ext_timeout(data, h)))) | 825 | ip_set_timeout_expired(ext_timeout(data, h)))) { |
809 | return mtype_data_match(data, ext, mext, set, flags); | 826 | ret = mtype_data_match(data, ext, mext, set, flags); |
827 | goto out; | ||
828 | } | ||
810 | } | 829 | } |
811 | return 0; | 830 | out: |
831 | rcu_read_unlock_bh(); | ||
832 | return ret; | ||
812 | } | 833 | } |
813 | 834 | ||
814 | /* Reply a HEADER request: fill out the header part of the set */ | 835 | /* Reply a HEADER request: fill out the header part of the set */ |
@@ -816,18 +837,18 @@ static int | |||
816 | mtype_head(struct ip_set *set, struct sk_buff *skb) | 837 | mtype_head(struct ip_set *set, struct sk_buff *skb) |
817 | { | 838 | { |
818 | const struct htype *h = set->data; | 839 | const struct htype *h = set->data; |
840 | const struct htable *t; | ||
819 | struct nlattr *nested; | 841 | struct nlattr *nested; |
820 | size_t memsize; | 842 | size_t memsize; |
821 | 843 | ||
822 | read_lock_bh(&set->lock); | 844 | t = rcu_dereference_bh_nfnl(h->table); |
823 | memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family)); | 845 | memsize = mtype_ahash_memsize(h, t, NETS_LENGTH(set->family)); |
824 | read_unlock_bh(&set->lock); | ||
825 | 846 | ||
826 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | 847 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); |
827 | if (!nested) | 848 | if (!nested) |
828 | goto nla_put_failure; | 849 | goto nla_put_failure; |
829 | if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE, | 850 | if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE, |
830 | htonl(jhash_size(h->table->htable_bits))) || | 851 | htonl(jhash_size(t->htable_bits))) || |
831 | nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem))) | 852 | nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem))) |
832 | goto nla_put_failure; | 853 | goto nla_put_failure; |
833 | #ifdef IP_SET_HASH_WITH_NETMASK | 854 | #ifdef IP_SET_HASH_WITH_NETMASK |
@@ -856,7 +877,7 @@ mtype_list(const struct ip_set *set, | |||
856 | struct sk_buff *skb, struct netlink_callback *cb) | 877 | struct sk_buff *skb, struct netlink_callback *cb) |
857 | { | 878 | { |
858 | const struct htype *h = set->data; | 879 | const struct htype *h = set->data; |
859 | const struct htable *t = h->table; | 880 | const struct htable *t = rcu_dereference_bh_nfnl(h->table); |
860 | struct nlattr *atd, *nested; | 881 | struct nlattr *atd, *nested; |
861 | const struct hbucket *n; | 882 | const struct hbucket *n; |
862 | const struct mtype_elem *e; | 883 | const struct mtype_elem *e; |
@@ -956,6 +977,7 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
956 | #endif | 977 | #endif |
957 | size_t hsize; | 978 | size_t hsize; |
958 | struct HTYPE *h; | 979 | struct HTYPE *h; |
980 | struct htable *t; | ||
959 | 981 | ||
960 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) | 982 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
961 | return -IPSET_ERR_INVALID_FAMILY; | 983 | return -IPSET_ERR_INVALID_FAMILY; |
@@ -1013,12 +1035,13 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
1013 | kfree(h); | 1035 | kfree(h); |
1014 | return -ENOMEM; | 1036 | return -ENOMEM; |
1015 | } | 1037 | } |
1016 | h->table = ip_set_alloc(hsize); | 1038 | t = ip_set_alloc(hsize); |
1017 | if (!h->table) { | 1039 | if (!t) { |
1018 | kfree(h); | 1040 | kfree(h); |
1019 | return -ENOMEM; | 1041 | return -ENOMEM; |
1020 | } | 1042 | } |
1021 | h->table->htable_bits = hbits; | 1043 | t->htable_bits = hbits; |
1044 | rcu_assign_pointer(h->table, t); | ||
1022 | 1045 | ||
1023 | set->data = h; | 1046 | set->data = h; |
1024 | if (set->family == NFPROTO_IPV4) | 1047 | if (set->family == NFPROTO_IPV4) |
@@ -1096,8 +1119,8 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
1096 | } | 1119 | } |
1097 | 1120 | ||
1098 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", | 1121 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", |
1099 | set->name, jhash_size(h->table->htable_bits), | 1122 | set->name, jhash_size(t->htable_bits), |
1100 | h->table->htable_bits, h->maxelem, set->data, h->table); | 1123 | t->htable_bits, h->maxelem, set->data, t); |
1101 | 1124 | ||
1102 | return 0; | 1125 | return 0; |
1103 | } | 1126 | } |