]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: prevent merge of sets with incompatible keys
authorFlorian Westphal <fw@strlen.de>
Thu, 26 Jun 2025 00:52:48 +0000 (02:52 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 13 Aug 2025 18:48:16 +0000 (20:48 +0200)
commit c9d6f089f0eb2cb615cbca3e4c99b07c5639960f upstream.

Its not enough to check for interval flag, this would assert in interval
code due to concat being passed to the interval code:
BUG: unhandled key type 13

After fix:
same_set_name_but_different_keys_assert:8:6-7: Error: set already exists with
different datatype (concatenation of (IPv4 address, network interface index) vs
network interface index)
        set s4 {
            ^^

This also improves error verbosity when mixing datamap and objref maps:

invalid_transcation_merge_map_and_objref_map:9:13-13:
Error: map already exists with different datatype (IPv4 address vs string)

.. instead of 'Cannot merge map with incompatible existing map of same name'.
The 'Cannot merge map with incompatible existing map of same name' check
is kept in place to catch when ruleset contains a set and map with same name
and same key definition.

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

index 0b181dcfc5457382396dbca158c0b78212401df2..2316e1e0f05cd64b2e83ce98268a012472b56117 100644 (file)
@@ -5036,6 +5036,18 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *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->data && existing_set->data &&
+                   !datatype_equal(existing_set->data->dtype, set->data->dtype))
+                       return set_error(ctx, set,
+                                        "%s already exists with different datatype (%s vs %s)",
+                                        type, existing_set->data->dtype->desc,
+                                        set->data->dtype->desc);
+               if (!datatype_equal(existing_set->key->dtype, set->key->dtype))
+                       return set_error(ctx, set,
+                                        "%s already exists with different datatype (%s vs %s)",
+                                        type, existing_set->key->dtype->desc,
+                                        set->key->dtype->desc);
+               /* Catch attempt to merge set and map */
                if (!set_type_compatible(set, existing_set))
                        return set_error(ctx, set, "Cannot merge %s with incompatible existing %s of same name",
                                        type,
index 0f5518ff00afd9928a5eb972d3cec431273d50d9..e0a72591034bffd8b5359c524555a98c85aabdd8 100644 (file)
@@ -57,7 +57,7 @@ static void setelem_expr_to_range(struct expr *expr)
                expr->key = key;
                break;
        default:
-               BUG("unhandled key type %d\n", expr->key->etype);
+               BUG("unhandled key type %s\n", expr_name(expr->key));
        }
 }
 
diff --git a/tests/shell/testcases/bogons/nft-f/same_set_name_but_different_keys_assert b/tests/shell/testcases/bogons/nft-f/same_set_name_but_different_keys_assert
new file mode 100644 (file)
index 0000000..8fcfdf5
--- /dev/null
@@ -0,0 +1,13 @@
+table ip t {
+       set s4 {
+               type ipv4_addr . iface_index
+               flags interval
+               elements = { 127.0.0.1 . "lo" }
+       }
+
+       set s4 {
+               type iface_index
+               flags interval
+               elements = { "lo" }
+       }
+}