]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
parser_json: only allow concatenations with 2 or more expressions
authorFlorian Westphal <fw@strlen.de>
Wed, 2 Apr 2025 05:18:18 +0000 (07:18 +0200)
committerFlorian Westphal <fw@strlen.de>
Wed, 2 Apr 2025 09:18:21 +0000 (11:18 +0200)
The bison parser enforces this implicitly by grammar rules.
Because subkeys have to be conatenated via ".", notation, e.g.
"mark . ip saddr", all concatenation expressions always consist of at
least two elements.

But this doesn't apply to the json frontend which just uses an array:
it can be empty or only contain one element.

The included reproducer makes the eval stage set the "concatenation" flag
on the interval set.  This prevents the needed conversion code to turn the
element values into ranges from getting run.

The reproducer asserts with:
nft: src/intervals.c:786: setelem_to_interval: Assertion `key->etype == EXPR_RANGE_VALUE' failed.

Convert the assertion to BUG() so we can see what element type got passed
to the set interval code in case we have further issues in this area.

Reject 0-or-1-element concatenations from the json parser.

Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/intervals.c
src/parser_json.c
tests/shell/testcases/bogons/nft-j-f/set_with_single_value_concat_assert [new file with mode: 0644]

index 71ad210bf759e1bd8bf12416c2d4dada90583dab..1ab443bcde87e4bc2127d89cb272647564634334 100644 (file)
@@ -783,7 +783,9 @@ int setelem_to_interval(const struct set *set, struct expr *elem,
                        next_key = NULL;
        }
 
-       assert(key->etype == EXPR_RANGE_VALUE);
+       if (key->etype != EXPR_RANGE_VALUE)
+               BUG("key must be RANGE_VALUE, not %s\n", expr_name(key));
+
        assert(!next_key || next_key->etype == EXPR_RANGE_VALUE);
 
        /* skip end element for adjacents intervals in anonymous sets. */
index 94d09212314fe0f6e5aa914c729780d4eaed04ef..724cba8816235fdf2c25c97a49aa4f1ba10090e2 100644 (file)
@@ -1251,6 +1251,16 @@ static struct expr *json_parse_binop_expr(struct json_ctx *ctx,
        return binop_expr_alloc(int_loc, thisop, left, right);
 }
 
+static struct expr *json_check_concat_expr(struct json_ctx *ctx, struct expr *e)
+{
+       if (e->size >= 2)
+               return e;
+
+       json_error(ctx, "Concatenation with %d elements is illegal", e->size);
+       expr_free(e);
+       return NULL;
+}
+
 static struct expr *json_parse_concat_expr(struct json_ctx *ctx,
                                           const char *type, json_t *root)
 {
@@ -1284,7 +1294,7 @@ static struct expr *json_parse_concat_expr(struct json_ctx *ctx,
                }
                compound_expr_add(expr, tmp);
        }
-       return expr;
+       return expr ? json_check_concat_expr(ctx, expr) : NULL;
 }
 
 static struct expr *json_parse_prefix_expr(struct json_ctx *ctx,
@@ -1748,13 +1758,7 @@ static struct expr *json_parse_dtype_expr(struct json_ctx *ctx, json_t *root)
                        compound_expr_add(expr, i);
                }
 
-               if (list_empty(&expr->expressions)) {
-                       json_error(ctx, "Empty concatenation");
-                       expr_free(expr);
-                       return NULL;
-               }
-
-               return expr;
+               return json_check_concat_expr(ctx, expr);
        } else if (json_is_object(root)) {
                const char *key;
                json_t *val;
diff --git a/tests/shell/testcases/bogons/nft-j-f/set_with_single_value_concat_assert b/tests/shell/testcases/bogons/nft-j-f/set_with_single_value_concat_assert
new file mode 100644 (file)
index 0000000..c99a266
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  "nftables": [
+    {
+  "metainfo": {
+   "version": "nftables", "json_schema_version": 1
+      }
+    },
+    {
+      "table": {
+       "family": "ip",
+       "name": "t",
+        "handle": 0
+      }
+    },
+    {
+      "set": {
+        "family": "ip",
+        "name": "s",
+        "table": "t",
+       "type": [ "ifname" ],
+        "flags": [ "interval" ],
+        "elem": [ [] ]
+      }
+    }
+  ]
+}