$OpenBSD: patch-src_lib-compression_istream-lz4_c,v 1.1 2021/08/16 17:43:21 sthen Exp $

From eea3b751dee019609e70d95b37118ec2abe4c6b1 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Mon, 16 Aug 2021 14:50:10 +0300
Subject: [PATCH] lib-compression: istream-lz4 - Add asserts to make sure
 parent buffer isn't full

The parent buffer's max size would have to be tiny for these to happen.


From d8995452c80803a080fc5d0dfaf100fdb37107fe Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Mon, 16 Aug 2021 14:51:29 +0300
Subject: [PATCH] lib-compression: istream-lz4 - Remove redundant check

The loop is reached only if ret is 0, so there's no need to check it again.


From e14e68cb0bc71b0e57b3b72378c4ad8e3292e4f1 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Mon, 16 Aug 2021 14:52:50 +0300
Subject: [PATCH] lib-compression: istream-lz4 - Fix handling partial header
 reads

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.

Index: src/lib-compression/istream-lz4.c
--- src/lib-compression/istream-lz4.c.orig
+++ src/lib-compression/istream-lz4.c
@@ -47,11 +47,13 @@ static int i_stream_lz4_read_header(struct lz4_istream
 	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?)");
 			zstream->istream.istream.stream_errno = EINVAL;
@@ -60,10 +62,10 @@ static int i_stream_lz4_read_header(struct lz4_istream
 				zstream->istream.parent->stream_errno;
 		return ret;
 	}
-	if (ret == 0 && !zstream->istream.istream.eof)
+	if (zstream->chunk_buf->used < sizeof(*hdr)) {
+		i_assert(!zstream->istream.istream.blocking);
 		return 0;
-	if (zstream->chunk_buf->used < sizeof(*hdr))
-		return 0;
+	}
 
 	hdr = zstream->chunk_buf->data;
 	if (ret == 0 || memcmp(hdr->magic, IOSTREAM_LZ4_MAGIC,
@@ -99,6 +101,7 @@ static int i_stream_lz4_read_chunk_header(struct lz4_i
 	buffer_append(zstream->chunk_buf, data, size);
 	i_stream_skip(stream->parent, size);
 	if (ret < 0) {
+		i_assert(ret != -2);
 		stream->istream.stream_errno = stream->parent->stream_errno;
 		if (stream->istream.stream_errno == 0) {
 			stream->istream.eof = TRUE;
@@ -147,7 +150,7 @@ static ssize_t i_stream_lz4_read(struct istream_privat
 
 	if (zstream->chunk_left == 0) {
 		while ((ret = i_stream_lz4_read_chunk_header(zstream)) == 0) {
-			if (ret == 0 && !stream->istream.blocking)
+			if (!stream->istream.blocking)
 				return 0;
 		}
 		if (ret < 0)
