[PATCH] netfilter: nf_tables: fix memory leak during stateful obj update

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
Signed-off-by: Florian Westphal <fw@xxxxxxxxx>
Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
---
 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


--pANdPOM7e9+z0cre--



[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux