From: Florian Westphal Date: Fri, 12 Jan 2024 12:27:23 +0000 (+0100) Subject: parser: reject raw payload expressions with 0 length X-Git-Tag: v1.0.6.1~251 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=aeef8aa8cc03fd3f3dd5261661d31901918524f5;p=thirdparty%2Fnftables.git parser: reject raw payload expressions with 0 length commit e08627257ecfa7dfb68a34a1c8866e7a7e012b15 upstream. Reject this at parser stage. Fix up the json input side too, else reproducer gives: nft: src/netlink.c:243: netlink_gen_raw_data: Assertion `len > 0' failed. Signed-off-by: Florian Westphal --- diff --git a/src/parser_bison.y b/src/parser_bison.y index f3bf8aa6..a6a8f795 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -849,6 +849,8 @@ int nft_lex(void *, void *, void *); %type payload_expr payload_raw_expr %destructor { expr_free($$); } payload_expr payload_raw_expr %type payload_base_spec +%type payload_raw_len + %type eth_hdr_expr vlan_hdr_expr %destructor { expr_free($$); } eth_hdr_expr vlan_hdr_expr %type eth_hdr_field vlan_hdr_field @@ -5465,15 +5467,26 @@ payload_expr : payload_raw_expr | th_hdr_expr ; -payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM close_scope_at +payload_raw_len : NUM { - if ($6 > NFT_MAX_EXPR_LEN_BITS) { + if ($1 > NFT_MAX_EXPR_LEN_BITS) { erec_queue(error(&@1, "raw payload length %u exceeds upper limit of %u", - $6, NFT_MAX_EXPR_LEN_BITS), - state->msgs); + $1, NFT_MAX_EXPR_LEN_BITS), + state->msgs); YYERROR; } + if ($1 == 0) { + erec_queue(error(&@1, "raw payload length cannot be 0"), state->msgs); + YYERROR; + } + + $$ = $1; + } + ; + +payload_raw_expr : AT payload_base_spec COMMA NUM COMMA payload_raw_len close_scope_at + { $$ = payload_expr_alloc(&@$, NULL, 0); payload_init_raw($$, $2, $4, $6); $$->byteorder = BYTEORDER_BIG_ENDIAN; @@ -5718,7 +5731,7 @@ tcp_hdr_expr : TCP tcp_hdr_field YYERROR; } } - | TCP OPTION AT close_scope_at tcp_hdr_option_type COMMA NUM COMMA NUM + | TCP OPTION AT close_scope_at tcp_hdr_option_type COMMA NUM COMMA payload_raw_len { $$ = tcpopt_expr_alloc(&@$, $5, 0); tcpopt_init_raw($$, $5, $7, $9, 0); diff --git a/src/parser_json.c b/src/parser_json.c index bb18a67b..f2393588 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -564,6 +564,13 @@ static struct expr *json_parse_payload_expr(struct json_ctx *ctx, json_error(ctx, "Invalid payload base '%s'.", base); return NULL; } + + if (len <= 0 || len > (int)NFT_MAX_EXPR_LEN_BITS) { + json_error(ctx, "Payload length must be between 0 and %lu, got %d", + NFT_MAX_EXPR_LEN_BITS, len); + return NULL; + } + expr = payload_expr_alloc(int_loc, NULL, 0); payload_init_raw(expr, val, offset, len); expr->byteorder = BYTEORDER_BIG_ENDIAN; @@ -608,6 +615,12 @@ static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx, if (kind < 0 || kind > 255) return NULL; + if (len <= 0 || len > (int)NFT_MAX_EXPR_LEN_BITS) { + json_error(ctx, "option length must be between 0 and %lu, got %d", + NFT_MAX_EXPR_LEN_BITS, len); + return NULL; + } + expr = tcpopt_expr_alloc(int_loc, kind, TCPOPT_COMMON_KIND); diff --git a/tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert b/tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert new file mode 100644 index 00000000..f85a04e7 --- /dev/null +++ b/tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert @@ -0,0 +1 @@ +add rule t c @th,0,0 0