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