]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: check that set type is identical before merging
authorFlorian Westphal <fw@strlen.de>
Mon, 23 Jun 2025 19:37:31 +0000 (21:37 +0200)
committerFlorian Westphal <fw@strlen.de>
Wed, 25 Jun 2025 22:43:24 +0000 (00:43 +0200)
Reject maps and sets of the same name:
 BUG: invalid range expression type catch-all set element
 nft: src/expression.c:1704: range_expr_value_low: Assertion `0' failed.

After:
Error: Cannot merge set with existing datamap of same name
  set z {
      ^

v2:
Pablo points out that we shouldn't merge datamaps (plain value) and objref
maps either, catch this too and add another test:

nft --check -f invalid_transcation_merge_map_and_objref_map
invalid_transcation_merge_map_and_objref_map:9:13-13: Error: Cannot merge map with incompatible existing map of same name

We should also make sure that both data (for map case) and
set keys are identical, this is added in a followup patch.

Signed-off-by: Florian Westphal <fw@strlen.de>
src/evaluate.c
tests/shell/testcases/bogons/nft-f/invalid_range_expression_type_catch-all_set_element_assert [new file with mode: 0644]
tests/shell/testcases/bogons/nft-f/invalid_transcation_merge_map_and_objref_map [new file with mode: 0644]

index 5f46aaf976d24c8277e8950e8bf8222cf182b286..fc9d82f73b68fca1538d7d41a04f12a7a201a13e 100644 (file)
@@ -5165,6 +5165,18 @@ static int elems_evaluate(struct eval_ctx *ctx, struct set *set)
        return 0;
 }
 
+static bool set_type_compatible(const struct set *set, const struct set *existing_set)
+{
+       if (set_is_datamap(set->flags))
+               return set_is_datamap(existing_set->flags);
+
+       if (set_is_objmap(set->flags))
+               return set_is_objmap(existing_set->flags);
+
+       assert(!set_is_map(set->flags));
+       return !set_is_map(existing_set->flags);
+}
+
 static int set_evaluate(struct eval_ctx *ctx, struct set *set)
 {
        struct set *existing_set = NULL;
@@ -5288,8 +5300,15 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
                return 0;
        }
 
-       if (existing_set && set_is_interval(set->flags) && !set_is_interval(existing_set->flags))
-               return set_error(ctx, set, "existing %s lacks interval flag", type);
+       if (existing_set) {
+               if (set_is_interval(set->flags) && !set_is_interval(existing_set->flags))
+                       return set_error(ctx, set,
+                                        "existing %s lacks interval flag", type);
+               if (!set_type_compatible(set, existing_set))
+                       return set_error(ctx, set, "Cannot merge %s with incompatible existing %s of same name",
+                                       type,
+                                       set_is_map(existing_set->flags) ? "map" : "set");
+       }
 
        set->existing_set = existing_set;
 
diff --git a/tests/shell/testcases/bogons/nft-f/invalid_range_expression_type_catch-all_set_element_assert b/tests/shell/testcases/bogons/nft-f/invalid_range_expression_type_catch-all_set_element_assert
new file mode 100644 (file)
index 0000000..3660ac3
--- /dev/null
@@ -0,0 +1,18 @@
+table ip x {
+       map z {
+               type ipv4_addr : ipv4_addr
+               flags interval
+               elements = { 10.0.0.2, * : 192.168.0.4 }
+       }
+
+       set z {
+               type ipv4_addr
+               flags interval
+               counter
+               elements = { 1.1.1.0/24 counter packets 0 bytes 0,
+                        * counter packets 0 bytes 0packets 0 bytes ipv4_addr }
+               flags interval
+               auto-merge
+               elements = { 1.1.1.1 }
+       }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/invalid_transcation_merge_map_and_objref_map b/tests/shell/testcases/bogons/nft-f/invalid_transcation_merge_map_and_objref_map
new file mode 100644 (file)
index 0000000..e1fde58
--- /dev/null
@@ -0,0 +1,13 @@
+table ip x {
+        counter a { }
+
+       map m {
+               type ipv4_addr : ipv4_addr
+               elements = { 10.0.0.2 : 192.168.0.4 }
+       }
+
+        map m {
+               type ipv4_addr : counter
+                elements = { 192.168.2.2 : "a" }
+        }
+}