]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
optimize: clone counter before insertion into set element
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 5 Jul 2024 12:03:33 +0000 (14:03 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 5 Jul 2024 14:11:37 +0000 (16:11 +0200)
The counter statement that is zapped from the rule needs to be cloned
before inserting it into each set element.

Fixes: 686ab8b6996e ("optimize: do not remove counter in verdict maps")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/optimize.c
tests/shell/testcases/optimizations/dumps/merge_counter.nft [new file with mode: 0644]
tests/shell/testcases/optimizations/merge_counter [new file with mode: 0755]

index 1dd08586f32687cd0a0cc56e2e9eacdc369b6265..62dd9082a587a807969e8bc5ae0d2d09fb5a6f2b 100644 (file)
@@ -692,29 +692,36 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict,
                              struct expr *set, struct stmt *counter)
 {
        struct expr *item, *elem, *mapping;
+       struct stmt *counter_elem;
 
        switch (expr->etype) {
        case EXPR_LIST:
                list_for_each_entry(item, &expr->expressions, list) {
                        elem = set_elem_expr_alloc(&internal_location, expr_get(item));
-                       if (counter)
-                               list_add_tail(&counter->list, &elem->stmt_list);
+                       if (counter) {
+                               counter_elem = counter_stmt_alloc(&counter->location);
+                               list_add_tail(&counter_elem->list, &elem->stmt_list);
+                       }
 
                        mapping = mapping_expr_alloc(&internal_location, elem,
                                                     expr_get(verdict->expr));
                        compound_expr_add(set, mapping);
                }
+               stmt_free(counter);
                break;
        case EXPR_SET:
                list_for_each_entry(item, &expr->expressions, list) {
                        elem = set_elem_expr_alloc(&internal_location, expr_get(item->key));
-                       if (counter)
-                               list_add_tail(&counter->list, &elem->stmt_list);
+                       if (counter) {
+                               counter_elem = counter_stmt_alloc(&counter->location);
+                               list_add_tail(&counter_elem->list, &elem->stmt_list);
+                       }
 
                        mapping = mapping_expr_alloc(&internal_location, elem,
                                                     expr_get(verdict->expr));
                        compound_expr_add(set, mapping);
                }
+               stmt_free(counter);
                break;
        case EXPR_PREFIX:
        case EXPR_RANGE:
@@ -819,8 +826,8 @@ static void __merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
                                      struct expr *set, struct stmt *verdict)
 {
        struct expr *concat, *next, *elem, *mapping;
+       struct stmt *counter, *counter_elem;
        LIST_HEAD(concat_list);
-       struct stmt *counter;
 
        counter = zap_counter(ctx, i);
        __merge_concat(ctx, i, merge, &concat_list);
@@ -828,13 +835,16 @@ static void __merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
        list_for_each_entry_safe(concat, next, &concat_list, list) {
                list_del(&concat->list);
                elem = set_elem_expr_alloc(&internal_location, concat);
-               if (counter)
-                       list_add_tail(&counter->list, &elem->stmt_list);
+               if (counter) {
+                       counter_elem = counter_stmt_alloc(&counter->location);
+                       list_add_tail(&counter_elem->list, &elem->stmt_list);
+               }
 
                mapping = mapping_expr_alloc(&internal_location, elem,
                                             expr_get(verdict->expr));
                compound_expr_add(set, mapping);
        }
+       stmt_free(counter);
 }
 
 static void merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
diff --git a/tests/shell/testcases/optimizations/dumps/merge_counter.nft b/tests/shell/testcases/optimizations/dumps/merge_counter.nft
new file mode 100644 (file)
index 0000000..72eed5d
--- /dev/null
@@ -0,0 +1,8 @@
+table ip x {
+       chain y {
+               type filter hook input priority filter; policy drop;
+               ct state vmap { invalid counter packets 0 bytes 0 : drop, established counter packets 0 bytes 0 : accept, related counter packets 0 bytes 0 : accept }
+               tcp dport { 80, 123 } counter packets 0 bytes 0 accept
+               ip saddr . ip daddr vmap { 1.1.1.1 . 2.2.2.2 counter packets 0 bytes 0 : accept, 1.1.1.2 . 3.3.3.3 counter packets 0 bytes 0 : drop }
+       }
+}
diff --git a/tests/shell/testcases/optimizations/merge_counter b/tests/shell/testcases/optimizations/merge_counter
new file mode 100755 (executable)
index 0000000..3b8bbad
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+RULESET="table ip x {
+        chain y {
+                type filter hook input priority 0; policy drop;
+
+                ct state invalid counter drop
+                ct state established,related counter accept
+                tcp dport 80 counter accept
+                tcp dport 123 counter accept
+                ip saddr 1.1.1.1 ip daddr 2.2.2.2 counter accept
+                ip saddr 1.1.1.2 ip daddr 3.3.3.3 counter drop
+        }
+}"
+
+$NFT -o -f - <<< $RULESET