netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org
Subject: [PATCH 21/32] netfilter: ipset: Make sure listing doesn't grab a set which is just being destroyed.
Date: Mon, 15 Jun 2015 23:26:18 +0200	[thread overview]
Message-ID: <1434403589-24796-22-git-send-email-pablo@netfilter.org> (raw)
In-Reply-To: <1434403589-24796-1-git-send-email-pablo@netfilter.org>

From: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

There was a small window when all sets are destroyed and a concurrent
listing of all sets could grab a set which is just being destroyed.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
---
 net/netfilter/ipset/ip_set_core.c |   49 +++++++++++++++++++++++++------------
 1 file changed, 34 insertions(+), 15 deletions(-)

diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 777cac6..87b4182 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -32,7 +32,8 @@ static DEFINE_RWLOCK(ip_set_ref_lock);		/* protects the set refs */
 struct ip_set_net {
 	struct ip_set * __rcu *ip_set_list;	/* all individual sets */
 	ip_set_id_t	ip_set_max;	/* max number of sets */
-	int		is_deleted;	/* deleted by ip_set_net_exit */
+	bool		is_deleted;	/* deleted by ip_set_net_exit */
+	bool		is_destroyed;	/* all sets are destroyed */
 };
 static int ip_set_net_id __read_mostly;
 
@@ -980,12 +981,9 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
 };
 
 static void
-ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index)
+ip_set_destroy_set(struct ip_set *set)
 {
-	struct ip_set *set = ip_set(inst, index);
-
 	pr_debug("set: %s\n",  set->name);
-	ip_set(inst, index) = NULL;
 
 	/* Must call it without holding any lock */
 	set->variant->destroy(set);
@@ -1025,12 +1023,17 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
 				goto out;
 			}
 		}
+		inst->is_destroyed = true;
 		read_unlock_bh(&ip_set_ref_lock);
 		for (i = 0; i < inst->ip_set_max; i++) {
 			s = ip_set(inst, i);
-			if (s != NULL)
-				ip_set_destroy_set(inst, i);
+			if (s) {
+				ip_set(inst, i) = NULL;
+				ip_set_destroy_set(s);
+			}
 		}
+		/* Modified by ip_set_destroy() only, which is serialized */
+		inst->is_destroyed = false;
 	} else {
 		s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
 				    &i);
@@ -1041,9 +1044,10 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
 			ret = -IPSET_ERR_BUSY;
 			goto out;
 		}
+		ip_set(inst, i) = NULL;
 		read_unlock_bh(&ip_set_ref_lock);
 
-		ip_set_destroy_set(inst, i);
+		ip_set_destroy_set(s);
 	}
 	return 0;
 out:
@@ -1283,6 +1287,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
 	unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0;
 	struct ip_set_net *inst = ip_set_pernet(sock_net(skb->sk));
 	u32 dump_type, dump_flags;
+	bool is_destroyed;
 	int ret = 0;
 
 	if (!cb->args[IPSET_CB_DUMP]) {
@@ -1309,12 +1314,20 @@ dump_last:
 		 dump_type, dump_flags, cb->args[IPSET_CB_INDEX]);
 	for (; cb->args[IPSET_CB_INDEX] < max; cb->args[IPSET_CB_INDEX]++) {
 		index = (ip_set_id_t) cb->args[IPSET_CB_INDEX];
+		write_lock_bh(&ip_set_ref_lock);
 		set = ip_set(inst, index);
-		if (set == NULL) {
+		is_destroyed = inst->is_destroyed;
+		if (!set || is_destroyed) {
+			write_unlock_bh(&ip_set_ref_lock);
 			if (dump_type == DUMP_ONE) {
 				ret = -ENOENT;
 				goto out;
 			}
+			if (is_destroyed) {
+				/* All sets are just being destroyed */
+				ret = 0;
+				goto out;
+			}
 			continue;
 		}
 		/* When dumping all sets, we must dump "sorted"
@@ -1322,14 +1335,17 @@ dump_last:
 		 */
 		if (dump_type != DUMP_ONE &&
 		    ((dump_type == DUMP_ALL) ==
-		     !!(set->type->features & IPSET_DUMP_LAST)))
+		     !!(set->type->features & IPSET_DUMP_LAST))) {
+			write_unlock_bh(&ip_set_ref_lock);
 			continue;
+		}
 		pr_debug("List set: %s\n", set->name);
 		if (!cb->args[IPSET_CB_ARG0]) {
 			/* Start listing: make sure set won't be destroyed */
 			pr_debug("reference set\n");
-			__ip_set_get(set);
+			set->ref++;
 		}
