fd9253fb28
when parsing message (RHEL-55218) fix CVE-2024-23184: using a large number of address headers may trigger a denial of service (RHEL-55205) Resolves: RHEL-55218
494 lines
19 KiB
Diff
494 lines
19 KiB
Diff
From f020e139c519121d9630a966310ea8e100ee33b7 Mon Sep 17 00:00:00 2001
|
|
From: Marco Bettini <marco.bettini@open-xchange.com>
|
|
Date: Fri, 12 Apr 2024 15:06:43 +0000
|
|
Subject: [PATCH 1/2] lib-mail: message-header-parser - Limit header block to
|
|
10MB by default
|
|
|
|
---
|
|
src/lib-mail/message-header-parser.c | 48 ++++++++++++----
|
|
src/lib-mail/message-header-parser.h | 10 ++++
|
|
src/lib-mail/test-message-header-parser.c | 67 +++++++++++++++++++++++
|
|
3 files changed, 114 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/src/lib-mail/message-header-parser.c b/src/lib-mail/message-header-parser.c
|
|
index c5026f1bb7..5e020bbeb3 100644
|
|
--- a/src/lib-mail/message-header-parser.c
|
|
+++ b/src/lib-mail/message-header-parser.c
|
|
@@ -21,6 +21,9 @@ struct message_header_parser_ctx {
|
|
string_t *name;
|
|
buffer_t *value_buf;
|
|
|
|
+ size_t header_block_max_size;
|
|
+ size_t header_block_total_size;
|
|
+
|
|
enum message_header_parser_flags flags;
|
|
bool skip_line:1;
|
|
bool has_nuls:1;
|
|
@@ -38,6 +41,7 @@ message_parse_header_init(struct istream *input, struct message_size *hdr_size,
|
|
ctx->name = str_new(default_pool, 128);
|
|
ctx->flags = flags;
|
|
ctx->value_buf = buffer_create_dynamic(default_pool, 4096);
|
|
+ ctx->header_block_max_size = MESSAGE_HEADER_BLOCK_DEFAULT_MAX_SIZE;
|
|
i_stream_ref(input);
|
|
|
|
if (hdr_size != NULL)
|
|
@@ -45,6 +49,21 @@ message_parse_header_init(struct istream *input, struct message_size *hdr_size,
|
|
return ctx;
|
|
}
|
|
|
|
+void
|
|
+message_parse_header_set_limit(struct message_header_parser_ctx *parser,
|
|
+ size_t header_block_max_size)
|
|
+{
|
|
+ parser->header_block_max_size = header_block_max_size;
|
|
+}
|
|
+
|
|
+void
|
|
+message_parse_header_lower_limit(struct message_header_parser_ctx *parser,
|
|
+ size_t header_block_max_size)
|
|
+{
|
|
+ if (header_block_max_size < parser->header_block_max_size)
|
|
+ message_parse_header_set_limit(parser, header_block_max_size);
|
|
+}
|
|
+
|
|
void message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
|
|
{
|
|
struct message_header_parser_ctx *ctx = *_ctx;
|
|
@@ -77,6 +96,7 @@ int message_parse_header_next(struct message_header_parser_ctx *ctx,
|
|
/* new header line */
|
|
line->name_offset = ctx->input->v_offset;
|
|
colon_pos = UINT_MAX;
|
|
+ ctx->header_block_total_size += ctx->value_buf->used;
|
|
buffer_set_used_size(ctx->value_buf, 0);
|
|
}
|
|
|
|
@@ -342,33 +362,39 @@ int message_parse_header_next(struct message_header_parser_ctx *ctx,
|
|
}
|
|
}
|
|
|
|
+ line->value_len = I_MIN(line->value_len, ctx->header_block_max_size);
|
|
+ size_t line_value_size = line->value_len;
|
|
+ size_t header_total_used = ctx->header_block_total_size + ctx->value_buf->used;
|
|
+ size_t line_available = ctx->header_block_max_size <= header_total_used ? 0 :
|
|
+ ctx->header_block_max_size - header_total_used;
|
|
+ line_value_size = I_MIN(line_value_size, line_available);
|
|
+
|
|
if (!line->continued) {
|
|
/* first header line. make a copy of the line since we can't
|
|
really trust input stream not to lose it. */
|
|
- buffer_append(ctx->value_buf, line->value, line->value_len);
|
|
+ buffer_append(ctx->value_buf, line->value, line_value_size);
|
|
line->value = line->full_value = ctx->value_buf->data;
|
|
- line->full_value_len = line->value_len;
|
|
+ line->full_value_len = line->value_len = line_value_size;
|
|
} else if (line->use_full_value) {
|
|
/* continue saving the full value. */
|
|
if (last_no_newline) {
|
|
/* line is longer than fit into our buffer, so we
|
|
were forced to break it into multiple
|
|
message_header_lines */
|
|
- } else {
|
|
- if (last_crlf)
|
|
+ } else if (line_value_size > 1) {
|
|
+ if (last_crlf && line_value_size > 2)
|
|
buffer_append_c(ctx->value_buf, '\r');
|
|
buffer_append_c(ctx->value_buf, '\n');
|
|
}
|
|
if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0 &&
|
|
line->value_len > 0 && line->value[0] != ' ' &&
|
|
- IS_LWSP(line->value[0])) {
|
|
+ IS_LWSP(line->value[0]) &&
|
|
+ line_value_size > 0) {
|
|
buffer_append_c(ctx->value_buf, ' ');
|
|
- buffer_append(ctx->value_buf,
|
|
- line->value + 1, line->value_len - 1);
|
|
- } else {
|
|
- buffer_append(ctx->value_buf,
|
|
- line->value, line->value_len);
|
|
- }
|
|
+ buffer_append(ctx->value_buf, line->value + 1, line_value_size - 1);
|
|
+ } else
|
|
+ buffer_append(ctx->value_buf, line->value, line_value_size);
|
|
+
|
|
line->full_value = ctx->value_buf->data;
|
|
line->full_value_len = ctx->value_buf->used;
|
|
} else {
|
|
diff --git a/src/lib-mail/message-header-parser.h b/src/lib-mail/message-header-parser.h
|
|
index ce0825c8e5..43cf95e56a 100644
|
|
--- a/src/lib-mail/message-header-parser.h
|
|
+++ b/src/lib-mail/message-header-parser.h
|
|
@@ -1,6 +1,9 @@
|
|
#ifndef MESSAGE_HEADER_PARSER_H
|
|
#define MESSAGE_HEADER_PARSER_H
|
|
|
|
+/* This can be overridden by message_parse_header_set_limit() */
|
|
+#define MESSAGE_HEADER_BLOCK_DEFAULT_MAX_SIZE ((size_t) 10 * 1024*1024)
|
|
+
|
|
#define IS_LWSP(c) \
|
|
((c) == ' ' || (c) == '\t')
|
|
|
|
@@ -48,6 +51,13 @@ message_parse_header_init(struct istream *input, struct message_size *hdr_size,
|
|
enum message_header_parser_flags flags) ATTR_NULL(2);
|
|
void message_parse_header_deinit(struct message_header_parser_ctx **ctx);
|
|
|
|
+void
|
|
+message_parse_header_set_limit(struct message_header_parser_ctx *parser,
|
|
+ size_t header_block_max_size);
|
|
+void
|
|
+message_parse_header_lower_limit(struct message_header_parser_ctx *parser,
|
|
+ size_t header_block_max_size);
|
|
+
|
|
/* Read and return next header line. Returns 1 if header is returned, 0 if
|
|
input stream is non-blocking and more data needs to be read, -1 when all is
|
|
done or error occurred (see stream's error status). */
|
|
diff --git a/src/lib-mail/test-message-header-parser.c b/src/lib-mail/test-message-header-parser.c
|
|
index 700d3413f1..93d8842002 100644
|
|
--- a/src/lib-mail/test-message-header-parser.c
|
|
+++ b/src/lib-mail/test-message-header-parser.c
|
|
@@ -463,6 +463,71 @@ static void test_message_header_parser_extra_crlf_in_name(void)
|
|
test_end();
|
|
}
|
|
|
|
+#define assert_parsed_field(line, expected, actual, len) STMT_START { \
|
|
+ test_assert_idx(memcmp(expected, actual, strlen(expected)) == 0, line); \
|
|
+ test_assert_cmp_idx(strlen(expected), ==, len, line); \
|
|
+} STMT_END
|
|
+
|
|
+/* NOTE: implicit variables: (parser, hdr) */
|
|
+#define assert_parse_line(line, exp_name, exp_value, exp_full) STMT_START { \
|
|
+ test_assert_idx(message_parse_header_next(parser, &hdr) > 0, line); \
|
|
+ assert_parsed_field(line, exp_name, hdr->name, hdr->name_len); \
|
|
+ assert_parsed_field(line, exp_value, hdr->value, hdr->value_len); \
|
|
+ assert_parsed_field(line, exp_full, hdr->full_value, hdr->full_value_len); \
|
|
+ if (hdr->continues) hdr->use_full_value = TRUE; \
|
|
+} STMT_END
|
|
+
|
|
+static const unsigned char test_message_header_truncation_input[] =
|
|
+ /*01*/ "header1: this is short\n"
|
|
+ /*02*/ "header2: this is multiline\n"
|
|
+ /*03*/ " and long 343638404244464850525456586062\n"
|
|
+ /*04*/ " 64666870727476788082848688909294969800\n"
|
|
+ /*05*/ " 02040608101214161820222426283032343638\n"
|
|
+ /*06*/ "header3: I should not appear at all\n"
|
|
+ /*07*/ "\n";
|
|
+
|
|
+static void test_message_header_truncation_clean_oneline(void)
|
|
+{
|
|
+ test_begin("message header parser truncate + CLEAN_ONELINE flag");
|
|
+ struct message_header_line *hdr = NULL;
|
|
+ struct istream *input = test_istream_create_data(test_message_header_truncation_input, sizeof(test_message_header_truncation_input));
|
|
+ struct message_header_parser_ctx *parser = message_parse_header_init(input, NULL, MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE);
|
|
+ message_parse_header_set_limit(parser, 96);
|
|
+
|
|
+ assert_parse_line( 1, "header1", "this is short", "this is short");
|
|
+ assert_parse_line( 2, "header2", "this is multiline", "this is multiline");
|
|
+ assert_parse_line( 3, "header2", " and long 343638404244464850525456586062", "this is multiline and long 343638404244464850525456586062");
|
|
+ assert_parse_line( 4, "header2", " 64666870727476788082848688909294969800", "this is multiline and long 343638404244464850525456586062 6466687072747678808284868");
|
|
+ assert_parse_line( 5, "header2", " 02040608101214161820222426283032343638", "this is multiline and long 343638404244464850525456586062 6466687072747678808284868");
|
|
+ assert_parse_line( 6, "header3", "", "");
|
|
+ test_assert(message_parse_header_next(parser, &hdr) > 0 && hdr->eoh);
|
|
+
|
|
+ message_parse_header_deinit(&parser);
|
|
+ i_stream_unref(&input);
|
|
+ test_end();
|
|
+}
|
|
+
|
|
+static void test_message_header_truncation_flag0(void)
|
|
+{
|
|
+ test_begin("message header parser truncate + NO flags");
|
|
+ struct message_header_line *hdr = NULL;
|
|
+ struct istream *input = test_istream_create_data(test_message_header_truncation_input, sizeof(test_message_header_truncation_input));
|
|
+ struct message_header_parser_ctx *parser = message_parse_header_init(input, NULL, 0);
|
|
+ message_parse_header_set_limit(parser, 96);
|
|
+
|
|
+ assert_parse_line( 1, "header1", "this is short", "this is short");
|
|
+ assert_parse_line( 2, "header2", "this is multiline", "this is multiline");
|
|
+ assert_parse_line( 3, "header2", " and long 343638404244464850525456586062", "this is multiline\n and long 343638404244464850525456586062");
|
|
+ assert_parse_line( 4, "header2", " 64666870727476788082848688909294969800", "this is multiline\n and long 343638404244464850525456586062\n 646668707274767880828486");
|
|
+ assert_parse_line( 5, "header2", " 02040608101214161820222426283032343638", "this is multiline\n and long 343638404244464850525456586062\n 646668707274767880828486");
|
|
+ assert_parse_line( 6, "header3", "", "");
|
|
+ test_assert(message_parse_header_next(parser, &hdr) > 0 && hdr->eoh);
|
|
+
|
|
+ message_parse_header_deinit(&parser);
|
|
+ i_stream_unref(&input);
|
|
+ test_end();
|
|
+}
|
|
+
|
|
int main(void)
|
|
{
|
|
static void (*const test_functions[])(void) = {
|
|
@@ -473,6 +538,8 @@ int main(void)
|
|
test_message_header_parser_no_eoh,
|
|
test_message_header_parser_nul,
|
|
test_message_header_parser_extra_crlf_in_name,
|
|
+ test_message_header_truncation_flag0,
|
|
+ test_message_header_truncation_clean_oneline,
|
|
NULL
|
|
};
|
|
return test_run(test_functions);
|
|
|
|
From ce88c33abc37e408592eff70aeefa28f803effb9 Mon Sep 17 00:00:00 2001
|
|
From: Marco Bettini <marco.bettini@open-xchange.com>
|
|
Date: Wed, 24 Apr 2024 10:45:46 +0000
|
|
Subject: [PATCH 2/2] lib-mail: message-parser - Limit headers total count to
|
|
50MB by default
|
|
|
|
(including top headers and all mime-sections headers)
|
|
---
|
|
src/lib-mail/message-parser-private.h | 2 +
|
|
src/lib-mail/message-parser.c | 15 +++
|
|
src/lib-mail/message-parser.h | 6 +
|
|
src/lib-mail/test-message-parser.c | 154 ++++++++++++++++++++++++++
|
|
4 files changed, 177 insertions(+)
|
|
|
|
diff --git a/src/lib-mail/message-parser-private.h b/src/lib-mail/message-parser-private.h
|
|
index 41c32daf3a..8b362a9e71 100644
|
|
--- a/src/lib-mail/message-parser-private.h
|
|
+++ b/src/lib-mail/message-parser-private.h
|
|
@@ -30,6 +30,8 @@ struct message_parser_ctx {
|
|
enum message_parser_flags flags;
|
|
unsigned int max_nested_mime_parts;
|
|
unsigned int max_total_mime_parts;
|
|
+ size_t all_headers_max_size;
|
|
+ size_t all_headers_total_size;
|
|
|
|
char *last_boundary;
|
|
struct message_boundary *boundaries;
|
|
diff --git a/src/lib-mail/message-parser.c b/src/lib-mail/message-parser.c
|
|
index 9a9c9a3515..c7e3b1e96a 100644
|
|
--- a/src/lib-mail/message-parser.c
|
|
+++ b/src/lib-mail/message-parser.c
|
|
@@ -617,7 +617,18 @@ static int parse_next_header(struct message_parser_ctx *ctx,
|
|
}
|
|
if (ret < 0) {
|
|
/* no boundary */
|
|
+ size_t headers_available =
|
|
+ ctx->all_headers_max_size > ctx->all_headers_total_size ?
|
|
+ ctx->all_headers_max_size - ctx->all_headers_total_size : 0;
|
|
+ message_parse_header_lower_limit(ctx->hdr_parser_ctx, headers_available);
|
|
ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
|
|
+ if (ret > 0) {
|
|
+ if (!hdr->continues) {
|
|
+ ctx->all_headers_total_size += hdr->name_len;
|
|
+ ctx->all_headers_total_size += hdr->middle_len;
|
|
+ }
|
|
+ ctx->all_headers_total_size += hdr->value_len;
|
|
+ }
|
|
if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
|
|
ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
|
|
return ret;
|
|
@@ -762,6 +773,9 @@ message_parser_init_int(struct istream *input,
|
|
ctx->max_total_mime_parts = set->max_total_mime_parts != 0 ?
|
|
set->max_total_mime_parts :
|
|
MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS;
|
|
+ ctx->all_headers_max_size = set->all_headers_max_size != 0 ?
|
|
+ set->all_headers_max_size :
|
|
+ MESSAGE_PARSER_DEFAULT_ALL_HEADERS_MAX_SIZE;
|
|
ctx->input = input;
|
|
i_stream_ref(input);
|
|
return ctx;
|
|
@@ -779,6 +793,7 @@ message_parser_init(pool_t part_pool, struct istream *input,
|
|
ctx->next_part = &ctx->part->children;
|
|
ctx->parse_next_block = parse_next_header_init;
|
|
ctx->total_parts_count = 1;
|
|
+ ctx->all_headers_total_size = 0;
|
|
i_array_init(&ctx->next_part_stack, 4);
|
|
return ctx;
|
|
}
|
|
diff --git a/src/lib-mail/message-parser.h b/src/lib-mail/message-parser.h
|
|
index f19e526284..8d70d73f05 100644
|
|
--- a/src/lib-mail/message-parser.h
|
|
+++ b/src/lib-mail/message-parser.h
|
|
@@ -19,6 +19,7 @@ enum message_parser_flags {
|
|
|
|
#define MESSAGE_PARSER_DEFAULT_MAX_NESTED_MIME_PARTS 100
|
|
#define MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS 10000
|
|
+#define MESSAGE_PARSER_DEFAULT_ALL_HEADERS_MAX_SIZE ((size_t) 50 * 1024*1024)
|
|
|
|
struct message_parser_settings {
|
|
enum message_header_parser_flags hdr_flags;
|
|
@@ -30,6 +31,11 @@ struct message_parser_settings {
|
|
/* Maximum MIME parts in total.
|
|
0 = MESSAGE_PARSER_DEFAULT_MAX_TOTAL_MIME_PARTS. */
|
|
unsigned int max_total_mime_parts;
|
|
+
|
|
+ /* Maximum bytes fore headers in top header plus all
|
|
+ MIME sections headers
|
|
+ 0 = MESSAGE_PARSER_DEFAULT_ALL_HEADERS_MAX_SIZE */
|
|
+ size_t all_headers_max_size;
|
|
};
|
|
|
|
struct message_parser_ctx;
|
|
diff --git a/src/lib-mail/test-message-parser.c b/src/lib-mail/test-message-parser.c
|
|
index 663bfe8c5a..b6bada2303 100644
|
|
--- a/src/lib-mail/test-message-parser.c
|
|
+++ b/src/lib-mail/test-message-parser.c
|
|
@@ -1369,6 +1369,158 @@ static const char input_msg[] =
|
|
test_end();
|
|
}
|
|
|
|
+#define test_assert_virtual_size(part) \
|
|
+ test_assert((part).virtual_size == (part).lines + (part).physical_size)
|
|
+
|
|
+#define test_assert_part(part, flags_, children, h_lines, h_size, b_lines, b_size ) \
|
|
+STMT_START { \
|
|
+ test_assert((part)->flags == (flags_)); \
|
|
+ test_assert((part)->children_count == children); \
|
|
+ test_assert((part)->header_size.lines == h_lines); \
|
|
+ test_assert((part)->header_size.physical_size == h_size); \
|
|
+ test_assert((part)->body_size.lines == b_lines); \
|
|
+ test_assert((part)->body_size.physical_size == b_size); \
|
|
+ test_assert_virtual_size((part)->header_size); \
|
|
+ test_assert_virtual_size((part)->body_size); \
|
|
+} STMT_END
|
|
+
|
|
+static const enum message_part_flags FLAGS_MULTIPART =
|
|
+ MESSAGE_PART_FLAG_IS_MIME | MESSAGE_PART_FLAG_MULTIPART;
|
|
+static const enum message_part_flags FLAGS_RFC822 =
|
|
+ MESSAGE_PART_FLAG_IS_MIME | MESSAGE_PART_FLAG_MESSAGE_RFC822;
|
|
+static const enum message_part_flags FLAGS_TEXT =
|
|
+ MESSAGE_PART_FLAG_IS_MIME | MESSAGE_PART_FLAG_TEXT;
|
|
+
|
|
+static const char too_many_header_bytes_input_msg[] =
|
|
+ "Content-Type: multipart/mixed; boundary=\"1\"\n\n"
|
|
+ "--1\n"
|
|
+ "Content-Type: multipart/mixed; boundary=\"2\"\n\n"
|
|
+ "--2\n"
|
|
+ "Content-Type: message/rfc822\n\n"
|
|
+ "Content-Type: text/plain\n\n1-rfc822\n"
|
|
+ "--2\n"
|
|
+ "Content-Type: message/rfc822\n\n"
|
|
+ "Content-Type: text/plain\n\n2-rfc822\n"
|
|
+ "--1\n"
|
|
+ "Content-Type: message/rfc822\n\n"
|
|
+ "Content-Type: text/plain\n\n3-rfc822\n";
|
|
+
|
|
+static void test_message_parser_too_many_header_bytes_run(
|
|
+ const struct message_parser_settings *parser_set,
|
|
+ pool_t *pool_r, struct istream **input_r,
|
|
+ struct message_part **parts_r)
|
|
+{
|
|
+ *pool_r = pool_alloconly_create("message parser", 10240);
|
|
+ *input_r = test_istream_create(too_many_header_bytes_input_msg);
|
|
+ struct message_parser_ctx *parser = message_parser_init(*pool_r, *input_r, parser_set);
|
|
+
|
|
+ int ret;
|
|
+ struct message_block block ATTR_UNUSED;
|
|
+ while ((ret = message_parser_parse_next_block(parser, &block)) > 0);
|
|
+ test_assert(ret < 0);
|
|
+
|
|
+ message_parser_deinit(&parser, parts_r);
|
|
+}
|
|
+
|
|
+static void test_message_parser_too_many_header_bytes_default(void)
|
|
+{
|
|
+ test_begin("message parser too many header bytes default");
|
|
+
|
|
+ pool_t pool;
|
|
+ struct istream *input;
|
|
+ struct message_part *part_root;
|
|
+ const struct message_parser_settings parser_set = { .all_headers_max_size = 0 };
|
|
+
|
|
+ test_message_parser_too_many_header_bytes_run(&parser_set, &pool, &input, &part_root);
|
|
+
|
|
+ // test_assert_part(part, flags_, children, h_lines, h_size, b_lines, b_size )
|
|
+
|
|
+ test_assert_part(part_root, FLAGS_MULTIPART, 7, 2, 45, 21, 256);
|
|
+ test_assert(part_root->parent == NULL);
|
|
+
|
|
+ struct message_part *part_1 = part_root->children;
|
|
+ test_assert_part(part_1, FLAGS_MULTIPART, 4, 2, 45, 11, 137);
|
|
+
|
|
+ struct message_part *part_1_1 = part_1->children;
|
|
+ test_assert_part(part_1_1, FLAGS_RFC822, 1, 2, 30, 2, 34);
|
|
+
|
|
+ struct message_part *part_1_1_1 = part_1_1->children;
|
|
+ test_assert_part(part_1_1_1, FLAGS_TEXT, 0, 2, 26, 0, 8);
|
|
+
|
|
+ test_assert(part_1_1_1->next == NULL);
|
|
+
|
|
+ struct message_part *part_1_2 = part_1_1->next;
|
|
+ test_assert_part(part_1_2, FLAGS_RFC822, 1, 2, 30, 2, 34);
|
|
+
|
|
+ struct message_part *part_1_2_1 = part_1_2->children;
|
|
+ test_assert_part(part_1_2_1, FLAGS_TEXT, 0, 2, 26, 0, 8);
|
|
+
|
|
+ test_assert(part_1_2_1->next == NULL);
|
|
+
|
|
+ test_assert(part_1_2->next == NULL);
|
|
+
|
|
+ struct message_part *part_2 = part_1->next;
|
|
+ test_assert_part(part_2, FLAGS_RFC822, 1, 2, 30, 3, 35);
|
|
+
|
|
+ struct message_part *part_2_1 = part_2->children;
|
|
+ test_assert_part(part_2_1, FLAGS_TEXT, 0, 2, 26, 1, 9);
|
|
+ test_assert(part_2_1->next == NULL);
|
|
+
|
|
+ test_assert(part_2->next == NULL);
|
|
+
|
|
+ test_assert(part_root->next == NULL);
|
|
+
|
|
+ test_parsed_parts(input, part_root);
|
|
+ i_stream_unref(&input);
|
|
+ pool_unref(&pool);
|
|
+ test_end();
|
|
+}
|
|
+
|
|
+static void test_message_parser_too_many_header_bytes_100(void)
|
|
+{
|
|
+ test_begin("message parser too many header bytes 100");
|
|
+
|
|
+ pool_t pool;
|
|
+ struct istream *input;
|
|
+ struct message_part *part_root;
|
|
+ const struct message_parser_settings parser_set = { .all_headers_max_size = 100 };
|
|
+
|
|
+ test_message_parser_too_many_header_bytes_run(&parser_set, &pool, &input, &part_root);
|
|
+
|
|
+ // test_assert_part(part, flags_, children, h_lines, h_size, b_lines, b_size )
|
|
+
|
|
+ test_assert_part(part_root, FLAGS_MULTIPART, 5, 2, 45, 21, 256);
|
|
+ test_assert(part_root->parent == NULL);
|
|
+
|
|
+ struct message_part *part_1 = part_root->children;
|
|
+ test_assert_part(part_1, FLAGS_MULTIPART, 3, 2, 45, 11, 137);
|
|
+
|
|
+ struct message_part *part_1_1 = part_1->children;
|
|
+ test_assert_part(part_1_1, FLAGS_RFC822, 1, 2, 30, 2, 34);
|
|
+
|
|
+ struct message_part *part_1_1_1 = part_1_1->children;
|
|
+ test_assert_part(part_1_1_1, MESSAGE_PART_FLAG_IS_MIME, 0, 2, 26, 0, 8);
|
|
+
|
|
+ test_assert(part_1_1_1->next == NULL);
|
|
+
|
|
+ struct message_part *part_1_2 = part_1_1->next;
|
|
+ test_assert_part(part_1_2, MESSAGE_PART_FLAG_IS_MIME, 0, 2, 30, 2, 34);
|
|
+
|
|
+ test_assert(part_1_2->next == NULL);
|
|
+
|
|
+ struct message_part *part_2 = part_1->next;
|
|
+ test_assert_part(part_2, MESSAGE_PART_FLAG_IS_MIME, 0, 2, 30, 3, 35);
|
|
+
|
|
+ test_assert(part_2->next == NULL);
|
|
+
|
|
+ test_assert(part_root->next == NULL);
|
|
+
|
|
+ test_parsed_parts(input, part_root);
|
|
+ i_stream_unref(&input);
|
|
+ pool_unref(&pool);
|
|
+ test_end();
|
|
+}
|
|
+
|
|
int main(void)
|
|
{
|
|
static void (*const test_functions[])(void) = {
|
|
@@ -1392,6 +1544,8 @@ int main(void)
|
|
test_message_parser_mime_part_limit_rfc822,
|
|
test_message_parser_mime_version,
|
|
test_message_parser_mime_version_missing,
|
|
+ test_message_parser_too_many_header_bytes_default,
|
|
+ test_message_parser_too_many_header_bytes_100,
|
|
NULL
|
|
};
|
|
return test_run(test_functions);
|