nftables/0037-json-Introduce-json_add_array_new.patch
Phil Sutter 63fbb66589 nftables-1.0.9-8.el9
* Tue Jun 30 2026 Phil Sutter <psutter@redhat.com> [1.0.9-8.el9]
- parser_json: fix map/set type confusion crash in map statement parser (Phil Sutter) [RHEL-190549]
- parser_json: bail out on malformed statement in set (Phil Sutter) [RHEL-190549]
- parser_json: allow statement stateful statement only in set elements (Phil Sutter) [RHEL-190549]
- parser_json: fix crash in json_parse_set_stmt_list (Phil Sutter) [RHEL-190549]
- cache: honor -c/--check for reset commands (Phil Sutter) [RHEL-190549]
- mnl: Fix ordering of hooks in 'list hooks' output (Phil Sutter) [RHEL-190549]
- segtree: Fix for variable-sized object may not be initialized (Phil Sutter) [RHEL-190549]
- cache: Filter for table when listing flowtables (Phil Sutter) [RHEL-190549]
- cache: Filter for table when listing sets or maps (Phil Sutter) [RHEL-190549]
- cache: Relax chain_cache_dump filter application (Phil Sutter) [RHEL-190549]
- cache: Respect family in all list commands (Phil Sutter) [RHEL-190549]
- json: complete multi-statement set element support (Phil Sutter) [RHEL-190549]
- mergesort: Align concatenation sort order with Big Endian (Phil Sutter) [RHEL-190549]
- optimize: expand expression list when merging into concatenation (Phil Sutter) [RHEL-190549]
- mergesort: Fix sorting of string values (Phil Sutter) [RHEL-190549]
- segtree: Fix range aggregation on Big Endian (Phil Sutter) [RHEL-190549]
- monitor: fix memleak in setelem cb (Phil Sutter) [RHEL-190549]
- tests: json_echo: Drop rule handle before multi-add (Phil Sutter) [RHEL-190549]
- rule: skip CMD_OBJ_SETELEMS with no elements after set flush (Phil Sutter) [RHEL-190549]
- doc: libnftables-json: Describe RULESET object (Phil Sutter) [RHEL-190549]
- doc: don't suggest to disable GSO (Phil Sutter) [RHEL-190549]
- tests: py: inet/osf.t: Fix element ordering in JSON equivalents (Phil Sutter) [RHEL-190549]
- tests: py: any/ct.t.json.output: Drop leftover entry (Phil Sutter) [RHEL-190549]
- optimize: Fix verdict expression comparison (Phil Sutter) [RHEL-190549]
- datatype: Fix boolean type on Big Endian (Phil Sutter) [RHEL-190549]
- datatype: clamp boolean value to 0 and 1 (Phil Sutter) [RHEL-190549]
- src: parser_json: fix format string bugs (Phil Sutter) [RHEL-190549]
- doc: fix tcpdump example (Phil Sutter) [RHEL-190549]
- fib: Fix for existence check on Big Endian (Phil Sutter) [RHEL-190549]
- monitor: Inform JSON printer when reporting an object delete event (Phil Sutter) [RHEL-190549]
- tests: monitor: Fix regex collecting expected echo output (Phil Sutter) [RHEL-190549]
- monitor: Quote device names in chain declarations, too (Phil Sutter) [RHEL-190549]
- mnl: continue on ENOBUFS errors when processing batch (Phil Sutter) [RHEL-190549]
- mnl: silence compiler warning (Phil Sutter) [RHEL-190549]
- fib: restore JSON output for relational expressions (Phil Sutter) [RHEL-190549]
- json: Do not reduce single-item arrays on output (Phil Sutter) [RHEL-190549]
- src: ensure chain policy evaluation when specified (Phil Sutter) [RHEL-190549]
- segtree: incorrect type when aggregating concatenated set ranges (Phil Sutter) [RHEL-190549]
- tests: py: Fix tests added for 'icmpv6 taddr' support (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entry from ip/snat.t.payload (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entries from ip6/{ct,meta}.t.json (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entry from ip/snat.t.json (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/vxlan.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entry from inet/tcp.t.json (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/gretap.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/gre.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop duplicate test from inet/geneve.t (Phil Sutter) [RHEL-190549]
- tests: py: Drop stale entries since redundant test case removal (Phil Sutter) [RHEL-190549]
- src: netlink: netlink_delinearize_table() may return NULL (Phil Sutter) [RHEL-190549]
- doc: nft.8: Minor NAT STATEMENTS section review (Phil Sutter) [RHEL-190549]
- mnl: Call mnl_attr_nest_end() just once (Phil Sutter) [RHEL-190549]
- evaluate: validate set expression type before accessing flags (Phil Sutter) [RHEL-190549]
- rule: print chain and flowtable devices in quotes (Phil Sutter) [RHEL-190549]
- tests: shell: skip if kernel does not support flowtable counter (Phil Sutter) [RHEL-190549]
- tests: shell: adjust add-after-delete flowtable for older kernels (Phil Sutter) [RHEL-190549]
- tests/shell: cover long interface name in "0042chain_variable_0" test (Phil Sutter) [RHEL-190549]
- tests: py: re-enables nft-test.py to load the local nftables.py (Phil Sutter) [RHEL-190549]
- fib: allow to use it in set statements (Phil Sutter) [RHEL-190549]
- fib: allow to check if route exists in maps (Phil Sutter) [RHEL-190549]
- tests: py: fix json single-flag output for fib & synproxy (Phil Sutter) [RHEL-190549]
- parser_json: Introduce parse_flags_array() (Phil Sutter) [RHEL-190549]
- json: work around fuzzer-induced assert crashes (Phil Sutter) [RHEL-190549]
- json: Introduce json_add_array_new() (Phil Sutter) [RHEL-190549]
- json: Print single synproxy flags as non-array (Phil Sutter) [RHEL-190549]
- json: Print single fib flag as non-array (Phil Sutter) [RHEL-190549]
- json: fix use after free in table_flags_json() (Phil Sutter) [RHEL-190549]
- doc: extend description of fib expression (Phil Sutter) [RHEL-190549]
- json: reject too long interface names (Phil Sutter) [RHEL-190549]
- parser_bison: allow delete command with map via handle (Phil Sutter) [RHEL-190549]
- parser_bison: only reset by name is supported by now (Phil Sutter) [RHEL-190549]
- cache: assert name is non-nul when looking up (Phil Sutter) [RHEL-190549]
- rule: skip fuzzy lookup if object name is not available (Phil Sutter) [RHEL-190549]
- src: BASECHAIN flag no longer implies presence of priority expression (Phil Sutter) [RHEL-190549]
- netlink: Avoid crash upon missing NFTNL_OBJ_CT_TIMEOUT_ARRAY attribute (Phil Sutter) [RHEL-190549]
- tests: py: Properly fix JSON equivalents for netdev/reject.t (Phil Sutter) [RHEL-190549]
- tests: monitor: Fix for single flag array avoidance (Phil Sutter) [RHEL-190549]
- json: Support typeof in set and map types (Phil Sutter) [RHEL-190549]
- netlink: Do not allocate a bogus flowtable priority expr (Phil Sutter) [RHEL-190549]
- netlink: Fix for potential crash parsing a flowtable (Phil Sutter) [RHEL-190549]
- json: prevent null deref if chain->policy is not set (Phil Sutter) [RHEL-190549]
- netlink: Catch unknown types when deserializing objects (Phil Sutter) [RHEL-190549]
- netlink: Avoid potential NULL-ptr deref parsing set elem expressions (Phil Sutter) [RHEL-190549]
- json: Print single set flag as non-array (Phil Sutter) [RHEL-190549]
- doc: Fix typo in nat statement 'prefix' description (Phil Sutter) [RHEL-190549]
Resolves: RHEL-190549
2026-06-30 19:42:31 +02:00

222 lines
6.6 KiB
Diff

From a3f57e683bbf70bbba05bd495a2f5d8c32eb6aa4 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 30 Jun 2026 14:25:20 +0200
Subject: [PATCH] json: Introduce json_add_array_new()
JIRA: https://issues.redhat.com/browse/RHEL-190549
Upstream Status: nftables commit a740f2036ad0d50b4a91e110611563809dac420a
Conflicts: Context change due to missing commit a0a15e4dd0576
("json: Fix for memleak in __binop_expr_json")
commit a740f2036ad0d50b4a91e110611563809dac420a
Author: Phil Sutter <phil@nwl.cc>
Date: Thu May 8 17:28:02 2025 +0200
json: Introduce json_add_array_new()
Propagate nat_stmt_add_array() to a generic helper for use in all spots
adding an array property which may reduce to a single item or even not
exist at all.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/json.c | 99 +++++++++++++-----------------------------------------
1 file changed, 24 insertions(+), 75 deletions(-)
diff --git a/src/json.c b/src/json.c
index 9b3a639..c8abc56 100644
--- a/src/json.c
+++ b/src/json.c
@@ -42,6 +42,18 @@
})
#endif
+static void json_add_array_new(json_t *obj, const char *name, json_t *array)
+{
+ if (json_array_size(array) > 1) {
+ json_object_set_new(obj, name, array);
+ } else {
+ if (json_array_size(array))
+ json_object_set(obj, name,
+ json_array_get(array, 0));
+ json_decref(array);
+ }
+}
+
static json_t *expr_print_json(const struct expr *expr, struct output_ctx *octx)
{
const struct expr_ops *ops;
@@ -188,14 +200,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
json_array_append_new(tmp, json_pack("s", "timeout"));
if (set->flags & NFT_SET_EVAL)
json_array_append_new(tmp, json_pack("s", "dynamic"));
-
- if (json_array_size(tmp) > 1) {
- json_object_set_new(root, "flags", tmp);
- } else {
- if (json_array_size(tmp))
- json_object_set(root, "flags", json_array_get(tmp, 0));
- json_decref(tmp);
- }
+ json_add_array_new(root, "flags", tmp);
if (set->timeout) {
tmp = json_integer(set->timeout / 1000);
@@ -443,19 +448,16 @@ static json_t *obj_print_json(const struct obj *obj)
json_decref(tmp);
break;
case NFT_OBJECT_SYNPROXY:
- flags = json_array();
tmp = json_pack("{s:i, s:i}",
"mss", obj->synproxy.mss,
"wscale", obj->synproxy.wscale);
+
+ flags = json_array();
if (obj->synproxy.flags & NF_SYNPROXY_OPT_TIMESTAMP)
json_array_append_new(flags, json_string("timestamp"));
if (obj->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
json_array_append_new(flags, json_string("sack-perm"));
-
- if (json_array_size(flags) > 0)
- json_object_set_new(tmp, "flags", flags);
- else
- json_decref(flags);
+ json_add_array_new(tmp, "flags", flags);
json_object_update(root, tmp);
json_decref(tmp);
@@ -512,31 +514,18 @@ static json_t *table_flags_json(const struct table *table)
flags >>= 1;
i++;
}
- switch (json_array_size(root)) {
- case 0:
- json_decref(root);
- return NULL;
- case 1:
- json_unpack(root, "[O]", &tmp);
- json_decref(root);
- root = tmp;
- break;
- }
return root;
}
static json_t *table_print_json(const struct table *table)
{
- json_t *root, *tmp;
+ json_t *root;
root = json_pack("{s:s, s:s, s:I}",
"family", family2str(table->handle.family),
"name", table->handle.table.name,
"handle", table->handle.handle.id);
-
- tmp = table_flags_json(table);
- if (tmp)
- json_object_set_new(root, "flags", tmp);
+ json_add_array_new(root, "flags", table_flags_json(table));
if (table->comment)
json_object_set_new(root, "comment", json_string(table->comment));
@@ -936,14 +925,7 @@ json_t *fib_expr_json(const struct expr *expr, struct output_ctx *octx)
if (flags)
json_array_append_new(tmp, json_integer(flags));
- if (json_array_size(tmp) > 1) {
- json_object_set_new(root, "flags", tmp);
- } else {
- if (json_array_size(tmp))
- json_object_set(root, "flags",
- json_array_get(tmp, 0));
- json_decref(tmp);
- }
+ json_add_array_new(root, "flags", tmp);
}
return json_pack("{s:o}", "fib", root);
}
@@ -1383,14 +1365,7 @@ json_t *log_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
if (stmt->log.logflags & NF_LOG_MACDECODE)
json_array_append_new(flags, json_string("ether"));
}
- if (json_array_size(flags) > 1) {
- json_object_set_new(root, "flags", flags);
- } else {
- if (json_array_size(flags))
- json_object_set(root, "flags",
- json_array_get(flags, 0));
- json_decref(flags);
- }
+ json_add_array_new(root, "flags", flags);
if (!json_object_size(root)) {
json_decref(root);
@@ -1425,18 +1400,6 @@ static json_t *nat_type_flags_json(uint32_t type_flags)
return array;
}
-static void nat_stmt_add_array(json_t *root, const char *name, json_t *array)
-{
- if (json_array_size(array) > 1) {
- json_object_set_new(root, name, array);
- } else {
- if (json_array_size(array))
- json_object_set(root, name,
- json_array_get(array, 0));
- json_decref(array);
- }
-}
-
json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
{
json_t *root = json_object();
@@ -1458,12 +1421,12 @@ json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
json_object_set_new(root, "port",
expr_print_json(stmt->nat.proto, octx));
- nat_stmt_add_array(root, "flags", array);
+ json_add_array_new(root, "flags", array);
if (stmt->nat.type_flags) {
array = nat_type_flags_json(stmt->nat.type_flags);
- nat_stmt_add_array(root, "type_flags", array);
+ json_add_array_new(root, "type_flags", array);
}
if (!json_object_size(root)) {
@@ -1615,14 +1578,7 @@ json_t *queue_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
json_array_append_new(flags, json_string("bypass"));
if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT)
json_array_append_new(flags, json_string("fanout"));
- if (json_array_size(flags) > 1) {
- json_object_set_new(root, "flags", flags);
- } else {
- if (json_array_size(flags))
- json_object_set(root, "flags",
- json_array_get(flags, 0));
- json_decref(flags);
- }
+ json_add_array_new(root, "flags", flags);
if (!json_object_size(root)) {
json_decref(root);
@@ -1685,14 +1641,7 @@ json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
if (stmt->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
json_array_append_new(flags, json_string("sack-perm"));
- if (json_array_size(flags) > 1) {
- json_object_set_new(root, "flags", flags);
- } else {
- if (json_array_size(flags))
- json_object_set(root, "flags",
- json_array_get(flags, 0));
- json_decref(flags);
- }
+ json_add_array_new(root, "flags", flags);
if (!json_object_size(root)) {
json_decref(root);