| From 00457814f2bf3d3ae6bcdb76b5ca3155500ee4a8 Mon Sep 17 00:00:00 2001 |
| From: Cong Wang <xiyou.wangcong@gmail.com> |
| Date: Sun, 2 Feb 2020 20:30:52 -0800 |
| Subject: [PATCH] netfilter: xt_hashlimit: reduce hashlimit_mutex scope for |
| htable_put() |
| |
| commit c4a3922d2d20c710f827d3a115ee338e8d0467df upstream. |
| |
| 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: syzbot+adf6c6c2be1c3a718121@syzkaller.appspotmail.com |
| Acked-by: Florian Westphal <fw@strlen.de> |
| Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> |
| Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c |
| index 94e37d024b1f..3cf399838294 100644 |
| --- a/net/netfilter/xt_hashlimit.c |
| +++ b/net/netfilter/xt_hashlimit.c |
| @@ -36,6 +36,7 @@ |
| #include <linux/netfilter_ipv6/ip6_tables.h> |
| #include <linux/netfilter/xt_hashlimit.h> |
| #include <linux/mutex.h> |
| +#include <linux/refcount.h> |
| #include <linux/kernel.h> |
| |
| MODULE_LICENSE("GPL"); |
| @@ -109,7 +110,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; |
| |
| @@ -310,7 +311,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; |
| @@ -429,7 +430,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; |
| } |
| } |
| @@ -438,12 +439,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) |
| -- |
| 2.7.4 |
| |