+		write_unlock_bh(&ip_set_ref_lock);
 		nlh = start_msg(skb, NETLINK_CB(cb->skb).portid,
 				cb->nlh->nlmsg_seq, flags,
 				IPSET_CMD_LIST);
@@ -2012,7 +2028,8 @@ ip_set_net_init(struct net *net)
 	list = kzalloc(sizeof(struct ip_set *) * inst->ip_set_max, GFP_KERNEL);
 	if (!list)
 		return -ENOMEM;
-	inst->is_deleted = 0;
+	inst->is_deleted = false;
+	inst->is_destroyed = false;
 	rcu_assign_pointer(inst->ip_set_list, list);
 	return 0;
 }
@@ -2025,12 +2042,14 @@ ip_set_net_exit(struct net *net)
 	struct ip_set *set = NULL;
 	ip_set_id_t i;
 
-	inst->is_deleted = 1; /* flag for ip_set_nfnl_put */
+	inst->is_deleted = true; /* flag for ip_set_nfnl_put */
 
 	for (i = 0; i < inst->ip_set_max; i++) {
 		set = ip_set(inst, i);
-		if (set != NULL)
-			ip_set_destroy_set(inst, i);
+		if (set) {
+			ip_set(inst, i) = NULL;
+			ip_set_destroy_set(set);
+		}
 	}
 	kfree(rcu_dereference_protected(inst->ip_set_list, 1));
 }
-- 
1.7.10.4

  parent reply	other threads:[~2015-06-15 21:26 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-15 21:25 [PATCH 00/32] Netfilter updates for net-next Pablo Neira Ayuso
2015-06-15 21:25 ` [PATCH 01/32] netfilter: conntrack: warn the user if there is a better helper to use Pablo Neira Ayuso
2015-06-15 21:25 ` [PATCH 02/32] netfilter: bridge: refactor clearing BRNF_NF_BRIDGE_PREROUTING Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 03/32] netfilter: bridge: re-order br_nf_pre_routing_finish_ipv6() Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 04/32] netfilter: bridge: detect NAT66 correctly and change MAC address Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 05/32] netfilter: bridge: refactor frag_max_size Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 06/32] netfilter: bridge: rename br_parse_ip_options Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 07/32] netfilter: bridge: re-order check_hbh_len() Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 08/32] netfilter: bridge: forward IPv6 fragmented packets Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 09/32] net: ip_fragment: remove BRIDGE_NETFILTER mtu special handling Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 10/32] netfilter: bridge: restore vlan tag when refragmenting Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 11/32] netfilter: xtables: use percpu rule counters Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 12/32] netfilter: xtables: avoid percpu ruleset duplication Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 13/32] netfilter: ipset: Use MSEC_PER_SEC consistently Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 14/32] netfilter: ipset: Use SET_WITH_*() helpers to test set extensions Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 15/32] netfilter: ipset: Check extensions attributes before getting extensions Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 16/32] netfilter: ipset: Permit CIDR equal to the host address CIDR in IPv6 Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 17/32] netfilter: ipset: Make sure we always return line number on batch Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 18/32] netfilter: ipset: Check CIDR value only when attribute is given Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 19/32] netfilter: ipset: Fix cidr handling for hash:*net* types Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 20/32] netfilter: ipset: Fix parallel resizing and listing of the same set Pablo Neira Ayuso
2015-06-15 21:26 ` Pablo Neira Ayuso [this message]
2015-06-15 21:26 ` [PATCH 22/32] netfilter:ipset Remove rbtree from hash:net,iface Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 23/32] netfilter: ipset: Prepare the ipset core to use RCU at set level Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 24/32] netfilter: ipset: Introduce RCU locking in bitmap:* types Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 25/32] netfilter: ipset: Introduce RCU locking in hash:* types Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 26/32] netfilter: ipset: Introduce RCU locking in list type Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 27/32] netfilter: ipset: Fix coding styles reported by checkpatch.pl Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 28/32] netfilter: Kconfig: get rid of parens around depends on Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 29/32] netfilter: x_tables: remove XT_TABLE_INFO_SZ and a dereference Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 30/32] netfilter: nf_tables: attach net_device to basechain Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 31/32] netfilter: nf_tables: add nft_register_basechain() and nft_unregister_basechain() Pablo Neira Ayuso
2015-06-15 21:26 ` [PATCH 32/32] netfilter: nf_tables_netdev: unregister hooks on net_device removal Pablo Neira Ayuso
2015-06-15 21:41 ` [PATCH 00/32] Netfilter updates for net-next David Miller
2015-06-20 13:11 ` Jakub Kiciński
2015-06-20 18:30   ` Pablo Neira Ayuso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1434403589-24796-22-git-send-email-pablo@netfilter.org \
    --to=pablo@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).