From 3bcd138f2baa8578caf261768e67b58ff3372f91 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 17 Jul 2026 11:14:03 +0200 Subject: [PATCH] json: Fix for memleak in __binop_expr_json JIRA: https://issues.redhat.com/browse/RHEL-190549 Upstream Status: nftables commit a0a15e4dd0576bc4efd9b01fdd4ee1c565effac9 commit a0a15e4dd0576bc4efd9b01fdd4ee1c565effac9 Author: Phil Sutter Date: Wed Apr 24 23:35:00 2024 +0200 json: Fix for memleak in __binop_expr_json When merging the JSON arrays generated for LHS and RHS of nested binop expressions, the emptied array objects leak if their reference is not decremented. Fix this and tidy up other spots which did it right already by introducing a json_array_extend wrapper. Reported-by: Pablo Neira Ayuso Fixes: 0ac39384fd9e4 ("json: Accept more than two operands in binary expressions") Signed-off-by: Phil Sutter Signed-off-by: Phil Sutter --- src/json.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/json.c b/src/json.c index 089c251..516045b 100644 --- a/src/json.c +++ b/src/json.c @@ -42,6 +42,15 @@ }) #endif +static int json_array_extend_new(json_t *array, json_t *other_array) +{ + int ret; + + ret = json_array_extend(array, other_array); + json_decref(other_array); + return ret; +} + static json_t *expr_print_json(const struct expr *expr, struct output_ctx *octx) { const struct expr_ops *ops; @@ -557,8 +566,10 @@ __binop_expr_json(int op, const struct expr *expr, struct output_ctx *octx) json_t *a = json_array(); if (expr->etype == EXPR_BINOP && expr->op == op) { - json_array_extend(a, __binop_expr_json(op, expr->left, octx)); - json_array_extend(a, __binop_expr_json(op, expr->right, octx)); + json_array_extend_new(a, + __binop_expr_json(op, expr->left, octx)); + json_array_extend_new(a, + __binop_expr_json(op, expr->right, octx)); } else { json_array_append_new(a, expr_print_json(expr, octx)); } @@ -1761,8 +1772,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx, } } - json_array_extend(root, rules); - json_decref(rules); + json_array_extend_new(root, rules); return root; } @@ -1770,7 +1780,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx, static json_t *do_list_ruleset_json(struct netlink_ctx *ctx, struct cmd *cmd) { unsigned int family = cmd->handle.family; - json_t *root = json_array(), *tmp; + json_t *root = json_array(); struct table *table; list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) { @@ -1778,9 +1788,7 @@ static json_t *do_list_ruleset_json(struct netlink_ctx *ctx, struct cmd *cmd) table->handle.family != family) continue; - tmp = table_print_json_full(ctx, table); - json_array_extend(root, tmp); - json_decref(tmp); + json_array_extend_new(root, table_print_json_full(ctx, table)); } return root;