At Wed, 3 Jun 2020 08:35:02 -0400, Jeff Janes <jeff.janes@gmail.com> wrote in
> I can reproduce this at any compression level if the data is random (not
> compressible) and exactly 16365 bytes long. If the data is compressible,
> then you need a longer length of message to reproduce it and it depends on
> the random content and compression level.
>
> I'm attaching the reproducer as a Perl script. I have not investigated the
> C code of pgcrypto itself.
Thanks for the reproducer.
Compressed stream must end with a normal packet. If a stream ends with
a complete stream packet, deflator adds a zero-length normal packet at
the end. decompress_read forgets to read such a terminating packet
when EOF comes at just at the end of the last stream packet. An extra
call to pullf_read at EOF correctly consumes such an extra packet.
The extra call doesn't harm if a stream ends with partial normal
packet.
The reproducer becomes not to fail with the attached patch.
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
From f4a8997ec08c0aaec8326b0f0dda9f3a001d5865 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horikyoga.ntt@gmail.com>
Date: Thu, 11 Jun 2020 20:29:23 +0900
Subject: [PATCH] Make sure to consume stream-terminating packet
When compressed stream is ended with a full stream packet, it must be
followed by a terminating normal packet with zero-length. Make sure
consume such terminating packet at the end of stream.
---
contrib/pgcrypto/pgp-compress.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c
index 0505bdee92..69a8d6c577 100644
--- a/contrib/pgcrypto/pgp-compress.c
+++ b/contrib/pgcrypto/pgp-compress.c
@@ -286,7 +286,20 @@ restart:
dec->buf_data = dec->buf_len - dec->stream.avail_out;
if (res == Z_STREAM_END)
+ {
+ uint8 *tmp;
+
+ /*
+ * If source stream ends with a full stream packet, it is followed by
+ * an extra normal zero-length packet, which should be consumed before
+ * reading further. If we have already seen a terminating packet,
+ * nothing happen by this call.
+ */
+ res = pullf_read(src, 1, &tmp);
+ Assert(res == 0);
+
dec->eof = 1;
+ }
goto restart;
}
--
2.18.2