Commit 574b238f authored by David S. Miller's avatar David S. Miller
Browse files


Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes:

1) Perform garbage collection from workqueue to fix rcu detected
   stall in ipset hash set types, from Jozsef Kadlecsik.

2) Fix the forceadd evaluation path, also from Jozsef.

3) Fix nft_set_pipapo selftest, from Stefano Brivio.

4) Crash when add-flush-add element in pipapo set, also from Stefano.
   Add test to cover this crash.

5) Remove sysctl entry under mutex in hashlimit, from Cong Wang.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9a005c38 99b79c39
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ struct ip_set_ext {
	u32 timeout;
	u8 packets_op;
	u8 bytes_op;
	bool target;
};

struct ip_set;
@@ -187,6 +188,14 @@ struct ip_set_type_variant {
	/* Return true if "b" set is the same as "a"
	 * according to the create set parameters */
	bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
	/* Region-locking is used */
	bool region_lock;
};

struct ip_set_region {
	spinlock_t lock;	/* Region lock */
	size_t ext_size;	/* Size of the dynamic extensions */
	u32 elements;		/* Number of elements vs timeout */
};

/* The core set type structure */
@@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
}

#define IP_SET_INIT_KEXT(skb, opt, set)			\
	{ .bytes = (skb)->len, .packets = 1,		\
	{ .bytes = (skb)->len, .packets = 1, .target = true,\
	  .timeout = ip_set_adt_opt_timeout(opt, set) }

#define IP_SET_INIT_UEXT(set)				\
+24 −10
Original line number Diff line number Diff line
@@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index)
	return set;
}

static inline void
ip_set_lock(struct ip_set *set)
{
	if (!set->variant->region_lock)
		spin_lock_bh(&set->lock);
}

static inline void
ip_set_unlock(struct ip_set *set)
{
	if (!set->variant->region_lock)
		spin_unlock_bh(&set->lock);
}

int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
	    const struct xt_action_param *par, struct ip_set_adt_opt *opt)
@@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
	if (ret == -EAGAIN) {
		/* Type requests element to be completed */
		pr_debug("element must be completed, ADD is triggered\n");
		spin_lock_bh(&set->lock);
		ip_set_lock(set);
		set->variant->kadt(set, skb, par, IPSET_ADD, opt);
		spin_unlock_bh(&set->lock);
		ip_set_unlock(set);
		ret = 1;
	} else {
		/* --return-nomatch: invert matched element */
@@ -775,9 +789,9 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
	    !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
		return -IPSET_ERR_TYPE_MISMATCH;

	spin_lock_bh(&set->lock);
	ip_set_lock(set);
	ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
	spin_unlock_bh(&set->lock);
	ip_set_unlock(set);

	return ret;
}
@@ -797,9 +811,9 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
	    !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
		return -IPSET_ERR_TYPE_MISMATCH;

	spin_lock_bh(&set->lock);
	ip_set_lock(set);
	ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
	spin_unlock_bh(&set->lock);
	ip_set_unlock(set);

	return ret;
}
@@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set)
{
	pr_debug("set: %s\n",  set->name);

	spin_lock_bh(&set->lock);
	ip_set_lock(set);
	set->variant->flush(set);
	spin_unlock_bh(&set->lock);
	ip_set_unlock(set);
}

static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
@@ -1713,9 +1727,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
	bool eexist = flags & IPSET_FLAG_EXIST, retried = false;

	do {
		spin_lock_bh(&set->lock);
		ip_set_lock(set);
		ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
		spin_unlock_bh(&set->lock);
		ip_set_unlock(set);
		retried = true;
	} while (ret == -EAGAIN &&
		 set->variant->resize &&
+440 −195

File changed.

Preview size limit exceeded, changes collapsed.

+4 −2
Original line number Diff line number Diff line
@@ -1766,11 +1766,13 @@ static bool pipapo_match_field(struct nft_pipapo_field *f,
static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
			      const struct nft_set_elem *elem)
{
	const u8 *data = (const u8 *)elem->key.val.data;
	struct nft_pipapo *priv = nft_set_priv(set);
	struct nft_pipapo_match *m = priv->clone;
	struct nft_pipapo_elem *e = elem->priv;
	int rules_f0, first_rule = 0;
	struct nft_pipapo_elem *e;
	const u8 *data;

	data = (const u8 *)nft_set_ext_key(&e->ext);

	e = pipapo_get(net, set, data, 0);
	if (IS_ERR(e))
+6 −10
Original line number Diff line number Diff line
@@ -402,15 +402,6 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo)
		remove_proc_entry(hinfo->name, parent);
}

static void htable_destroy(struct xt_hashlimit_htable *hinfo)
{
	cancel_delayed_work_sync(&hinfo->gc_work);
	htable_remove_proc_entry(hinfo);
	htable_selective_cleanup(hinfo, true);
	kfree(hinfo->name);
	vfree(hinfo);
}

static struct xt_hashlimit_htable *htable_find_get(struct net *net,
						   const char *name,
						   u_int8_t family)
@@ -432,8 +423,13 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
{
	if (refcount_dec_and_mutex_lock(&hinfo->use, &hashlimit_mutex)) {
		hlist_del(&hinfo->node);
		htable_remove_proc_entry(hinfo);
		mutex_unlock(&hashlimit_mutex);
		htable_destroy(hinfo);

		cancel_delayed_work_sync(&hinfo->gc_work);
		htable_selective_cleanup(hinfo, true);
		kfree(hinfo->name);
		vfree(hinfo);
	}
}

Loading