Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions src/lib-mail/message-parser-from-parts.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,26 @@ static int preparsed_parse_prologue_more(struct message_parser_ctx *ctx,
if (*cur == '\n') break;
}

if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') {
ctx->broken_reason = "Prologue boundary beginning not at expected position";
return -1;
}
if (cur < block_r->data) {
/* boundary is at the very start of the prologue, i.e.
there is no preamble before it (no preceding newline
to find). Don't read before block_r->data. */
if (block_r->data[0] != '-' || block_r->data[1] != '-') {
ctx->broken_reason = "Prologue boundary beginning not at expected position";
return -1;
}
block_r->size = 0;
} else {
if (cur[0] != '\n' || cur[1] != '-' || cur[2] != '-') {
ctx->broken_reason = "Prologue boundary beginning not at expected position";
return -1;
}

if (cur != block_r->data && cur[-1] == '\r') cur--;
if (cur != block_r->data && cur[-1] == '\r') cur--;

/* clip boundary */
block_r->size = cur - block_r->data;
/* clip boundary */
block_r->size = cur - block_r->data;
}

ctx->parse_next_block = preparsed_parse_prologue_finish;
ctx->skip = block_r->size;
Expand Down
45 changes: 45 additions & 0 deletions src/lib-mail/test-message-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1521,6 +1521,50 @@ static void test_message_parser_too_many_header_bytes_100(void)
test_end();
}

static void test_message_parser_preparsed_empty_preamble(void)
{
static const char input_msg[] =
"Content-Type: multipart/mixed; boundary=\"b\"\r\n"
"\r\n"
"--b\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"hello\r\n"
"--b--\r\n";
const struct message_parser_settings preparsed_set = {
.flags = MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS,
};
struct message_parser_ctx *parser;
struct istream *input;
struct message_part *parts, *parts2;
struct message_block block;
const char *error;
pool_t pool;

test_begin("message parser preparsed empty preamble");
pool = pool_alloconly_create("message parser", 10240);
input = test_istream_create(input_msg);
test_istream_set_allow_eof(input, TRUE);

test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);

/* Re-parse from the cached parts, requesting multipart blocks so the
prologue is returned. The prologue region here is exactly the
boundary line ("--b\r\n") with no preamble before it. Before the fix
the backward newline scan walked past block start and clipped the
block to a (size_t)-underflowed length. */
i_stream_seek(input, 0);
parser = message_parser_init_from_parts(parts, input, &preparsed_set);
while (message_parser_parse_next_block(parser, &block) > 0)
test_assert(block.size <= sizeof(input_msg));
test_assert(message_parser_deinit_from_parts(&parser, &parts2, &error) == 0);
test_assert(message_part_is_equal(parts, parts2));

i_stream_unref(&input);
pool_unref(&pool);
test_end();
}

int main(void)
{
static void (*const test_functions[])(void) = {
Expand All @@ -1546,6 +1590,7 @@ int main(void)
test_message_parser_mime_version_missing,
test_message_parser_too_many_header_bytes_default,
test_message_parser_too_many_header_bytes_100,
test_message_parser_preparsed_empty_preamble,
NULL
};
return test_run(test_functions);
Expand Down