]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: do not merge a set with a erroneous one
authorFlorian Westphal <fw@strlen.de>
Fri, 12 Jan 2024 12:19:26 +0000 (13:19 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 23 Jan 2025 00:35:35 +0000 (01:35 +0100)
commit ea011231c06cbe828cf6056bc9c3d116e1f528d5 upstream.

The included sample causes a crash because we attempt to
range-merge a prefix expression with a symbolic expression.

The first set is evaluated, the symbol expression evaluation fails
and nft queues an error message ("Could not resolve hostname").

However, nft continues evaluation.

nft then encounters the same set definition again and merges the
new content with the preceeding one.

But the first set structure is dodgy, it still contains the
unresolved symbolic expression.

That then makes nft crash (assert) in the set internals.

There are various different incarnations of this issue, but the low
level set processing code does not allow for any partially transformed
expressions to still remain.

Before:
nft --check -f tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop
BUG: invalid range expression type binop
nft: src/expression.c:1479: range_expr_value_low: Assertion `0' failed.

After:
nft --check -f tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop
invalid_range_expr_type_binop:4:18-25: Error: Could not resolve hostname: Name or service not known
elements = { 1&.141.0.1 - 192.168.0.2}
             ^^^^^^^^

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

index c4d8166cb332a6c03862c0b048becc76ccd90e73..042fd3f0bc73f979f3823598136bd31c9320fa91 100644 (file)
@@ -331,6 +331,7 @@ void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
  * @policy:    set mechanism policy
  * @automerge: merge adjacents and overlapping elements, if possible
  * @comment:   comment
+ * @errors:    expr evaluation errors seen
  * @desc.size:         count of set elements
  * @desc.field_len:    length of single concatenated fields, bytes
  * @desc.field_count:  count of concatenated fields
@@ -355,6 +356,7 @@ struct set {
        bool                    root;
        bool                    automerge;
        bool                    key_typeof_valid;
+       bool                    errors;
        const char              *comment;
        struct {
                uint32_t        size;
index 098d9a11131eff3a31b1f8ca9bc495b51c82b445..b1c239ec92970f14a72ce1bb7fea30fc9cb01502 100644 (file)
@@ -4627,8 +4627,10 @@ static int elems_evaluate(struct eval_ctx *ctx, struct set *set)
        if (set->init != NULL) {
                __expr_set_context(&ctx->ectx, set->key->dtype,
                                   set->key->byteorder, set->key->len, 0);
-               if (expr_evaluate(ctx, &set->init) < 0)
+               if (expr_evaluate(ctx, &set->init) < 0) {
+                       set->errors = true;
                        return -1;
+               }
                if (set->init->etype != EXPR_SET)
                        return expr_error(ctx->msgs, set->init, "Set %s: Unexpected initial type %s, missing { }?",
                                          set->handle.set.name, expr_name(set->init));
index af48d5ec1ac0f70a0ffb931a1d2ccd3385867057..6dcca6042dc547caa57a25946b1bf1675080e5b2 100644 (file)
@@ -128,7 +128,7 @@ static void set_sort_splice(struct expr *init, struct set *set)
        set_to_range(init);
        list_expr_sort(&init->expressions);
 
-       if (!existing_set)
+       if (!existing_set || existing_set->errors)
                return;
 
        if (existing_set->init) {
diff --git a/tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop b/tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop
new file mode 100644 (file)
index 0000000..514d6ff
--- /dev/null
@@ -0,0 +1,12 @@
+table ip x {
+       map z {
+               type ipv4_addr : ipv4_addr
+               elements = { 1&.141.0.1 - 192.168.0.2}
+       }
+
+       map z {
+               type ipv4_addr : ipv4_addr
+               flags interval
+               elements = { 10.141.0.0, * : 192.168.0.4 }
+       }
+}