summaryrefslogtreecommitdiff
path: root/kernel/include/linux
diff options
context:
space:
mode:
authorVishwanath Pai <vpai@akamai.com>2016-03-16 09:03:30 +0100
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2016-03-16 09:03:30 +0100
commit4c70c227fdbb4ec302286bb7ade2ec4051b4d508 (patch)
treef31c5063691ff6f519cea879c964dbf641975058 /kernel/include/linux
parente2b58fe3c45933957ec38161fc255a0f88333d14 (diff)
downloadipset-4c70c227fdbb4ec302286bb7ade2ec4051b4d508.tar.gz
netfilter: ipset: fix race condition in ipset save, swap and delete
This fix adds a new reference counter (ref_netlink) for the struct ip_set. The other reference counter (ref) can be swapped out by ip_set_swap and we need a separate counter to keep track of references for netlink events like dump. Using the same ref counter for dump causes a race condition which can be demonstrated by the following script: ipset create hash_ip1 hash:ip family inet hashsize 1024 maxelem 500000 \ counters ipset create hash_ip2 hash:ip family inet hashsize 300000 maxelem 500000 \ counters ipset create hash_ip3 hash:ip family inet hashsize 1024 maxelem 500000 \ counters ipset save & ipset swap hash_ip3 hash_ip2 ipset destroy hash_ip3 /* will crash the machine */ Swap will exchange the values of ref so destroy will see ref = 0 instead of ref = 1. With this fix in place swap will not succeed because ipset save still has ref_netlink on the set (ip_set_swap doesn't swap ref_netlink). Both delete and swap will error out if ref_netlink != 0 on the set. Note: The changes to *_head functions is because previously we would increment ref whenever we called these functions, we don't do that anymore. Reviewed-by: Joshua Hunt <johunt@akamai.com> Signed-off-by: Vishwanath Pai <vpai@akamai.com> Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Diffstat (limited to 'kernel/include/linux')
-rw-r--r--kernel/include/linux/netfilter/ipset/ip_set.h4
1 files changed, 4 insertions, 0 deletions
diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h
index eaf5057..3e44e66 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set.h
+++ b/kernel/include/linux/netfilter/ipset/ip_set.h
@@ -235,6 +235,10 @@ struct ip_set {
spinlock_t lock;
/* References to the set */
u32 ref;
+ /* References to the set for netlink events like dump,
+ * ref can be swapped out by ip_set_swap
+ */
+ u32 ref_netlink;
/* The core set type */
struct ip_set_type *type;
/* The type variant doing the real job */