Commit a0f28dc7 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik

netfilter: ipset: Fix sparse warnings due to missing rcu annotations

Reported-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
parent b3aabd14
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#define rcu_dereference_bh(p) rcu_dereference(p) #define rcu_dereference_bh(p) rcu_dereference(p)
#endif #endif
#define rcu_dereference_bh_nfnl(p) rcu_dereference_bh_check(p, 1)
#define CONCAT(a, b) a##b #define CONCAT(a, b) a##b
#define TOKEN(a, b) CONCAT(a, b) #define TOKEN(a, b) CONCAT(a, b)
...@@ -269,7 +271,7 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) ...@@ -269,7 +271,7 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
/* The generic hash structure */ /* The generic hash structure */
struct htype { struct htype {
struct htable *table; /* the hash table */ struct htable __rcu *table; /* the hash table */
u32 maxelem; /* max elements in the hash */ u32 maxelem; /* max elements in the hash */
u32 elements; /* current element (vs timeout) */ u32 elements; /* current element (vs timeout) */
u32 initval; /* random jhash init value */ u32 initval; /* random jhash init value */
...@@ -347,10 +349,10 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length) ...@@ -347,10 +349,10 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
/* Calculate the actual memory size of the set data */ /* Calculate the actual memory size of the set data */
static size_t static size_t
mtype_ahash_memsize(const struct htype *h, u8 nets_length) mtype_ahash_memsize(const struct htype *h, const struct htable *t,
u8 nets_length)
{ {
u32 i; u32 i;
struct htable *t = h->table;
size_t memsize = sizeof(*h) size_t memsize = sizeof(*h)
+ sizeof(*t) + sizeof(*t)
#ifdef IP_SET_HASH_WITH_NETS #ifdef IP_SET_HASH_WITH_NETS
...@@ -369,10 +371,11 @@ static void ...@@ -369,10 +371,11 @@ static void
mtype_flush(struct ip_set *set) mtype_flush(struct ip_set *set)
{ {
struct htype *h = set->data; struct htype *h = set->data;
struct htable *t = h->table; struct htable *t;
struct hbucket *n; struct hbucket *n;
u32 i; u32 i;
t = rcu_dereference_bh_nfnl(h->table);
for (i = 0; i < jhash_size(t->htable_bits); i++) { for (i = 0; i < jhash_size(t->htable_bits); i++) {
n = hbucket(t, i); n = hbucket(t, i);
if (n->size) { if (n->size) {
...@@ -397,7 +400,7 @@ mtype_destroy(struct ip_set *set) ...@@ -397,7 +400,7 @@ mtype_destroy(struct ip_set *set)
if (set->extensions & IPSET_EXT_TIMEOUT) if (set->extensions & IPSET_EXT_TIMEOUT)
del_timer_sync(&h->gc); del_timer_sync(&h->gc);
ahash_destroy(h->table); ahash_destroy(rcu_dereference_bh_nfnl(h->table));
#ifdef IP_SET_HASH_WITH_RBTREE #ifdef IP_SET_HASH_WITH_RBTREE
rbtree_destroy(&h->rbtree); rbtree_destroy(&h->rbtree);
#endif #endif
...@@ -443,12 +446,14 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b) ...@@ -443,12 +446,14 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
static void static void
mtype_expire(struct htype *h, u8 nets_length, size_t dsize) mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
{ {
struct htable *t = h->table; struct htable *t;
struct hbucket *n; struct hbucket *n;
struct mtype_elem *data; struct mtype_elem *data;
u32 i; u32 i;
int j; int j;
rcu_read_lock_bh();
t = rcu_dereference_bh(h->table);
for (i = 0; i < jhash_size(t->htable_bits); i++) { for (i = 0; i < jhash_size(t->htable_bits); i++) {
n = hbucket(t, i); n = hbucket(t, i);
for (j = 0; j < n->pos; j++) { for (j = 0; j < n->pos; j++) {
...@@ -481,6 +486,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize) ...@@ -481,6 +486,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
n->value = tmp; n->value = tmp;
} }
} }
rcu_read_unlock_bh();
} }
static void static void
...@@ -505,7 +511,7 @@ static int ...@@ -505,7 +511,7 @@ static int
mtype_resize(struct ip_set *set, bool retried) mtype_resize(struct ip_set *set, bool retried)
{ {
struct htype *h = set->data; struct htype *h = set->data;
struct htable *t, *orig = h->table; struct htable *t, *orig = rcu_dereference_bh_nfnl(h->table);
u8 htable_bits = orig->htable_bits; u8 htable_bits = orig->htable_bits;
#ifdef IP_SET_HASH_WITH_NETS #ifdef IP_SET_HASH_WITH_NETS
u8 flags; u8 flags;
...@@ -682,13 +688,15 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -682,13 +688,15 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags) struct ip_set_ext *mext, u32 flags)
{ {
struct htype *h = set->data; struct htype *h = set->data;
struct htable *t = h->table; struct htable *t;
const struct mtype_elem *d = value; const struct mtype_elem *d = value;
struct mtype_elem *data; struct mtype_elem *data;
struct hbucket *n; struct hbucket *n;
int i; int i, ret = -IPSET_ERR_EXIST;
u32 key, multi = 0; u32 key, multi = 0;
rcu_read_lock_bh();
t = rcu_dereference_bh(h->table);
key = HKEY(value, h->initval, t->htable_bits); key = HKEY(value, h->initval, t->htable_bits);
n = hbucket(t, key); n = hbucket(t, key);
for (i = 0; i < n->pos; i++) { 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,7 +705,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
continue; continue;
if (SET_WITH_TIMEOUT(set) && if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(data, h))) ip_set_timeout_expired(ext_timeout(data, h)))
return -IPSET_ERR_EXIST; goto out;
if (i != n->pos - 1) if (i != n->pos - 1)
/* Not last one */ /* Not last one */
memcpy(data, ahash_data(n, n->pos - 1, h->dsize), 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,17 +720,22 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
* h->dsize, * h->dsize,
GFP_ATOMIC); GFP_ATOMIC);
if (!tmp) if (!tmp) {
return 0; ret = 0;
goto out;
}
n->size -= AHASH_INIT_SIZE; n->size -= AHASH_INIT_SIZE;
memcpy(tmp, n->value, n->size * h->dsize); memcpy(tmp, n->value, n->size * h->dsize);
kfree(n->value); kfree(n->value);
n->value = tmp; n->value = tmp;
} }
return 0; ret = 0;
goto out;
} }
return -IPSET_ERR_EXIST; out:
rcu_read_unlock_bh();
return ret;
} }
static inline int static inline int
...@@ -745,7 +758,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, ...@@ -745,7 +758,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
struct ip_set_ext *mext, u32 flags) struct ip_set_ext *mext, u32 flags)
{ {
struct htype *h = set->data; struct htype *h = set->data;
struct htable *t = h->table; struct htable *t = rcu_dereference_bh(h->table);
struct hbucket *n; struct hbucket *n;
struct mtype_elem *data; struct mtype_elem *data;
int i, j = 0; int i, j = 0;
...@@ -785,18 +798,22 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, ...@@ -785,18 +798,22 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags) struct ip_set_ext *mext, u32 flags)
{ {
struct htype *h = set->data; struct htype *h = set->data;
struct htable *t = h->table; struct htable *t;
struct mtype_elem *d = value; struct mtype_elem *d = value;
struct hbucket *n; struct hbucket *n;
struct mtype_elem *data; struct mtype_elem *data;
int i; int i, ret = 0;
u32 key, multi = 0; u32 key, multi = 0;
rcu_read_lock_bh();
t = rcu_dereference_bh(h->table);
#ifdef IP_SET_HASH_WITH_NETS #ifdef IP_SET_HASH_WITH_NETS
/* If we test an IP address and not a network address, /* If we test an IP address and not a network address,
* try all possible network sizes */ * try all possible network sizes */
if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) {
return mtype_test_cidrs(set, d, ext, mext, flags); ret = mtype_test_cidrs(set, d, ext, mext, flags);
goto out;
}
#endif #endif
key = HKEY(d, h->initval, t->htable_bits); 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,10 +822,14 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
data = ahash_data(n, i, h->dsize); data = ahash_data(n, i, h->dsize);
if (mtype_data_equal(data, d, &multi) && if (mtype_data_equal(data, d, &multi) &&
!(SET_WITH_TIMEOUT(set) && !(SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(data, h)))) ip_set_timeout_expired(ext_timeout(data, h)))) {
return mtype_data_match(data, ext, mext, set, flags); ret = mtype_data_match(data, ext, mext, set, flags);
goto out;
}
} }
return 0; out:
rcu_read_unlock_bh();
return ret;
} }
/* Reply a HEADER request: fill out the header part of the set */ /* Reply a HEADER request: fill out the header part of the set */
...@@ -816,18 +837,18 @@ static int ...@@ -816,18 +837,18 @@ static int
mtype_head(struct ip_set *set, struct sk_buff *skb) mtype_head(struct ip_set *set, struct sk_buff *skb)
{ {
const struct htype *h = set->data; const struct htype *h = set->data;
const struct htable *t;
struct nlattr *nested; struct nlattr *nested;
size_t memsize; size_t memsize;
read_lock_bh(&set->lock); t = rcu_dereference_bh_nfnl(h->table);
memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family)); memsize = mtype_ahash_memsize(h, t, NETS_LENGTH(set->family));
read_unlock_bh(&set->lock);
nested = ipset_nest_start(skb, IPSET_ATTR_DATA); nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) if (!nested)
goto nla_put_failure; goto nla_put_failure;
if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE, if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE,
htonl(jhash_size(h->table->htable_bits))) || htonl(jhash_size(t->htable_bits))) ||
nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem))) nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))
goto nla_put_failure; goto nla_put_failure;
#ifdef IP_SET_HASH_WITH_NETMASK #ifdef IP_SET_HASH_WITH_NETMASK
...@@ -856,7 +877,7 @@ mtype_list(const struct ip_set *set, ...@@ -856,7 +877,7 @@ mtype_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb) struct sk_buff *skb, struct netlink_callback *cb)
{ {
const struct htype *h = set->data; const struct htype *h = set->data;
const struct htable *t = h->table; const struct htable *t = rcu_dereference_bh_nfnl(h->table);
struct nlattr *atd, *nested; struct nlattr *atd, *nested;
const struct hbucket *n; const struct hbucket *n;
const struct mtype_elem *e; const struct mtype_elem *e;
...@@ -956,6 +977,7 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -956,6 +977,7 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
#endif #endif
size_t hsize; size_t hsize;
struct HTYPE *h; struct HTYPE *h;
struct htable *t;
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;
...@@ -1013,12 +1035,13 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -1013,12 +1035,13 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
} }
h->table = ip_set_alloc(hsize); t = ip_set_alloc(hsize);
if (!h->table) { if (!t) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
} }
h->table->htable_bits = hbits; t->htable_bits = hbits;
rcu_assign_pointer(h->table, t);
set->data = h; set->data = h;
if (set->family == NFPROTO_IPV4) if (set->family == NFPROTO_IPV4)
...@@ -1096,8 +1119,8 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -1096,8 +1119,8 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
} }
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits), set->name, jhash_size(t->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table); t->htable_bits, h->maxelem, set->data, t);
return 0; return 0;
} }
......
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