]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-compress: Fix assert-crash when .gz header size exceeds buffer max length
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 13 Feb 2017 16:05:13 +0000 (18:05 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 17 Feb 2017 09:32:31 +0000 (11:32 +0200)
Instead treat the stream as corrupted and return EINVAL.

Fixes:
Panic: file istream.c: line 182 (i_stream_read): assertion failed: (_stream->skip != _stream->pos)

src/lib-compression/istream-zlib.c
src/lib-compression/test-compression.c

index 0ed2686e3ed4d4b6495cc9a5471d613d359eecb5..d82fbbccfe4f55797cc5876a3b7d793e6f5949a9 100644 (file)
@@ -81,6 +81,11 @@ static int i_stream_zlib_read_header(struct istream_private *stream)
                        zlib_read_error(zstream, "missing gz trailer");
                        stream->istream.stream_errno = EINVAL;
                }
+               if (ret == -2) {
+                       zlib_read_error(zstream, "gz header is too large");
+                       stream->istream.stream_errno = EINVAL;
+                       ret = -1;
+               }
                return ret;
        }
        zstream->prev_size = size;
index 012d0eebf11ca6026dc874f0634e3c46c57194b0..43ee5c17bba14730f7e6a8417f23f81811013f53 100644 (file)
@@ -7,6 +7,7 @@
 #include "sha1.h"
 #include "randgen.h"
 #include "test-common.h"
+#include "istream-zlib.h"
 #include "compression.h"
 
 #include <unistd.h>
@@ -159,6 +160,45 @@ static void test_gz_no_concat(void)
        test_end();
 }
 
+static void test_gz_large_header(void)
+{
+       static const unsigned char gz_input[] = {
+               0x1f, 0x8b, 0x08, 0x08,
+               'a','a','a','a','a','a','a','a','a','a','a',
+               0
+       };
+       struct istream *file_input, *input;
+       size_t i;
+
+       test_begin("gz large header");
+
+       /* max buffer size smaller than gz header */
+       for (i = 1; i < sizeof(gz_input); i++) {
+               file_input = test_istream_create_data(gz_input, sizeof(gz_input));
+               test_istream_set_size(file_input, i);
+               test_istream_set_max_buffer_size(file_input, i);
+
+               input = i_stream_create_gz(file_input, FALSE);
+               test_assert_idx(i_stream_read(input) == 0, i);
+               test_assert_idx(i_stream_read(input) == -1 &&
+                               input->stream_errno == EINVAL, i);
+               i_stream_unref(&input);
+               i_stream_unref(&file_input);
+       }
+
+       /* max buffer size is exactly the gz header */
+       file_input = test_istream_create_data(gz_input, sizeof(gz_input));
+       input = i_stream_create_gz(file_input, FALSE);
+       test_istream_set_size(input, i);
+       test_istream_set_allow_eof(input, FALSE);
+       test_istream_set_max_buffer_size(input, i);
+       test_assert(i_stream_read(input) == 0);
+       i_stream_unref(&input);
+       i_stream_unref(&file_input);
+
+       test_end();
+}
+
 static void test_uncompress_file(const char *path)
 {
        const struct compression_handler *handler;
@@ -249,6 +289,7 @@ int main(int argc, char *argv[])
                test_compression,
                test_gz_concat,
                test_gz_no_concat,
+               test_gz_large_header,
                NULL
        };
        if (argc == 2) {