changeset 22989:4e9251b0435d

lib-storage: Fix bodystructure parsing crash if header is parsed twice The second parsing will recreate the parser_ctx, discarding the old parsed message_part.data for the header. On the second parsing save_bodystructure_header=FALSE so the message_part.data isn't filled for the header. Later on the bodystructure parsing assumes the data is set, and crashes. This only happened with mail_attachment_detection_options=add-flags-on-save and Sieve script that first accessed a non-cached header and then used the "body" extension. Fixes segfault and also: Panic: file imap-bodystructure.c: line 116 (part_write_body_multipart): assertion failed: (part->data != NULL)
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Wed, 25 Jul 2018 13:17:45 +0300
parents c3c55b15fb6f
children 39eb7899c21d
files src/lib-storage/index/index-mail-headers.c src/lib-storage/index/index-mail.c src/lib-storage/index/index-mail.h
diffstat 3 files changed, 11 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/index-mail-headers.c	Wed Jul 25 13:17:05 2018 +0300
+++ b/src/lib-storage/index/index-mail-headers.c	Wed Jul 25 13:17:45 2018 +0300
@@ -315,7 +315,7 @@
 		if (data->save_bodystructure_header) {
 			i_assert(!data->save_bodystructure_body ||
 				 data->parser_ctx != NULL);
-			data->save_bodystructure_header = FALSE;
+			data->parsed_bodystructure_header = TRUE;
 		}
 		return;
 	}
@@ -416,6 +416,12 @@
 			index_mail_set_message_parts_corrupted(&mail->mail.mail, error);
 			data->parts = NULL;
 		}
+		if (data->parts == NULL) {
+			/* The previous parsing didn't finish, so we're
+			   re-parsing the header. The new parts don't have data
+			   filled anymore. */
+			data->parsed_bodystructure_header = FALSE;
+		}
 	}
 
 	if (data->parts == NULL) {
--- a/src/lib-storage/index/index-mail.c	Wed Jul 25 13:17:05 2018 +0300
+++ b/src/lib-storage/index/index-mail.c	Wed Jul 25 13:17:45 2018 +0300
@@ -1182,7 +1182,7 @@
 	if (data->save_bodystructure_body) {
 		/* bodystructure header is parsed, we want the body's mime
 		   headers too */
-		i_assert(!data->save_bodystructure_header);
+		i_assert(data->parsed_bodystructure_header);
 		message_parser_parse_body(data->parser_ctx,
 					  parse_bodystructure_part_header,
 					  mail->mail.data_pool);
@@ -1327,7 +1327,8 @@
 		   a string */
 		index_mail_body_parsed_cache_bodystructure(mail, field);
 	} else {
-		if (data->save_bodystructure_header ||
+		if ((data->save_bodystructure_header &&
+		     !data->parsed_bodystructure_header) ||
 		    !data->save_bodystructure_body ||
 		    field == MAIL_CACHE_BODY_SNIPPET) {
 			/* we haven't parsed the header yet */
--- a/src/lib-storage/index/index-mail.h	Wed Jul 25 13:17:05 2018 +0300
+++ b/src/lib-storage/index/index-mail.h	Wed Jul 25 13:17:45 2018 +0300
@@ -118,6 +118,7 @@
 	unsigned int save_body_snippet:1;
 	unsigned int stream_has_only_header:1;
 	unsigned int parsed_bodystructure:1;
+	unsigned int parsed_bodystructure_header:1;
 	unsigned int hdr_size_set:1;
 	unsigned int body_size_set:1;
 	unsigned int messageparts_saved_to_cache:1;