aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter/nft_dynset.c
diff options
context:
space:
mode:
authorLiping Zhang <zlpnobody@gmail.com>2016-10-22 18:51:25 +0800
committerPablo Neira Ayuso <pablo@netfilter.org>2016-10-27 18:20:45 +0200
commit61f9e2924f4981d626b3a931fed935f2fa3cb4de (patch)
tree77d9f1c293690b43f9d858294e3164b464edd5fa /net/netfilter/nft_dynset.c
parentnetfilter: nft_dynset: fix panic if NFT_SET_HASH is not enabled (diff)
downloadlinux-dev-61f9e2924f4981d626b3a931fed935f2fa3cb4de.tar.xz
linux-dev-61f9e2924f4981d626b3a931fed935f2fa3cb4de.zip
netfilter: nf_tables: fix *leak* when expr clone fail
When nft_expr_clone failed, a series of problems will happen: 1. module refcnt will leak, we call __module_get at the beginning but we forget to put it back if ops->clone returns fail 2. memory will be leaked, if clone fail, we just return NULL and forget to free the alloced element 3. set->nelems will become incorrect when set->size is specified. If clone fail, we should decrease the set->nelems Now this patch fixes these problems. And fortunately, clone fail will only happen on counter expression when memory is exhausted. Fixes: 086f332167d6 ("netfilter: nf_tables: add clone interface to expression operations") Signed-off-by: Liping Zhang <zlpnobody@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter/nft_dynset.c')
-rw-r--r--net/netfilter/nft_dynset.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index bfdb689664b0..31ca94793aa9 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -44,18 +44,22 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
&regs->data[priv->sreg_key],
&regs->data[priv->sreg_data],
timeout, GFP_ATOMIC);
- if (elem == NULL) {
- if (set->size)
- atomic_dec(&set->nelems);
- return NULL;
- }
+ if (elem == NULL)
+ goto err1;
ext = nft_set_elem_ext(set, elem);
if (priv->expr != NULL &&
nft_expr_clone(nft_set_ext_expr(ext), priv->expr) < 0)
- return NULL;
+ goto err2;
return elem;
+
+err2:
+ nft_set_elem_destroy(set, elem, false);
+err1:
+ if (set->size)
+ atomic_dec(&set->nelems);
+ return NULL;
}
static void nft_dynset_eval(const struct nft_expr *expr,