diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2015-03-19 13:24:47 +0100 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2015-03-19 13:24:47 +0100 |
commit | e2a781b4b8916ee5eff4c29ed5f08790b5ef28d1 (patch) | |
tree | ea17470fd41f2c58f69ea9d2a9641b43303b2614 | |
parent | 1759d7ec38637e1eaf009619f463d6b121e23502 (diff) |
Make sure bit operations are not reordered
Sergey Popovich pointed out that {set,clear}_bit() operations
must be protected against instruction reordering.
-rw-r--r-- | kernel/include/linux/netfilter/ipset/ip_set_compat.h.in | 5 | ||||
-rw-r--r-- | kernel/net/netfilter/ipset/ip_set_hash_gen.h | 7 |
2 files changed, 10 insertions, 2 deletions
diff --git a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in index 66e830f..a0a7436 100644 --- a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in +++ b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in @@ -204,6 +204,11 @@ static inline int nla_put_net32(struct sk_buff *skb, int attrtype, __be32 value) list_entry((pos)->member.prev, typeof(*(pos)), member) #endif +#ifndef smp_mb__before_atomic +#define smp_mb__before_atomic() smp_mb() +#define smp_mb__after_atomic() smp_mb() +#endif + #ifndef __aligned_u64 #define __aligned_u64 __u64 #endif diff --git a/kernel/net/netfilter/ipset/ip_set_hash_gen.h b/kernel/net/netfilter/ipset/ip_set_hash_gen.h index 85cac70..249a7f9 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_gen.h +++ b/kernel/net/netfilter/ipset/ip_set_hash_gen.h @@ -479,6 +479,8 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize) data = ahash_data(n, j, dsize); if (ip_set_timeout_expired(ext_timeout(data, set))) { pr_debug("expired %u/%u\n", i, j); + clear_bit(j, n->used); + smp_mb__after_atomic(); #ifdef IP_SET_HASH_WITH_NETS for (k = 0; k < IPSET_NET_COUNT; k++) mtype_del_cidr(h, @@ -487,7 +489,6 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize) nets_length, k); #endif ip_set_ext_destroy(set, data); - clear_bit(j, n->used); h->elements--; d++; } @@ -799,9 +800,10 @@ overwrite_extensions: ip_set_init_comment(ext_comment(data, set), ext); if (SET_WITH_SKBINFO(set)) ip_set_init_skbinfo(ext_skbinfo(data, set), ext); - /* Must come last */ + /* Must come last for the case when timed out entry is reused */ if (SET_WITH_TIMEOUT(set)) ip_set_timeout_set(ext_timeout(data, set), ext->timeout); + smp_mb__before_atomic(); set_bit(j, n->used); if (old != ERR_PTR(-ENOENT)) { rcu_assign_pointer(hbucket(t, key), n); @@ -851,6 +853,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, ret = 0; clear_bit(i, n->used); + smp_mb__after_atomic(); if (i + 1 == n->pos) n->pos--; h->elements--; |