From e72d13f3bec179b93d6dacf2fb44d68d8c5d1710 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 13 Feb 2017 18:05:13 +0200 Subject: [PATCH] lib-compress: Fix assert-crash when .gz header size exceeds buffer max length 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 | 5 ++++ src/lib-compression/test-compression.c | 41 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/lib-compression/istream-zlib.c b/src/lib-compression/istream-zlib.c index 0ed2686e3e..d82fbbccfe 100644 --- a/src/lib-compression/istream-zlib.c +++ b/src/lib-compression/istream-zlib.c @@ -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; diff --git a/src/lib-compression/test-compression.c b/src/lib-compression/test-compression.c index 012d0eebf1..43ee5c17bb 100644 --- a/src/lib-compression/test-compression.c +++ b/src/lib-compression/test-compression.c @@ -7,6 +7,7 @@ #include "sha1.h" #include "randgen.h" #include "test-common.h" +#include "istream-zlib.h" #include "compression.h" #include @@ -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) {