]> dgit.raspbian.org Git - dovecot.git/commitdiff
[PATCH 01/14] lib-mail: Reset charset translation buffer between MIME parts
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sat, 28 Feb 2026 08:27:19 +0000 (10:27 +0200)
committerNoah Meyerhans <noahm@debian.org>
Wed, 16 Sep 2026 19:06:35 +0000 (15:06 -0400)
If MIME part ended with an incomplete charset translation, the buffer was
kept for the next MIME part. This could have produced garbage in the next
MIME part, or a crash.

Fixes:
Panic: file message-decoder.c: line 232 (translation_buf_decode): assertion failed: (orig_size < CHARSET_MAX_PENDING_BUF_SIZE)

Gbp-Pq: Name 0001-lib-mail-Reset-charset-translation-buffer-between-MI.patch

src/lib-mail/message-decoder.c
src/lib-mail/test-message-decoder.c

index 845b3d5e3aee805275bad9be1f3e63d3e9f64c71..4eea9994a22e8ffad21fa96a77c3592ce52b76d0 100644 (file)
@@ -257,6 +257,10 @@ message_decode_body_init_charset(struct message_decoder_context *ctx,
        if (ctx->binary_input)
                return;
 
+       /* If some input was left untranslated in the previous MIME part,
+          it needs to be discarded now so it won't affect the next part. */
+       ctx->translation_size = 0;
+
        if (ctx->charset_trans != NULL && ctx->content_charset != NULL &&
            strcasecmp(ctx->content_charset, ctx->charset_trans_charset) == 0) {
                /* already have the correct translation selected */
index edf9210cda6bdde1a716bab970c4c8b8b866f6ed..83c267187b3f1a4539a1bd4219b640f583f2f8fe 100644 (file)
@@ -498,6 +498,57 @@ UNICODE_REPLACEMENT_CHAR_UTF8;
        test_end();
 }
 
+static void test_message_decoder_charset_mime_part_change(void)
+{
+       static const unsigned char test_message_input[] =
+"Content-Type: multipart/mixed; boundary=\"1\"\n"
+"MIME-Version: 1.0\n\n"
+"--1\n"
+"Content-Type: text/plain; charset=utf-8\n\n"
+"\xc3\n"
+"--1\n"
+"Content-Type: text/plain; charset=utf-8\n\n"
+"\xa4\n"
+"--1--\n";
+
+       static const char *test_message_output =
+               UNICODE_REPLACEMENT_CHAR_UTF8;
+
+       test_begin("message decoder charset - mime part change");
+
+       const struct message_parser_settings parser_set = { .flags = 0, };
+       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;
+
+       pool_t pool = pool_alloconly_create("message parser", 10240);
+       istream = test_istream_create_data(test_message_input,
+                                          sizeof(test_message_input)-1);
+       parser = message_parser_init(pool, istream, &parser_set);
+       decoder = message_decoder_init(NULL, 0);
+
+       while ((ret = message_parser_parse_next_block(parser, &input)) > 0) {
+               message_part_data_parse_from_header(pool, input.part, input.hdr);
+               if (message_decoder_decode_next_block(decoder, &input, &output) &&
+                   output.hdr == NULL && output.size > 0)
+                       str_append_data(str_out, output.data, output.size);
+       }
+
+       test_assert(ret == -1);
+       test_assert_strcmp(test_message_output, str_c(str_out));
+       message_decoder_deinit(&decoder);
+       message_parser_deinit(&parser, &parts);
+       test_assert(istream->stream_errno == 0);
+
+       i_stream_unref(&istream);
+       pool_unref(&pool);
+       test_end();
+}
+
 int main(void)
 {
        static void (*const test_functions[])(void) = {
@@ -507,6 +558,7 @@ int main(void)
                test_message_decoder_content_transfer_encoding,
                test_message_decoder_invalid_content_transfer_encoding,
                test_message_decoder_charset,
+               test_message_decoder_charset_mime_part_change,
                NULL
        };
        return test_run(test_functions);