]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
parser: reject raw payload expressions with 0 length
authorFlorian Westphal <fw@strlen.de>
Fri, 12 Jan 2024 12:27:23 +0000 (13:27 +0100)
committerFlorian Westphal <fw@strlen.de>
Fri, 12 Jan 2024 14:25:09 +0000 (15:25 +0100)
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 <fw@strlen.de>
src/parser_bison.y
src/parser_json.c
tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert [new file with mode: 0644]

index 86fb9f077db897428e7e2376fb24b70adb4a6afa..17edaef8b0bcba40058a6403bec6cc22bc847341 100644 (file)
@@ -883,6 +883,8 @@ int nft_lex(void *, void *, void *);
 %type <expr>                   payload_expr payload_raw_expr
 %destructor { expr_free($$); } payload_expr payload_raw_expr
 %type <val>                    payload_base_spec
+%type <val>                    payload_raw_len
+
 %type <expr>                   eth_hdr_expr    vlan_hdr_expr
 %destructor { expr_free($$); } eth_hdr_expr    vlan_hdr_expr
 %type <val>                    eth_hdr_field   vlan_hdr_field
@@ -5681,15 +5683,26 @@ payload_expr            :       payload_raw_expr
                        |       gretap_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;
@@ -5936,7 +5949,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);
index 9e02bc34409785bacc44ea8ad8bbb4dabb0cab09..a0c9318c83db9ac13ea6fada94c6ff5787b26be0 100644 (file)
@@ -592,6 +592,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;
@@ -663,6 +670,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 (file)
index 0000000..f85a04e
--- /dev/null
@@ -0,0 +1 @@
+add rule t c @th,0,0 0