281 lines
8.6 KiB
Diff
281 lines
8.6 KiB
Diff
From c7225a21a31131edd16f018a4e4947944db88f01 Mon Sep 17 00:00:00 2001
|
|
From: Phil Sutter <psutter@redhat.com>
|
|
Date: Wed, 23 Apr 2025 14:26:47 +0200
|
|
Subject: [PATCH] parser_json: fix handle memleak from error path
|
|
|
|
JIRA: https://issues.redhat.com/browse/RHEL-88181
|
|
Upstream Status: nftables commit 47e18c0eba51a538e1110322d1a9248b0501d7c8
|
|
|
|
commit 47e18c0eba51a538e1110322d1a9248b0501d7c8
|
|
Author: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
Date: Mon Aug 19 21:34:49 2024 +0200
|
|
|
|
parser_json: fix handle memleak from error path
|
|
|
|
Based on patch from Sebastian Walz.
|
|
|
|
Fixes: 586ad210368b ("libnftables: Implement JSON parser")
|
|
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
|
|
Signed-off-by: Phil Sutter <psutter@redhat.com>
|
|
---
|
|
src/parser_json.c | 93 ++++++++++++++++++++++++-----------------------
|
|
1 file changed, 47 insertions(+), 46 deletions(-)
|
|
|
|
diff --git a/src/parser_json.c b/src/parser_json.c
|
|
index d57aa6b..2acc248 100644
|
|
--- a/src/parser_json.c
|
|
+++ b/src/parser_json.c
|
|
@@ -3138,8 +3138,7 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
|
|
chain->hook.name = chain_hookname_lookup(hookstr);
|
|
if (!chain->hook.name) {
|
|
json_error(ctx, "Invalid chain hook '%s'.", hookstr);
|
|
- chain_free(chain);
|
|
- return NULL;
|
|
+ goto err_free_chain;
|
|
}
|
|
|
|
json_unpack(root, "{s:o}", "dev", &devs);
|
|
@@ -3148,8 +3147,7 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
|
|
chain->dev_expr = json_parse_devs(ctx, devs);
|
|
if (!chain->dev_expr) {
|
|
json_error(ctx, "Invalid chain dev.");
|
|
- chain_free(chain);
|
|
- return NULL;
|
|
+ goto err_free_chain;
|
|
}
|
|
}
|
|
|
|
@@ -3157,8 +3155,7 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
|
|
chain->policy = parse_policy(policy);
|
|
if (!chain->policy) {
|
|
json_error(ctx, "Unknown policy '%s'.", policy);
|
|
- chain_free(chain);
|
|
- return NULL;
|
|
+ goto err_free_chain;
|
|
}
|
|
}
|
|
|
|
@@ -3167,6 +3164,11 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
|
|
|
|
handle_merge(&chain->handle, &h);
|
|
return cmd_alloc(op, obj, &h, int_loc, chain);
|
|
+
|
|
+err_free_chain:
|
|
+ chain_free(chain);
|
|
+ handle_free(&h);
|
|
+ return NULL;
|
|
}
|
|
|
|
static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
|
|
@@ -3206,6 +3208,7 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
|
|
|
|
if (!json_is_array(tmp)) {
|
|
json_error(ctx, "Value of property \"expr\" must be an array.");
|
|
+ handle_free(&h);
|
|
return NULL;
|
|
}
|
|
|
|
@@ -3225,16 +3228,14 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
|
|
if (!json_is_object(value)) {
|
|
json_error(ctx, "Unexpected expr array element of type %s, expected object.",
|
|
json_typename(value));
|
|
- rule_free(rule);
|
|
- return NULL;
|
|
+ goto err_free_rule;
|
|
}
|
|
|
|
stmt = json_parse_stmt(ctx, value);
|
|
|
|
if (!stmt) {
|
|
json_error(ctx, "Parsing expr array at index %zd failed.", index);
|
|
- rule_free(rule);
|
|
- return NULL;
|
|
+ goto err_free_rule;
|
|
}
|
|
|
|
rule_stmt_append(rule, stmt);
|
|
@@ -3244,6 +3245,11 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
|
|
json_object_del(root, "handle");
|
|
|
|
return cmd_alloc(op, obj, &h, int_loc, rule);
|
|
+
|
|
+err_free_rule:
|
|
+ rule_free(rule);
|
|
+ handle_free(&h);
|
|
+ return NULL;
|
|
}
|
|
|
|
static int string_to_nft_object(const char *str)
|
|
@@ -3617,8 +3623,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
if (ret < 0 || ret >= (int)sizeof(obj->secmark.ctx)) {
|
|
json_error(ctx, "Invalid secmark context '%s', max length is %zu.",
|
|
tmp, sizeof(obj->secmark.ctx));
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
}
|
|
break;
|
|
@@ -3634,8 +3639,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
ret >= (int)sizeof(obj->ct_helper.name)) {
|
|
json_error(ctx, "Invalid CT helper type '%s', max length is %zu.",
|
|
tmp, sizeof(obj->ct_helper.name));
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
}
|
|
if (!json_unpack(root, "{s:s}", "protocol", &tmp)) {
|
|
@@ -3645,15 +3649,13 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
obj->ct_helper.l4proto = IPPROTO_UDP;
|
|
} else {
|
|
json_error(ctx, "Invalid ct helper protocol '%s'.", tmp);
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
}
|
|
if (!json_unpack(root, "{s:s}", "l3proto", &tmp) &&
|
|
parse_family(tmp, &l3proto)) {
|
|
json_error(ctx, "Invalid ct helper l3proto '%s'.", tmp);
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
obj->ct_helper.l3proto = l3proto;
|
|
break;
|
|
@@ -3667,23 +3669,19 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
obj->ct_timeout.l4proto = IPPROTO_UDP;
|
|
} else {
|
|
json_error(ctx, "Invalid ct timeout protocol '%s'.", tmp);
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
}
|
|
if (!json_unpack(root, "{s:s}", "l3proto", &tmp) &&
|
|
parse_family(tmp, &l3proto)) {
|
|
json_error(ctx, "Invalid ct timeout l3proto '%s'.", tmp);
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
obj->ct_timeout.l3proto = l3proto;
|
|
|
|
init_list_head(&obj->ct_timeout.timeout_list);
|
|
- if (json_parse_ct_timeout_policy(ctx, root, obj)) {
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
- }
|
|
+ if (json_parse_ct_timeout_policy(ctx, root, obj))
|
|
+ goto err_free_obj;
|
|
break;
|
|
case NFT_OBJECT_CT_EXPECT:
|
|
cmd_obj = CMD_OBJ_CT_EXPECT;
|
|
@@ -3691,8 +3689,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
if (!json_unpack(root, "{s:s}", "l3proto", &tmp) &&
|
|
parse_family(tmp, &l3proto)) {
|
|
json_error(ctx, "Invalid ct expectation l3proto '%s'.", tmp);
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
obj->ct_expect.l3proto = l3proto;
|
|
if (!json_unpack(root, "{s:s}", "protocol", &tmp)) {
|
|
@@ -3702,8 +3699,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
obj->ct_expect.l4proto = IPPROTO_UDP;
|
|
} else {
|
|
json_error(ctx, "Invalid ct expectation protocol '%s'.", tmp);
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
+ goto err_free_obj;
|
|
}
|
|
}
|
|
if (!json_unpack(root, "{s:i}", "dport", &i))
|
|
@@ -3717,10 +3713,9 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
obj->type = NFT_OBJECT_LIMIT;
|
|
if (json_unpack_err(ctx, root, "{s:I, s:s}",
|
|
"rate", &obj->limit.rate,
|
|
- "per", &tmp)) {
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
- }
|
|
+ "per", &tmp))
|
|
+ goto err_free_obj;
|
|
+
|
|
json_unpack(root, "{s:s}", "rate_unit", &rate_unit);
|
|
json_unpack(root, "{s:b}", "inv", &inv);
|
|
json_unpack(root, "{s:i}", "burst", &obj->limit.burst);
|
|
@@ -3741,20 +3736,18 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
case CMD_OBJ_SYNPROXY:
|
|
obj->type = NFT_OBJECT_SYNPROXY;
|
|
if (json_unpack_err(ctx, root, "{s:i, s:i}",
|
|
- "mss", &i, "wscale", &j)) {
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
- }
|
|
+ "mss", &i, "wscale", &j))
|
|
+ goto err_free_obj;
|
|
+
|
|
obj->synproxy.mss = i;
|
|
obj->synproxy.wscale = j;
|
|
obj->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
|
|
obj->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
|
|
if (!json_unpack(root, "{s:o}", "flags", &jflags)) {
|
|
flags = json_parse_synproxy_flags(ctx, jflags);
|
|
- if (flags < 0) {
|
|
- obj_free(obj);
|
|
- return NULL;
|
|
- }
|
|
+ if (flags < 0)
|
|
+ goto err_free_obj;
|
|
+
|
|
obj->synproxy.flags |= flags;
|
|
}
|
|
break;
|
|
@@ -3766,6 +3759,11 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
|
|
json_object_del(root, "handle");
|
|
|
|
return cmd_alloc(op, cmd_obj, &h, int_loc, obj);
|
|
+
|
|
+err_free_obj:
|
|
+ obj_free(obj);
|
|
+ handle_free(&h);
|
|
+ return NULL;
|
|
}
|
|
|
|
static struct cmd *json_parse_cmd_add(struct json_ctx *ctx,
|
|
@@ -3879,8 +3877,7 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx,
|
|
if (!json_is_object(value)) {
|
|
json_error(ctx, "Unexpected expr array element of type %s, expected object.",
|
|
json_typename(value));
|
|
- rule_free(rule);
|
|
- return NULL;
|
|
+ goto err_free_replace;
|
|
}
|
|
|
|
stmt = json_parse_stmt(ctx, value);
|
|
@@ -3888,8 +3885,7 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx,
|
|
if (!stmt) {
|
|
json_error(ctx, "Parsing expr array at index %zd failed.",
|
|
index);
|
|
- rule_free(rule);
|
|
- return NULL;
|
|
+ goto err_free_replace;
|
|
}
|
|
|
|
rule_stmt_append(rule, stmt);
|
|
@@ -3899,6 +3895,11 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx,
|
|
json_object_del(root, "handle");
|
|
|
|
return cmd_alloc(op, CMD_OBJ_RULE, &h, int_loc, rule);
|
|
+
|
|
+err_free_replace:
|
|
+ rule_free(rule);
|
|
+ handle_free(&h);
|
|
+ return NULL;
|
|
}
|
|
|
|
static struct cmd *json_parse_cmd_list_multiple(struct json_ctx *ctx,
|