diff mbox series

[nft,3/4] parser_json: fix handle memleak from error path

Message ID 20240819222304.1041208-4-pablo@netfilter.org
State Accepted
Headers show
Series fixes for json parser | expand

Commit Message

Pablo Neira Ayuso Aug. 19, 2024, 10:23 p.m. UTC
Based on patch from Sebastian Walz.

Fixes: 586ad210368b ("libnftables: Implement JSON parser")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 src/parser_json.c | 93 ++++++++++++++++++++++++-----------------------
 1 file changed, 47 insertions(+), 46 deletions(-)
diff mbox series

Patch

diff --git a/src/parser_json.c b/src/parser_json.c
index 8ca44efbb52e..d18188d81b3f 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3168,8 +3168,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);
@@ -3178,8 +3177,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;
 		}
 	}
 
@@ -3187,8 +3185,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;
 		}
 	}
 
@@ -3197,6 +3194,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,
@@ -3236,6 +3238,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;
 	}
 
@@ -3255,16 +3258,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);
@@ -3274,6 +3275,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)
@@ -3654,8 +3660,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;
@@ -3671,8 +3676,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)) {
@@ -3682,15 +3686,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;
@@ -3704,23 +3706,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;
@@ -3728,8 +3726,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)) {
@@ -3739,8 +3736,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))
@@ -3754,10 +3750,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);
@@ -3778,20 +3773,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;
@@ -3803,6 +3796,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,
@@ -3917,8 +3915,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);
@@ -3926,8 +3923,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);
@@ -3937,6 +3933,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,