From: Pablo Neira Ayuso Date: Thu, 10 Apr 2025 21:23:58 +0000 (+0200) Subject: parser_bison: add selector_expr rule to restrict typeof_expr X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=3286e08a0afa21493793fd658f78c8610f1108ce;p=thirdparty%2Fnftables.git parser_bison: add selector_expr rule to restrict typeof_expr commit 8bbdcb7346788a067968e3aa62ac7e5a670b08af upstream. 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 Signed-off-by: Pablo Neira Ayuso --- diff --git a/src/parser_bison.y b/src/parser_bison.y index 67ac8f57..86bd4d7c 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -798,8 +798,8 @@ int nft_lex(void *, void *, void *); %type 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 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 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 exclusive_or_expr inclusive_or_expr %destructor { expr_free($$); } exclusive_or_expr inclusive_or_expr %type basic_expr @@ -1952,19 +1952,10 @@ subchain_block : /* empty */ { $$ = $-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); @@ -1973,7 +1964,7 @@ typeof_verdict_expr : primary_expr } $$ = e; } - | typeof_expr DOT primary_expr + | typeof_expr DOT selector_expr { struct location rhs[] = { [1] = @2, @@ -1997,9 +1988,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); + xfree($1); + YYERROR; + } + verdict = verdict_expr_alloc(&@1, NF_ACCEPT, NULL); + verdict->flags &= ~EXPR_F_CONSTANT; + $$ = verdict; + xfree($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), @@ -4248,9 +4254,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; } @@ -4262,6 +4266,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 index 00000000..d73dce8e --- /dev/null +++ b/tests/shell/testcases/bogons/nft-f/invalid_set_key_stmt_evaluate_nat_map_assert @@ -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 + } +}