* [PATCH v2 nf] netfilter: nf_tables: fix memory leak during stateful obj update
@ 2022-02-20 11:18 Florian Westphal
2022-02-21 10:34 ` Pablo Neira Ayuso
0 siblings, 1 reply; 5+ messages in thread
From: Florian Westphal @ 2022-02-20 11:18 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Fernando Fernandez Mancera
stateful objects can be updated from the control plane.
The transaction logic allocates a temporary object for this purpose.
This object has to be released via nft_obj_destroy, not kfree, since
the ->init function was called and it can have side effects beyond
memory allocation.
Unlike normal NEWOBJ path, the objects module refcount isn't
incremented, so add nft_newobj_destroy and use that.
Fixes: d62d0ba97b58 ("netfilter: nf_tables: Introduce stateful object update operation")
Cc: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
v2: can't use nft_obj_destroy, module refcount is not incremented.
net/netfilter/nf_tables_api.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 5fa16990da95..56208e778982 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -6909,6 +6909,15 @@ static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info,
return err;
}
+/* nf_tables_updobj does not increment module refcount */
+static void nft_newobj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
+{
+ if (obj->ops->destroy)
+ obj->ops->destroy(ctx, obj);
+
+ kfree(obj);
+}
+
static void nft_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
{
if (obj->ops->destroy)
@@ -8185,7 +8194,7 @@ static void nft_obj_commit_update(struct nft_trans *trans)
if (obj->ops->update)
obj->ops->update(obj, newobj);
- kfree(newobj);
+ nft_newobj_destroy(&trans->ctx, newobj);
}
static void nft_commit_release(struct nft_trans *trans)
@@ -8976,7 +8985,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
break;
case NFT_MSG_NEWOBJ:
if (nft_trans_obj_update(trans)) {
- kfree(nft_trans_obj_newobj(trans));
+ nft_newobj_destroy(&trans->ctx, nft_trans_obj_newobj(trans));
nft_trans_destroy(trans);
} else {
trans->ctx.table->use--;
--
2.35.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v2 nf] netfilter: nf_tables: fix memory leak during stateful obj update 2022-02-20 11:18 [PATCH v2 nf] netfilter: nf_tables: fix memory leak during stateful obj update Florian Westphal @ 2022-02-21 10:34 ` Pablo Neira Ayuso 2022-02-21 10:46 ` Florian Westphal 0 siblings, 1 reply; 5+ messages in thread From: Pablo Neira Ayuso @ 2022-02-21 10:34 UTC (permalink / raw) To: Florian Westphal; +Cc: netfilter-devel, Fernando Fernandez Mancera [-- Attachment #1: Type: text/plain, Size: 578 bytes --] Hi Florian, On Sun, Feb 20, 2022 at 12:18:50PM +0100, Florian Westphal wrote: > stateful objects can be updated from the control plane. > The transaction logic allocates a temporary object for this purpose. > > This object has to be released via nft_obj_destroy, not kfree, since > the ->init function was called and it can have side effects beyond > memory allocation. > > Unlike normal NEWOBJ path, the objects module refcount isn't > incremented, so add nft_newobj_destroy and use that. Probably this? .udata and .key is NULL for the update path so kfree should be fine. [-- Attachment #2: 0001-netfilter-nf_tables-fix-memory-leak-during-stateful-.patch --] [-- Type: text/x-diff, Size: 3459 bytes --] From 909c4c67deadbc674fcadd081c32c0781eb8e26f Mon Sep 17 00:00:00 2001 From: Florian Westphal <fw@strlen.de> Date: Sun, 20 Feb 2022 12:18:50 +0100 Subject: [PATCH] netfilter: nf_tables: fix memory leak during stateful obj update stateful objects can be updated from the control plane. The transaction logic allocates a temporary object for this purpose. This object has to be released via nft_obj_destroy, not kfree, since the ->init function was called and it can have side effects beyond memory allocation. Unlike normal NEWOBJ path, the objects module refcount isn't incremented, so extend nft_obj_destroy to specify if this is an update. Fixes: d62d0ba97b58 ("netfilter: nf_tables: Introduce stateful object update operation") Cc: Fernando Fernandez Mancera <ffmancera@riseup.net> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- net/netfilter/nf_tables_api.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 3081c4399f10..7982268d0001 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6909,12 +6909,16 @@ static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info, return err; } -static void nft_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj) +static void nft_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj, + bool update) { if (obj->ops->destroy) obj->ops->destroy(ctx, obj); - module_put(obj->ops->type->owner); + /* nf_tables_updobj does not increment module refcount */ + if (!update) + module_put(obj->ops->type->owner); + kfree(obj->key.name); kfree(obj->udata); kfree(obj); @@ -8185,7 +8189,7 @@ static void nft_obj_commit_update(struct nft_trans *trans) if (obj->ops->update) obj->ops->update(obj, newobj); - kfree(newobj); + nft_obj_destroy(&trans->ctx, newobj, true); } static void nft_commit_release(struct nft_trans *trans) @@ -8213,7 +8217,7 @@ static void nft_commit_release(struct nft_trans *trans) nft_trans_elem(trans).priv); break; case NFT_MSG_DELOBJ: - nft_obj_destroy(&trans->ctx, nft_trans_obj(trans)); + nft_obj_destroy(&trans->ctx, nft_trans_obj(trans), false); break; case NFT_MSG_DELFLOWTABLE: if (nft_trans_flowtable_update(trans)) @@ -8853,7 +8857,7 @@ static void nf_tables_abort_release(struct nft_trans *trans) nft_trans_elem(trans).priv, true); break; case NFT_MSG_NEWOBJ: - nft_obj_destroy(&trans->ctx, nft_trans_obj(trans)); + nft_obj_destroy(&trans->ctx, nft_trans_obj(trans), false); break; case NFT_MSG_NEWFLOWTABLE: if (nft_trans_flowtable_update(trans)) @@ -8976,7 +8980,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) break; case NFT_MSG_NEWOBJ: if (nft_trans_obj_update(trans)) { - kfree(nft_trans_obj_newobj(trans)); + nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans), true); nft_trans_destroy(trans); } else { trans->ctx.table->use--; @@ -9693,7 +9697,7 @@ static void __nft_release_table(struct net *net, struct nft_table *table) list_for_each_entry_safe(obj, ne, &table->objects, list) { nft_obj_del(obj); table->use--; - nft_obj_destroy(&ctx, obj); + nft_obj_destroy(&ctx, obj, false); } list_for_each_entry_safe(chain, nc, &table->chains, list) { ctx.chain = chain; -- 2.30.2 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 nf] netfilter: nf_tables: fix memory leak during stateful obj update 2022-02-21 10:34 ` Pablo Neira Ayuso @ 2022-02-21 10:46 ` Florian Westphal 2022-02-21 10:59 ` Florian Westphal 0 siblings, 1 reply; 5+ messages in thread From: Florian Westphal @ 2022-02-21 10:46 UTC (permalink / raw) To: Pablo Neira Ayuso Cc: Florian Westphal, netfilter-devel, Fernando Fernandez Mancera Pablo Neira Ayuso <pablo@netfilter.org> wrote: > On Sun, Feb 20, 2022 at 12:18:50PM +0100, Florian Westphal wrote: > > stateful objects can be updated from the control plane. > > The transaction logic allocates a temporary object for this purpose. > > > > This object has to be released via nft_obj_destroy, not kfree, since > > the ->init function was called and it can have side effects beyond > > memory allocation. > > > > Unlike normal NEWOBJ path, the objects module refcount isn't > > incremented, so add nft_newobj_destroy and use that. > > Probably this? .udata and .key is NULL for the update path so kfree > should be fine. Yes, that works too. We could also ... > - module_put(obj->ops->type->owner); > + /* nf_tables_updobj does not increment module refcount */ > + if (!update) > + module_put(obj->ops->type->owner); > + Increment the refcount for update case as well to avoid the special case? ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 nf] netfilter: nf_tables: fix memory leak during stateful obj update 2022-02-21 10:46 ` Florian Westphal @ 2022-02-21 10:59 ` Florian Westphal 2022-02-21 11:39 ` Pablo Neira Ayuso 0 siblings, 1 reply; 5+ messages in thread From: Florian Westphal @ 2022-02-21 10:59 UTC (permalink / raw) To: Florian Westphal Cc: Pablo Neira Ayuso, netfilter-devel, Fernando Fernandez Mancera Florian Westphal <fw@strlen.de> wrote: > Pablo Neira Ayuso <pablo@netfilter.org> wrote: > > On Sun, Feb 20, 2022 at 12:18:50PM +0100, Florian Westphal wrote: > > > stateful objects can be updated from the control plane. > > > The transaction logic allocates a temporary object for this purpose. > > > > > > This object has to be released via nft_obj_destroy, not kfree, since > > > the ->init function was called and it can have side effects beyond > > > memory allocation. > > > > > > Unlike normal NEWOBJ path, the objects module refcount isn't > > > incremented, so add nft_newobj_destroy and use that. > > > > Probably this? .udata and .key is NULL for the update path so kfree > > should be fine. > > Yes, that works too. > > We could also ... > > > - module_put(obj->ops->type->owner); > > + /* nf_tables_updobj does not increment module refcount */ > > + if (!update) > > + module_put(obj->ops->type->owner); > > + > > Increment the refcount for update case as well to avoid the special > case? Untested: diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 3081c4399f10..49060f281342 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6553,10 +6553,13 @@ static int nf_tables_updobj(const struct nft_ctx *ctx, struct nft_trans *trans; int err; + if (!try_module_get(type->owner)) + return -ENOENT; + trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ, sizeof(struct nft_trans_obj)); if (!trans) - return -ENOMEM; + goto err_trans; newobj = nft_obj_init(ctx, type, attr); if (IS_ERR(newobj)) { @@ -6573,6 +6576,8 @@ static int nf_tables_updobj(const struct nft_ctx *ctx, err_free_trans: kfree(trans); +err_trans: + module_put(type->owner); return err; } @@ -8185,7 +8190,7 @@ static void nft_obj_commit_update(struct nft_trans *trans) if (obj->ops->update) obj->ops->update(obj, newobj); - kfree(newobj); + nft_obj_destroy(&trans->ctx, newobj); } static void nft_commit_release(struct nft_trans *trans) @@ -8976,7 +8981,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) break; case NFT_MSG_NEWOBJ: if (nft_trans_obj_update(trans)) { - kfree(nft_trans_obj_newobj(trans)); + nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans)); nft_trans_destroy(trans); } else { trans->ctx.table->use--; ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 nf] netfilter: nf_tables: fix memory leak during stateful obj update 2022-02-21 10:59 ` Florian Westphal @ 2022-02-21 11:39 ` Pablo Neira Ayuso 0 siblings, 0 replies; 5+ messages in thread From: Pablo Neira Ayuso @ 2022-02-21 11:39 UTC (permalink / raw) To: Florian Westphal; +Cc: netfilter-devel, Fernando Fernandez Mancera On Mon, Feb 21, 2022 at 11:59:22AM +0100, Florian Westphal wrote: > Florian Westphal <fw@strlen.de> wrote: > > Pablo Neira Ayuso <pablo@netfilter.org> wrote: > > > On Sun, Feb 20, 2022 at 12:18:50PM +0100, Florian Westphal wrote: > > > > stateful objects can be updated from the control plane. > > > > The transaction logic allocates a temporary object for this purpose. > > > > > > > > This object has to be released via nft_obj_destroy, not kfree, since > > > > the ->init function was called and it can have side effects beyond > > > > memory allocation. > > > > > > > > Unlike normal NEWOBJ path, the objects module refcount isn't > > > > incremented, so add nft_newobj_destroy and use that. > > > > > > Probably this? .udata and .key is NULL for the update path so kfree > > > should be fine. > > > > Yes, that works too. > > > > We could also ... > > > > > - module_put(obj->ops->type->owner); > > > + /* nf_tables_updobj does not increment module refcount */ > > > + if (!update) > > > + module_put(obj->ops->type->owner); > > > + > > > > Increment the refcount for update case as well to avoid the special > > case? Yes, I also though of this one. I prefer this approach indeed to consolidate this path. Would you test and submit v3? Thanks! > Untested: > > diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c > index 3081c4399f10..49060f281342 100644 > --- a/net/netfilter/nf_tables_api.c > +++ b/net/netfilter/nf_tables_api.c > @@ -6553,10 +6553,13 @@ static int nf_tables_updobj(const struct nft_ctx *ctx, > struct nft_trans *trans; > int err; > > + if (!try_module_get(type->owner)) > + return -ENOENT; > + > trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ, > sizeof(struct nft_trans_obj)); > if (!trans) > - return -ENOMEM; > + goto err_trans; > > newobj = nft_obj_init(ctx, type, attr); > if (IS_ERR(newobj)) { > @@ -6573,6 +6576,8 @@ static int nf_tables_updobj(const struct nft_ctx *ctx, > > err_free_trans: > kfree(trans); > +err_trans: > + module_put(type->owner); > return err; > } > > @@ -8185,7 +8190,7 @@ static void nft_obj_commit_update(struct nft_trans *trans) > if (obj->ops->update) > obj->ops->update(obj, newobj); > > - kfree(newobj); > + nft_obj_destroy(&trans->ctx, newobj); > } > > static void nft_commit_release(struct nft_trans *trans) > @@ -8976,7 +8981,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) > break; > case NFT_MSG_NEWOBJ: > if (nft_trans_obj_update(trans)) { > - kfree(nft_trans_obj_newobj(trans)); > + nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans)); > nft_trans_destroy(trans); > } else { > trans->ctx.table->use--; ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2022-02-21 11:39 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2022-02-20 11:18 [PATCH v2 nf] netfilter: nf_tables: fix memory leak during stateful obj update Florian Westphal 2022-02-21 10:34 ` Pablo Neira Ayuso 2022-02-21 10:46 ` Florian Westphal 2022-02-21 10:59 ` Florian Westphal 2022-02-21 11:39 ` Pablo Neira Ayuso
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).