From: Florian Westphal Date: Tue, 12 Dec 2023 18:13:14 +0000 (+0100) Subject: src: reject large raw payload and concat expressions X-Git-Tag: v1.1.0~152 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ef10d65db278d77208e960d210a1f4f532ebb552;p=thirdparty%2Fnftables.git src: reject large raw payload and concat expressions The kernel will reject this too, but unfortunately nft may try to cram the data into the underlying libnftnl expr. This causes heap corruption or BUG: nld buffer overflow: want to copy 132, max 64 After: Error: Concatenation of size 544 exceeds maximum size of 512 udp length . @th,0,512 . @th,512,512 { 47-63 . 0xe373135363130 . 0x33131303735353203 } ^^^^^^^^^ resp. same warning for an over-sized raw expression. Signed-off-by: Florian Westphal --- diff --git a/include/expression.h b/include/expression.h index aede223db..809089c89 100644 --- a/include/expression.h +++ b/include/expression.h @@ -11,6 +11,9 @@ #include #include +#define NFT_MAX_EXPR_LEN_BYTES (NFT_REG32_COUNT * sizeof(uint32_t)) +#define NFT_MAX_EXPR_LEN_BITS (NFT_MAX_EXPR_LEN_BYTES * BITS_PER_BYTE) + /** * enum expr_types * diff --git a/src/evaluate.c b/src/evaluate.c index 1c5078d67..87cd68d34 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1591,6 +1591,10 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr) } ctx->inner_desc = NULL; + + if (size > NFT_MAX_EXPR_LEN_BITS) + return expr_error(ctx->msgs, i, "Concatenation of size %u exceeds maximum size of %u", + size, NFT_MAX_EXPR_LEN_BITS); } (*expr)->flags |= flags; @@ -4719,6 +4723,10 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr) (*expr)->field_len[(*expr)->field_count++] = dsize_bytes; size += netlink_padded_len(i->len); + + if (size > NFT_MAX_EXPR_LEN_BITS) + return expr_error(ctx->msgs, i, "Concatenation of size %u exceeds maximum size of %u", + size, NFT_MAX_EXPR_LEN_BITS); } (*expr)->flags |= flags; diff --git a/src/parser_bison.y b/src/parser_bison.y index 571eddf13..7082d2ba0 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -5627,6 +5627,13 @@ payload_expr : payload_raw_expr payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM close_scope_at { + if ($6 > 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); + YYERROR; + } + $$ = payload_expr_alloc(&@$, NULL, 0); payload_init_raw($$, $2, $4, $6); $$->byteorder = BYTEORDER_BIG_ENDIAN; diff --git a/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr new file mode 100644 index 000000000..8b0d27444 --- /dev/null +++ b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr @@ -0,0 +1,5 @@ +table t { + chain c { + udp length . @th,0,512 . @th,512,512 { 47-63 . 0xe373135363130 . 0x33131303735353203 } + } +} diff --git a/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr new file mode 100644 index 000000000..66bd6bf87 --- /dev/null +++ b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr @@ -0,0 +1,5 @@ +table t { + chain c { + @th,160,1272 gt 0 + } +}