From e2a781b4b8916ee5eff4c29ed5f08790b5ef28d1 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 19 Mar 2015 13:24:47 +0100 Subject: Make sure bit operations are not reordered Sergey Popovich pointed out that {set,clear}_bit() operations must be protected against instruction reordering. --- kernel/include/linux/netfilter/ipset/ip_set_compat.h.in | 5 +++++ 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--; -- cgit v1.2.3