]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: reject large raw payload and concat expressions
authorFlorian Westphal <fw@strlen.de>
Tue, 12 Dec 2023 18:13:14 +0000 (19:13 +0100)
committerFlorian Westphal <fw@strlen.de>
Fri, 15 Dec 2023 01:27:14 +0000 (02:27 +0100)
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 <fw@strlen.de>
include/expression.h
src/evaluate.c
src/parser_bison.y
tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr [new file with mode: 0644]
tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr [new file with mode: 0644]

index aede223db7418c85bfc482284c929cc44d514ff9..809089c899741d5aee3058028151646ad2d66355 100644 (file)
@@ -11,6 +11,9 @@
 #include <json.h>
 #include <libnftnl/udata.h>
 
+#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
  *
index 1c5078d67c13ea88848d2ba5c6dbd44a33183112..87cd68d3468aed95b081504ef4671572db925ca9 100644 (file)
@@ -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;
index 571eddf137aae8283a5eca97fe0c648073fc348f..7082d2ba00a01aee199bdc912708112c5e27e441 100644 (file)
@@ -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 (file)
index 0000000..8b0d274
--- /dev/null
@@ -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 (file)
index 0000000..66bd6bf
--- /dev/null
@@ -0,0 +1,5 @@
+table t {
+       chain c {
+                @th,160,1272 gt 0
+       }
+}