]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
parser_json: initialize geneve options list for empty tunnel array
authorOmkhar Arasaratnam <omkhar@linkedin.com>
Wed, 8 Jul 2026 23:09:52 +0000 (23:09 +0000)
committerFlorian Westphal <fw@strlen.de>
Thu, 9 Jul 2026 08:03:52 +0000 (10:03 +0200)
json_parse_cmd_add_object() only initializes obj->tunnel.geneve_opts on
the first iteration of the json_array_foreach() loop, guarded by
"if (index == 0)". A geneve tunnel object whose options array is empty
("tunnel": []) never enters the loop, so the list head is left
uninitialized. obj_tunnel_add_opts() (src/mnl.c) later walks it with
list_for_each_entry() and passes the bogus element to libnftnl, which
dereferences the near-NULL pointer and crashes nft:

  # nft -j -f empty_geneve.json
  AddressSanitizer: SEGV on unknown address 0x000000000012
    #1 nftnl_tunnel_opt_geneve_set  obj/tunnel.c:880
    #2 nftnl_tunnel_opt_set         obj/tunnel.c:910
    #3 obj_tunnel_add_opts          src/mnl.c:1608
    #4 mnl_nft_obj_add              src/mnl.c:1757
    #5 do_command_add               src/rule.c:1542

Initialize the list head unconditionally before the loop and drop the
per-iteration guard, so an empty array leaves a valid empty list. The
equivalent native-syntax empty definition was already handled in commit
f9047c1f ("evaluate: tunnel: don't assume src is set"); this covers the
JSON parser path, which that fix did not reach.

Fixes: 3a957f8f1ff1 ("tunnel: add tunnel object and statement json support")
Signed-off-by: Omkhar Arasaratnam <omkhar@linkedin.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
src/parser_json.c
tests/shell/testcases/bogons/nft-j-f/empty_tunnel_option_array [new file with mode: 0644]

index f04772a022a0b6061e625f6bbea776db5e850a50..6a0c17459e7f67e35e3c1595a701ec74e7453d58 100644 (file)
@@ -3941,6 +3941,8 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
                                            "{s:o}", "tunnel", &tmp_json))
                                goto err_free_obj;
 
+                       init_list_head(&obj->tunnel.geneve_opts);
+
                        json_array_foreach(tmp_json, index, value) {
                                struct tunnel_geneve *geneve = xmalloc(sizeof(struct tunnel_geneve));
                                if (!geneve)
@@ -3963,9 +3965,6 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
                                        goto err_free_obj;
                                }
 
-                               if (index == 0)
-                                       init_list_head(&obj->tunnel.geneve_opts);
-
                                list_add_tail(&geneve->list, &obj->tunnel.geneve_opts);
                        }
                        break;
diff --git a/tests/shell/testcases/bogons/nft-j-f/empty_tunnel_option_array b/tests/shell/testcases/bogons/nft-j-f/empty_tunnel_option_array
new file mode 100644 (file)
index 0000000..9e8afbe
--- /dev/null
@@ -0,0 +1,5 @@
+{ "nftables": [
+ { "add": { "table": { "family": "netdev", "name": "x" } } },
+ { "add": { "tunnel": { "family": "netdev", "name": "t", "table": "y",
+   "src-ipv4": "192.168.2.10", "dst-ipv4": "",
+   "type": "geneve", "tunnel": [] } } } ] }