From: Timo Sirainen Date: Thu, 19 Aug 2021 10:32:45 +0000 (+0200) Subject: lib-storage: Fix potential assert-crash if filter-stream fails X-Git-Tag: 2.3.17~163 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0b6a2fb6c1abd8b05ee28dfbe1857437e13fd3d0;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: Fix potential assert-crash if filter-stream fails If filter-stream isn't read until header (because the parent istream fails), the header parsing isn't deinitialized. If after the failure the headers are attempted to be parsed again, there's an assert-crash. Make sure this won't happen by finishing the filter-istream read, and if that fails then reset the header parsing anyway. Destroying the filter_stream may also change the parent istream offset to change, so this commit adds an extra seek to beginning of the istream when beginning to parse the mail headers. Fixes: Panic: file index-mail-headers.c: line 198 (index_mail_parse_header_init): assertion failed: (!mail->data.header_parser_initialized) --- diff --git a/src/lib-storage/index/index-mail-headers.c b/src/lib-storage/index/index-mail-headers.c index 80d3401a81..59f1e6bbde 100644 --- a/src/lib-storage/index/index-mail-headers.c +++ b/src/lib-storage/index/index-mail-headers.c @@ -22,6 +22,8 @@ static const struct message_parser_settings msg_parser_set = { .flags = MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK, }; +static void index_mail_filter_stream_destroy(struct index_mail *mail); + static int header_line_cmp(const struct index_mail_line *l1, const struct index_mail_line *l2) { @@ -32,6 +34,11 @@ static int header_line_cmp(const struct index_mail_line *l1, (int)l1->line_num - (int)l2->line_num; } +static void index_mail_parse_header_deinit(struct index_mail *mail) +{ + mail->data.header_parser_initialized = FALSE; +} + static void index_mail_parse_header_finish(struct index_mail *mail) { struct mail *_mail = &mail->mail.mail; @@ -134,7 +141,7 @@ static void index_mail_parse_header_finish(struct index_mail *mail) } mail->data.dont_cache_field_idx = UINT_MAX; - mail->data.header_parser_initialized = FALSE; + index_mail_parse_header_deinit(mail); } static unsigned int @@ -195,6 +202,7 @@ void index_mail_parse_header_init(struct index_mail *mail, const uint8_t *match; unsigned int i, field_idx, match_count; + index_mail_filter_stream_destroy(mail); i_assert(!mail->data.header_parser_initialized); mail->header_seq = data->seq; @@ -425,6 +433,8 @@ static void index_mail_init_parser(struct index_mail *mail) } } + /* make sure parsing starts from the beginning of the stream */ + i_stream_seek(mail->data.stream, 0); if (data->parts == NULL) { data->parser_input = data->stream; data->parser_ctx = message_parser_init(mail->mail.data_pool, @@ -900,6 +910,11 @@ static void index_mail_filter_stream_destroy(struct index_mail *mail) header_parser_initialized=FALSE so we don't assert on it. */ while (i_stream_read_more(mail->data.filter_stream, &data, &size) > 0) i_stream_skip(mail->data.filter_stream, size); + if (mail->data.header_parser_initialized) { + /* istream failed while reading the header */ + i_assert(mail->data.filter_stream->stream_errno != 0); + index_mail_parse_header_deinit(mail); + } i_stream_destroy(&mail->data.filter_stream); }