]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-compression: istream-lz4 - Fix handling partial header reads
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 16 Aug 2021 11:52:50 +0000 (14:52 +0300)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 16 Aug 2021 11:57:36 +0000 (14:57 +0300)
Reading assert-crashed if the header was read only partially. Either
because the file really was truncated or because parent stream already
had fewer bytes buffered.

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

index 86a78b7b366362a059f6659bc0027f2ccada4613..24d539a96f2fe861eada9c7aebf8f5bcb86ec79a 100644 (file)
@@ -47,11 +47,12 @@ static int i_stream_lz4_read_header(struct lz4_istream *zstream)
        size_t size;
        int ret;
 
-       ret = i_stream_read_more(zstream->istream.parent, &data, &size);
+       ret = i_stream_read_bytes(zstream->istream.parent, &data,
+                                 &size, sizeof(*hdr));
        size = I_MIN(size, sizeof(*hdr));
        buffer_append(zstream->chunk_buf, data, size);
        i_stream_skip(zstream->istream.parent, size);
-       if (ret < 0) {
+       if (ret < 0 || (ret == 0 && zstream->istream.istream.eof)) {
                i_assert(ret != -2);
                if (zstream->istream.istream.stream_errno == 0) {
                        lz4_read_error(zstream, "missing header (not lz4 file?)");
@@ -61,10 +62,10 @@ static int i_stream_lz4_read_header(struct lz4_istream *zstream)
                                zstream->istream.parent->stream_errno;
                return ret;
        }
-       if (ret == 0 && !zstream->istream.istream.eof)
-               return 0;
-       if (zstream->chunk_buf->used < sizeof(*hdr))
+       if (zstream->chunk_buf->used < sizeof(*hdr)) {
+               i_assert(!zstream->istream.istream.blocking);
                return 0;
+       }
 
        hdr = zstream->chunk_buf->data;
        if (ret == 0 || memcmp(hdr->magic, IOSTREAM_LZ4_MAGIC,
index eee89fd3d230c40995fdb2863361cb7d46f0dff5..f690c7b9d505c8322bd10ef6173dc0e15da345e7 100644 (file)
@@ -9,6 +9,7 @@
 #include "randgen.h"
 #include "test-common.h"
 #include "compression.h"
+#include "iostream-lz4.h"
 
 #include "hex-binary.h"
 
@@ -952,6 +953,48 @@ static void test_gz_large_header(void)
        test_gz_large_header_int(TRUE);
 }
 
+static void test_lz4_small_header(void)
+{
+       const struct compression_handler *lz4;
+       struct iostream_lz4_header lz4_input;
+       struct istream *file_input, *input;
+
+       if (compression_lookup_handler("lz4", &lz4) <= 0)
+               return; /* not compiled in or unkown */
+
+       test_begin("lz4 small header");
+
+       memcpy(lz4_input.magic, IOSTREAM_LZ4_MAGIC, IOSTREAM_LZ4_MAGIC_LEN);
+       lz4_input.max_uncompressed_chunk_size[0] = 0;
+       lz4_input.max_uncompressed_chunk_size[1] = 1;
+       lz4_input.max_uncompressed_chunk_size[2] = 0;
+       lz4_input.max_uncompressed_chunk_size[3] = 0;
+
+       /* truncated header */
+       file_input = i_stream_create_from_data(&lz4_input, sizeof(lz4_input)-1);
+       input = lz4->create_istream(file_input);
+       test_assert(i_stream_read(input) == -1 &&
+                   input->stream_errno == EINVAL);
+       i_stream_unref(&input);
+       i_stream_unref(&file_input);
+
+       /* partial initial header read */
+       file_input = test_istream_create_data(&lz4_input, sizeof(lz4_input));
+       file_input->blocking = TRUE;
+
+       test_istream_set_max_buffer_size(file_input, sizeof(lz4_input)-1);
+       (void)i_stream_read(file_input);
+       test_istream_set_max_buffer_size(file_input, sizeof(lz4_input));
+
+       input = lz4->create_istream(file_input);
+       test_assert(i_stream_read(input) == -1 &&
+                   input->stream_errno == 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;
@@ -1063,6 +1106,7 @@ int main(int argc, char *argv[])
                test_gz_no_concat,
                test_gz_header,
                test_gz_large_header,
+               test_lz4_small_header,
                test_compression_ext,
                NULL
        };