]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
parser_bison: add selector_expr rule to restrict typeof_expr
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 10 Apr 2025 21:23:58 +0000 (23:23 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 10 Apr 2025 22:28:39 +0000 (00:28 +0200)
typeof_expr allows for symbol, constant and bitwise expressions,
restrict it to selector expressions.

After this patch, input generated by fuzzer is rejected upfront:

 # nft -f test.nft
 test.nft:3:53-53: Error: syntax error, unexpected number
               typeof numgen inc mod 2 : ip daddr . 0
                                                    ^
 test.nft:2:12-13: Error: set definition does not specify key
       map t2 {
           ^^
 test.nft:8:65-67: Error: No such file or directory
               meta l4proto tcp dnat ip to numgen inc mod 2 map @t2
                                                                ^^^
 test.nft:8:65-67: Error: No such file or directory
               meta l4proto tcp dnat ip to numgen inc mod 2 map @t2
                                                                ^^^

Revisit 4ab1e5e60779 ("src: allow use of 'verdict' in typeof
definitions") to handle verdict as string, later a token can be added
to the scanner and enable it via flex start conditions.

Fixes: 14357cff40ed ("parser: add typeof keyword for declarations")
Reported-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/parser_bison.y
tests/shell/testcases/bogons/nft-f/invalid_set_key_stmt_evaluate_nat_map_assert [new file with mode: 0644]

index 4b2b51d4275c7a223e2e5144f9e38703bb2a374a..ed6a24a15377a236904392837e185988225ba2ea 100644 (file)
@@ -818,8 +818,8 @@ int nft_lex(void *, void *, void *);
 
 %type <expr>                   symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr
 %destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr
-%type <expr>                   primary_expr shift_expr and_expr primary_typeof_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr
-%destructor { expr_free($$); } primary_expr shift_expr and_expr primary_typeof_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr
+%type <expr>                   primary_expr shift_expr and_expr primary_typeof_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr selector_expr
+%destructor { expr_free($$); } primary_expr shift_expr and_expr primary_typeof_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr selector_expr
 %type <expr>                   exclusive_or_expr inclusive_or_expr
 %destructor { expr_free($$); } exclusive_or_expr inclusive_or_expr
 %type <expr>                   basic_expr
@@ -2097,19 +2097,10 @@ subchain_block          :       /* empty */     { $$ = $<chain>-1; }
                        }
                        ;
 
-typeof_verdict_expr    :       primary_expr
+typeof_verdict_expr    :       selector_expr
                        {
                                struct expr *e = $1;
 
-                               if (e->etype == EXPR_SYMBOL &&
-                                   strcmp("verdict", e->identifier) == 0) {
-                                       struct expr *v = verdict_expr_alloc(&@1, NF_ACCEPT, NULL);
-
-                                       expr_free(e);
-                                       v->flags &= ~EXPR_F_CONSTANT;
-                                       e = v;
-                               }
-
                                if (expr_ops(e)->build_udata == NULL) {
                                        erec_queue(error(&@1, "map data type '%s' lacks typeof serialization", expr_ops(e)->name),
                                                   state->msgs);
@@ -2118,7 +2109,7 @@ typeof_verdict_expr       :       primary_expr
                                }
                                $$ = e;
                        }
-                       |       typeof_expr             DOT             primary_expr
+                       |       typeof_expr             DOT             selector_expr
                        {
                                struct location rhs[] = {
                                        [1]     = @2,
@@ -2142,9 +2133,24 @@ typeof_data_expr :       INTERVAL        typeof_expr
                        {
                                $$ = constant_expr_alloc(&@$, &queue_type, BYTEORDER_HOST_ENDIAN, 16, NULL);
                        }
+                       |       STRING
+                       {
+                               struct expr *verdict;
+
+                               if (strcmp("verdict", $1) != 0) {
+                                       erec_queue(error(&@1, "map data type '%s' lacks typeof serialization", $1),
+                                                  state->msgs);
+                                       free_const($1);
+                                       YYERROR;
+                               }
+                               verdict = verdict_expr_alloc(&@1, NF_ACCEPT, NULL);
+                               verdict->flags &= ~EXPR_F_CONSTANT;
+                               $$ = verdict;
+                               free_const($1);
+                       }
                        ;
 
-primary_typeof_expr    :       primary_expr
+primary_typeof_expr    :       selector_expr
                        {
                                if (expr_ops($1)->build_udata == NULL) {
                                        erec_queue(error(&@1, "primary expression type '%s' lacks typeof serialization", expr_ops($1)->name),
@@ -4332,9 +4338,7 @@ integer_expr              :       NUM
                        }
                        ;
 
-primary_expr           :       symbol_expr                     { $$ = $1; }
-                       |       integer_expr                    { $$ = $1; }
-                       |       payload_expr                    { $$ = $1; }
+selector_expr          :       payload_expr                    { $$ = $1; }
                        |       exthdr_expr                     { $$ = $1; }
                        |       exthdr_exists_expr              { $$ = $1; }
                        |       meta_expr                       { $$ = $1; }
@@ -4346,6 +4350,11 @@ primary_expr             :       symbol_expr                     { $$ = $1; }
                        |       fib_expr                        { $$ = $1; }
                        |       osf_expr                        { $$ = $1; }
                        |       xfrm_expr                       { $$ = $1; }
+                       ;
+
+primary_expr           :       symbol_expr                     { $$ = $1; }
+                       |       integer_expr                    { $$ = $1; }
+                       |       selector_expr                   { $$ = $1; }
                        |       '('     basic_expr      ')'     { $$ = $2; }
                        ;
 
diff --git a/tests/shell/testcases/bogons/nft-f/invalid_set_key_stmt_evaluate_nat_map_assert b/tests/shell/testcases/bogons/nft-f/invalid_set_key_stmt_evaluate_nat_map_assert
new file mode 100644 (file)
index 0000000..d73dce8
--- /dev/null
@@ -0,0 +1,10 @@
+table ip t {
+       map t2 {
+               typeof numgen inc mod 2 : ip daddr . 0
+       }
+
+       chain c {
+               type nat hook prerouting priority dstnat; policy accept;
+               meta l4proto tcp dnat ip to numgen inc mod 2 map @t2
+       }
+}