Blame SOURCES/dovecot-2.3.8-CVE_2020_12100prereq.patch

b62b43
diff -up dovecot-2.3.8/src/lib-mail/message-decoder.c.CVE_2020_12100prereq dovecot-2.3.8/src/lib-mail/message-decoder.c
b62b43
--- dovecot-2.3.8/src/lib-mail/message-decoder.c.CVE_2020_12100prereq	2019-10-08 10:46:18.000000000 +0200
b62b43
+++ dovecot-2.3.8/src/lib-mail/message-decoder.c	2020-08-07 17:48:58.320126698 +0200
b62b43
@@ -13,9 +13,6 @@
b62b43
 #include "message-header-decode.h"
b62b43
 #include "message-decoder.h"
b62b43
 
b62b43
-/* base64 takes max 4 bytes per character, q-p takes max 3. */
b62b43
-#define MAX_ENCODING_BUF_SIZE 3
b62b43
-
b62b43
 struct message_decoder_context {
b62b43
 	enum message_decoder_flags flags;
b62b43
 	normalizer_func_t *normalizer;
b62b43
@@ -30,7 +27,7 @@ struct message_decoder_context {
b62b43
 	size_t translation_size;
b62b43
 
b62b43
 	struct qp_decoder *qp;
b62b43
-	buffer_t *encoding_buf;
b62b43
+	struct base64_decoder base64_decoder;
b62b43
 
b62b43
 	char *content_type, *content_charset;
b62b43
 	enum message_cte message_cte;
b62b43
@@ -53,7 +50,7 @@ message_decoder_init(normalizer_func_t *
b62b43
 	ctx->normalizer = normalizer;
b62b43
 	ctx->buf = buffer_create_dynamic(default_pool, 8192);
b62b43
 	ctx->buf2 = buffer_create_dynamic(default_pool, 8192);
b62b43
-	ctx->encoding_buf = buffer_create_dynamic(default_pool, 128);
b62b43
+	base64_decode_init(&ctx->base64_decoder, &base64_scheme, 0);
b62b43
 	return ctx;
b62b43
 }
b62b43
 
b62b43
@@ -68,7 +65,6 @@ void message_decoder_deinit(struct messa
b62b43
 	if (ctx->qp != NULL)
b62b43
 		qp_decoder_deinit(&ctx->qp);
b62b43
 
b62b43
-	buffer_free(&ctx->encoding_buf);
b62b43
 	buffer_free(&ctx->buf);
b62b43
 	buffer_free(&ctx->buf2);
b62b43
 	i_free(ctx->charset_trans_charset);
b62b43
@@ -273,14 +269,9 @@ static bool message_decode_body(struct m
b62b43
 				struct message_block *input,
b62b43
 				struct message_block *output)
b62b43
 {
b62b43
-	struct base64_decoder b64dec;
b62b43
 	const unsigned char *data = NULL;
b62b43
-	size_t pos = 0, size = 0;
b62b43
+	size_t pos, size = 0;
b62b43
 	const char *error;
b62b43
-	int ret;
b62b43
-
b62b43
-	if (ctx->encoding_buf->used != 0)
b62b43
-		buffer_append(ctx->encoding_buf, input->data, input->size);
b62b43
 
b62b43
 	switch (ctx->message_cte) {
b62b43
 	case MESSAGE_CTE_UNKNOWN:
b62b43
@@ -289,12 +280,10 @@ static bool message_decode_body(struct m
b62b43
 
b62b43
 	case MESSAGE_CTE_78BIT:
b62b43
 	case MESSAGE_CTE_BINARY:
b62b43
-		i_assert(ctx->encoding_buf->used == 0);
b62b43
 		data = input->data;
b62b43
-		size = pos = input->size;
b62b43
+		size = input->size;
b62b43
 		break;
b62b43
 	case MESSAGE_CTE_QP: {
b62b43
-		i_assert(ctx->encoding_buf->used == 0);
b62b43
 		buffer_set_used_size(ctx->buf, 0);
b62b43
 		if (ctx->qp == NULL)
b62b43
 			ctx->qp = qp_decoder_init(ctx->buf);
b62b43
@@ -302,45 +291,24 @@ static bool message_decode_body(struct m
b62b43
 				      &pos, &error);
b62b43
 		data = ctx->buf->data;
b62b43
 		size = ctx->buf->used;
b62b43
-		/* eat away all input. qp-decoder buffers it internally. */
b62b43
-		pos = input->size;
b62b43
 		break;
b62b43
 	}
b62b43
 	case MESSAGE_CTE_BASE64:
b62b43
 		buffer_set_used_size(ctx->buf, 0);
b62b43
-		base64_decode_init(&b64dec, &base64_scheme, 0);
b62b43
-		if (ctx->encoding_buf->used != 0) {
b62b43
-			ret = base64_decode_more(&b64dec,
b62b43
-						 ctx->encoding_buf->data,
b62b43
-						 ctx->encoding_buf->used,
b62b43
-						 &pos, ctx->buf);
b62b43
-		} else {
b62b43
-			ret = base64_decode_more(&b64dec,
b62b43
-						 input->data, input->size,
b62b43
-						 &pos, ctx->buf);
b62b43
-		}
b62b43
-		if (ret < 0 || base64_decode_finish(&b64dec) < 0) {
b62b43
-			/* corrupted base64 data, don't bother with
b62b43
-			   the rest of it */
b62b43
-			return FALSE;
b62b43
-		}
b62b43
-		if (ret == 0) {
b62b43
-			/* end of base64 input */
b62b43
-			pos = input->size;
b62b43
-			buffer_set_used_size(ctx->encoding_buf, 0);
b62b43
+		if (!base64_decode_is_finished(&ctx->base64_decoder)) {
b62b43
+			if (base64_decode_more(&ctx->base64_decoder,
b62b43
+					       input->data, input->size,
b62b43
+					       &pos, ctx->buf) <= 0) {
b62b43
+				/* ignore the rest of the input in this
b62b43
+				   MIME part */
b62b43
+				(void)base64_decode_finish(&ctx->base64_decoder);
b62b43
+			}
b62b43
 		}
b62b43
 		data = ctx->buf->data;
b62b43
 		size = ctx->buf->used;
b62b43
 		break;
b62b43
 	}
b62b43
 
b62b43
-	if (ctx->encoding_buf->used != 0)
b62b43
-		buffer_delete(ctx->encoding_buf, 0, pos);
b62b43
-	else if (pos != input->size) {
b62b43
-		buffer_append(ctx->encoding_buf,
b62b43
-			      input->data + pos, input->size - pos);
b62b43
-	}
b62b43
-
b62b43
 	if (ctx->binary_input) {
b62b43
 		output->data = data;
b62b43
 		output->size = size;
b62b43
@@ -402,10 +370,11 @@ void message_decoder_decode_reset(struct
b62b43
 {
b62b43
 	const char *error;
b62b43
 
b62b43
+	base64_decode_reset(&ctx->base64_decoder);
b62b43
+
b62b43
 	if (ctx->qp != NULL)
b62b43
 		(void)qp_decoder_finish(ctx->qp, &error);
b62b43
 	i_free_and_null(ctx->content_type);
b62b43
 	i_free_and_null(ctx->content_charset);
b62b43
 	ctx->message_cte = MESSAGE_CTE_78BIT;
b62b43
-	buffer_set_used_size(ctx->encoding_buf, 0);
b62b43
 }
b62b43
diff -up dovecot-2.3.8/src/lib-mail/test-message-decoder.c.CVE_2020_12100prereq dovecot-2.3.8/src/lib-mail/test-message-decoder.c
b62b43
--- dovecot-2.3.8/src/lib-mail/test-message-decoder.c.CVE_2020_12100prereq	2019-10-08 10:46:18.000000000 +0200
b62b43
+++ dovecot-2.3.8/src/lib-mail/test-message-decoder.c	2020-08-07 17:50:04.612248484 +0200
b62b43
@@ -1,7 +1,8 @@
b62b43
 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
b62b43
 
b62b43
 #include "lib.h"
b62b43
-#include "buffer.h"
b62b43
+#include "str.h"
b62b43
+#include "istream.h"
b62b43
 #include "charset-utf8.h"
b62b43
 #include "message-parser.h"
b62b43
 #include "message-header-decode.h"
b62b43
@@ -82,6 +83,66 @@ static void test_message_decoder(void)
b62b43
 	test_end();
b62b43
 }
b62b43
 
b62b43
+static void test_message_decoder_multipart(void)
b62b43
+{
b62b43
+	static const char test_message_input[] =
b62b43
+		"Content-Type: multipart/mixed; boundary=foo\n"
b62b43
+		"\n"
b62b43
+		"--foo\n"
b62b43
+		"Content-Transfer-Encoding: quoted-printable\n"
b62b43
+		"Content-Type: text/plain; charset=utf-8\n"
b62b43
+		"\n"
b62b43
+		"p=C3=A4iv=C3=A4=C3=A4\n"
b62b43
+		"\n"
b62b43
+		"--foo\n"
b62b43
+		"Content-Transfer-Encoding: base64\n"
b62b43
+		"Content-Type: text/plain; charset=utf-8\n"
b62b43
+		"\n"
b62b43
+		"ecO2dMOkIHZhYW4uCg== ignored\n"
b62b43
+		"--foo\n"
b62b43
+		"Content-Transfer-Encoding: base64\n"
b62b43
+		"Content-Type: text/plain; charset=utf-8\n"
b62b43
+		"\n"
b62b43
+		"?garbage\n"
b62b43
+		"--foo--\n";
b62b43
+	struct message_parser_ctx *parser;
b62b43
+	struct message_decoder_context *decoder;
b62b43
+	struct message_part *parts;
b62b43
+	struct message_block input, output;
b62b43
+	struct istream *istream;
b62b43
+	string_t *str_out = t_str_new(20);
b62b43
+	int ret;
b62b43
+
b62b43
+	test_begin("message decoder multipart");
b62b43
+
b62b43
+	istream = test_istream_create(test_message_input);
b62b43
+	parser = message_parser_init(pool_datastack_create(), istream, 0, 0);
b62b43
+	decoder = message_decoder_init(NULL, 0);
b62b43
+
b62b43
+	test_istream_set_allow_eof(istream, FALSE);
b62b43
+	for (size_t i = 0; i < sizeof(test_message_input); i++) {
b62b43
+		if (i == sizeof(test_message_input)-1)
b62b43
+			test_istream_set_allow_eof(istream, TRUE);
b62b43
+		test_istream_set_size(istream, i);
b62b43
+		while ((ret = message_parser_parse_next_block(parser, &input)) > 0) {
b62b43
+			if (message_decoder_decode_next_block(decoder, &input, &output) &&
b62b43
+			    output.hdr == NULL && output.size > 0)
b62b43
+				str_append_data(str_out, output.data, output.size);
b62b43
+		}
b62b43
+		if (i == sizeof(test_message_input)-1)
b62b43
+			test_assert(ret == -1);
b62b43
+		else
b62b43
+			test_assert(ret == 0);
b62b43
+	}
b62b43
+	/* NOTE: qp-decoder decoder changes \n into \r\n */
b62b43
+	test_assert_strcmp(str_c(str_out), "p\xC3\xA4iv\xC3\xA4\xC3\xA4\r\ny\xC3\xB6t\xC3\xA4 vaan.\n");
b62b43
+
b62b43
+	message_decoder_deinit(&decoder);
b62b43
+	message_parser_deinit(&parser, &parts;;
b62b43
+	i_stream_unref(&istream);
b62b43
+	test_end();
b62b43
+}
b62b43
+
b62b43
 static void test_message_decoder_current_content_type(void)
b62b43
 {
b62b43
 	struct message_decoder_context *ctx;
b62b43
@@ -149,6 +210,7 @@ int main(void)
b62b43
 {
b62b43
 	static void (*const test_functions[])(void) = {
b62b43
 		test_message_decoder,
b62b43
+		test_message_decoder_multipart,
b62b43
 		test_message_decoder_current_content_type,
b62b43
 		NULL
b62b43
 	};