From 3df3d432073390bb403e9b022790497ae2f0dece Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Wed, 3 Feb 2021 16:31:26 +0800
Subject: [PATCH] lib-mail: message-parser - Fix assert-crash when enforcing
 MIME part limit

The limit could have been exceeded with message/rfc822 parts.
---
 src/lib-mail/message-parser.c      |  3 +-
 src/lib-mail/test-message-parser.c | 82 ++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/src/lib-mail/message-parser.c b/src/lib-mail/message-parser.c
index 011dea9..8bc5972 100644
--- a/src/lib-mail/message-parser.c
+++ b/src/lib-mail/message-parser.c
@@ -700,7 +700,8 @@ static int parse_next_header(struct message_parser_ctx *ctx,
 		ctx->multipart = FALSE;
 		ctx->parse_next_block = parse_next_body_to_boundary;
 	} else if ((part->flags & MESSAGE_PART_FLAG_MESSAGE_RFC822) != 0 &&
-		   !parse_too_many_nested_mime_parts(ctx)) {
+		   !parse_too_many_nested_mime_parts(ctx) &&
+		   ctx->total_parts_count < ctx->max_total_mime_parts) {
 		ctx->parse_next_block = parse_next_body_message_rfc822_init;
 	} else {
 		part->flags &= ~MESSAGE_PART_FLAG_MESSAGE_RFC822;
diff --git a/src/lib-mail/test-message-parser.c b/src/lib-mail/test-message-parser.c
index 71a738d..5dfe491 100644
--- a/src/lib-mail/test-message-parser.c
+++ b/src/lib-mail/test-message-parser.c
@@ -1131,6 +1131,87 @@ static const char input_msg[] =
 	test_end();
 }
 
+static void test_message_parser_mime_part_limit_rfc822(void)
+{
+static const char 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"
+"\n"
+"1\n"
+"--2\n"
+"Content-Type: message/rfc822\n"
+"\n"
+"Content-Type: text/plain\n"
+"\n"
+"22\n"
+"--1\n"
+"Content-Type: message/rfc822\n"
+"\n"
+"Content-Type: text/plain\n"
+"\n"
+"333\n";
+	const struct message_parser_settings parser_set = {
+		.max_total_mime_parts = 3,
+	};
+	struct message_parser_ctx *parser;
+	struct istream *input;
+	struct message_part *parts, *part;
+	struct message_block block;
+	pool_t pool;
+	int ret;
+
+	test_begin("message parser mime part limit rfc822");
+	pool = pool_alloconly_create("message parser", 10240);
+	input = test_istream_create(input_msg);
+
+	parser = message_parser_init(pool, input, &parser_set);
+	while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ;
+	test_assert(ret < 0);
+	message_parser_deinit(&parser, &parts);
+
+	part = parts;
+	test_assert(part->children_count == 2);
+	test_assert(part->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
+	test_assert(part->header_size.lines == 2);
+	test_assert(part->header_size.physical_size == 45);
+	test_assert(part->header_size.virtual_size == 45+2);
+	test_assert(part->body_size.lines == 21);
+	test_assert(part->body_size.physical_size == 238);
+	test_assert(part->body_size.virtual_size == 238+21);
+
+	part = parts->children;
+	test_assert(part->children_count == 1);
+	test_assert(part->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
+	test_assert(part->header_size.lines == 2);
+	test_assert(part->header_size.physical_size == 45);
+	test_assert(part->header_size.virtual_size == 45+2);
+	test_assert(part->body_size.lines == 18);
+	test_assert(part->body_size.physical_size == 189);
+	test_assert(part->body_size.virtual_size == 189+18);
+
+	part = parts->children->children;
+	test_assert(part->children_count == 0);
+	test_assert(part->flags == MESSAGE_PART_FLAG_IS_MIME);
+	test_assert(part->header_size.lines == 2);
+	test_assert(part->header_size.physical_size == 30);
+	test_assert(part->header_size.virtual_size == 30+2);
+	test_assert(part->body_size.lines == 15);
+	test_assert(part->body_size.physical_size == 155);
+	test_assert(part->body_size.virtual_size == 155+15);
+
+	test_parsed_parts(input, parts);
+	i_stream_unref(&input);
+	pool_unref(&pool);
+	test_end();
+}
+
 int main(void)
 {
 	static void (*const test_functions[])(void) = {
@@ -1151,6 +1232,7 @@ int main(void)
 		test_message_parser_mime_part_nested_limit,
 		test_message_parser_mime_part_nested_limit_rfc822,
 		test_message_parser_mime_part_limit,
+		test_message_parser_mime_part_limit_rfc822,
 		NULL
 	};
 	return test_run(test_functions);
-- 
2.23.0

