Commit 9ea4894b authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

Merge branch 'master' of git://blackhole.kfki.hu/nf



Jozsef Kadlecsik says:

====================
ipset patches for nf

The first one is larger than usual, but the issue could not be solved simpler.
Also, it's a resend of the patch I submitted a few days ago, with a one line
fix on top of that: the size of the comment extensions was not taken into
account at reporting the full size of the set.

- Fix "INFO: rcu detected stall in hash_xxx" reports of syzbot
  by introducing region locking and using workqueue instead of timer based
  gc of timed out entries in hash types of sets in ipset.
- Fix the forceadd evaluation path - the bug was also uncovered by the syzbot.
====================

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parents d0820556 8af1c6fb
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.