Commit c4a3922d authored by Cong Wang's avatar Cong Wang Committed by Pablo Neira Ayuso
Browse files

netfilter: xt_hashlimit: reduce hashlimit_mutex scope for htable_put()



It is unnecessary to hold hashlimit_mutex for htable_destroy()
as it is already removed from the global hashtable and its
refcount is already zero.

Also, switch hinfo->use to refcount_t so that we don't have
to hold the mutex until it reaches zero in htable_put().

Reported-and-tested-by: default avatar <syzbot+adf6c6c2be1c3a718121@syzkaller.appspotmail.com>
Acked-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 259039fa
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/refcount.h>
#include <uapi/linux/netfilter/xt_hashlimit.h>

#define XT_HASHLIMIT_ALL (XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT | \
@@ -114,7 +115,7 @@ struct dsthash_ent {

struct xt_hashlimit_htable {
	struct hlist_node node;		/* global list of all htables */
	int use;
	refcount_t use;
	u_int8_t family;
	bool rnd_initialized;

@@ -315,7 +316,7 @@ static int htable_create(struct net *net, struct hashlimit_cfg3 *cfg,
	for (i = 0; i < hinfo->cfg.size; i++)
		INIT_HLIST_HEAD(&hinfo->hash[i]);

	hinfo->use = 1;
	refcount_set(&hinfo->use, 1);
	hinfo->count = 0;
	hinfo->family = family;
	hinfo->rnd_initialized = false;
@@ -420,7 +421,7 @@ static struct xt_hashlimit_htable *htable_find_get(struct net *net,
	hlist_for_each_entry(hinfo, &hashlimit_net->htables, node) {
		if (!strcmp(name, hinfo->name) &&
		    hinfo->family == family) {
			hinfo->use++;
			refcount_inc(&hinfo->use);
			return hinfo;
		}
	}
@@ -429,12 +430,11 @@ static struct xt_hashlimit_htable *htable_find_get(struct net *net,

static void htable_put(struct xt_hashlimit_htable *hinfo)
{
	mutex_lock(&hashlimit_mutex);
	if (--hinfo->use == 0) {
	if (refcount_dec_and_mutex_lock(&hinfo->use, &hashlimit_mutex)) {
		hlist_del(&hinfo->node);
		mutex_unlock(&hashlimit_mutex);
		htable_destroy(hinfo);
	}
	mutex_unlock(&hashlimit_mutex);
}

/* The algorithm used is the Simple Token Bucket Filter (TBF)