Skip to content

Commit e517341

Browse files
rosslagerwallummakynes
authored andcommitted
netfilter: ipset: Fix race between dump and swap
Fix a race between ip_set_dump_start() and ip_set_swap(). The race is as follows: * Without holding the ref lock, ip_set_swap() checks ref_netlink of the set and it is 0. * ip_set_dump_start() takes a reference on the set. * ip_set_swap() does the swap (even though it now has a non-zero reference count). * ip_set_dump_start() gets the set from ip_set_list again which is now a different set since it has been swapped. * ip_set_dump_start() calls __ip_set_put_netlink() and hits a BUG_ON due to the reference count being 0. Fix this race by extending the critical region in which the ref lock is held to include checking the ref counts. The race can be reproduced with the following script: while :; do ipset destroy hash_ip1 ipset destroy hash_ip2 ipset create hash_ip1 hash:ip family inet hashsize 1024 \ maxelem 500000 ipset create hash_ip2 hash:ip family inet hashsize 300000 \ maxelem 500000 ipset create hash_ip3 hash:ip family inet hashsize 1024 \ maxelem 500000 ipset save & ipset swap hash_ip3 hash_ip2 ipset destroy hash_ip3 wait done Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com> Acked-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent e23ed76 commit e517341

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

net/netfilter/ipset/ip_set_core.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,14 +1191,17 @@ static int ip_set_swap(struct net *net, struct sock *ctnl, struct sk_buff *skb,
11911191
from->family == to->family))
11921192
return -IPSET_ERR_TYPE_MISMATCH;
11931193

1194-
if (from->ref_netlink || to->ref_netlink)
1194+
write_lock_bh(&ip_set_ref_lock);
1195+
1196+
if (from->ref_netlink || to->ref_netlink) {
1197+
write_unlock_bh(&ip_set_ref_lock);
11951198
return -EBUSY;
1199+
}
11961200

11971201
strncpy(from_name, from->name, IPSET_MAXNAMELEN);
11981202
strncpy(from->name, to->name, IPSET_MAXNAMELEN);
11991203
strncpy(to->name, from_name, IPSET_MAXNAMELEN);
12001204

1201-
write_lock_bh(&ip_set_ref_lock);
12021205
swap(from->ref, to->ref);
12031206
ip_set(inst, from_id) = to;
12041207
ip_set(inst, to_id) = from;

0 commit comments

Comments
 (0)