Subject: bug#56247: closed (Re: bug#56247: inflate fails to reject invalid distance)

From: [email-masked] (GNU bug Tracking System)
Date: Wed, 29 Jun 2022 03:46:01 +0000

Your bug report

#56247: inflate fails to reject invalid distance

which was filed against the gzip package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
56247: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=56247
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#56247: inflate fails to reject invalid distance
From: Paul Eggert <[email-masked]>
To: "Adler, Mark" <[email-masked]>
Cc: Young Mo Kang <[email-masked]>, GNU bug 56247 <[email-masked]>
Date: Tue, 28 Jun 2022 22:44:57 -0500
List-Id: <debbugs-submit.debbugs.gnu.org>

On 6/27/22 16:29, Adler, Mark wrote:
> Paul,
>
> gzip should reject invalid inflate input. The patch below does that.
>
Thanks for the quick patch. I installed that, along with Young Mo Kang's 
test case, as per the attached.
From 4b58eee79d3af3647adb4c78938d83970e788975 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@trombone>
Date: Tue, 28 Jun 2022 22:30:08 -0500
Subject: [PATCH 1/2] gzip: detect invalid input

Problem reported by Young Mo Kang and fix from Mark Adler (Bug#56247).
* inflate.c: Include stdbool.h.
(fresh): New static var.
* inflate.c (flush_output): Clear it.
(inflate): Set it.
(inflate_codes): Fail if the offset is outside a fresh input window.
---
 inflate.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/inflate.c b/inflate.c
index 199a935..4fbb1be 100644
--- a/inflate.c
+++ b/inflate.c
@@ -117,6 +117,7 @@
 
 #include <config.h>
 
+#include <stdbool.h>
 #include <stdlib.h>
 
 #include "tailor.h"
@@ -153,8 +154,9 @@ static int huft_free (struct huft *);
    "uch *slide;" and then malloc'ed in the latter case.  The definition
    must be in unzip.h, included above. */
 /* unsigned wp;             current position in slide */
+static bool fresh;
 #define wp outcnt
-#define flush_output(w) (wp=(w),flush_window())
+#define flush_output(w) (fresh = false, wp = (w), flush_window ())
 
 /* Tables for deflate from PKZIP's appnote.txt. */
 static unsigned border[] = {    /* Order of the bit length code lengths */
@@ -582,6 +584,8 @@ inflate_codes(struct huft *tl, struct huft *td, int bl, int bd)
       NEEDBITS(e)
       d = w - t->v.n - ((unsigned)b & mask_bits[e]);
       DUMPBITS(e)
+      if (fresh && w <= d)
+	return 1;
       Tracevv ((stderr, "\\[%u,%u]", w - d, n));
 
       /* do the copy */
@@ -964,6 +968,7 @@ inflate(void)
   wp = 0;
   bk = 0;
   bb = 0;
+  fresh = true;

   /* decompress until the last block */
-- 
2.25.1

From 3e32e3c3583e5249394d45f7a1f9bf3156c8d32f Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@trombone>
Date: Tue, 28 Jun 2022 22:32:09 -0500
Subject: [PATCH 2/2] gzip: test invalid-input bug

* NEWS: Mention the bug.
* tests/unpack-invalid: Test for the bug.
---
 NEWS                 | 6 ++++++
 tests/unpack-invalid | 1 +
 2 files changed, 7 insertions(+)

diff --git a/NEWS b/NEWS
index 1074c66..364811a 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@ GNU gzip NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
+  'gzip -d' no longer fails to report invalid compressed data
+  that uses a dictionary distance outside the input window.
+  [bug present since the beginning]
+
 
 * Noteworthy changes in release 1.12 (2022-04-07) [stable]
 
diff --git a/tests/unpack-invalid b/tests/unpack-invalid
index 14984a1..f659aa8 100755
--- a/tests/unpack-invalid
+++ b/tests/unpack-invalid
@@ -22,6 +22,7 @@
 
 fail=0
 for input in \
+  '\37\213\b\0\0\0\0\0\0\3s\212\31204t\214T\v\216\274)q)\210\201A\341\377\377\37\f\23\30B\4\30\30\27+\\aih`hpd8\300\252\320\300\310\300\340\300\300\330\340\350\300\261\200!$\331M\201!\205q\341\253\214o+LM\331W\2300\310-|\305\300\256r\341\213\377\357\312\266$N\16E6\206\24\206\365\346\22\253\332L3l\366\334]]\244\275lM\355I\241;\377\343x\23\26M9\330\252\375\261\\%%\270\225\223wb\257\252\2\302\5\336\377\205\302\30\30\30\243$\03700010214\b0\260002p.`0dv\270 5o\371+7\237\366%%WL\246YMZ\234\367FN\277{\247\322\34\r\17\325\377\235\332\20\177\0\0@\23a\3\315\0\0\0' \
   '\037\036\000\000\037\213\010\000\000\000\000\000\002\003\036\000\000\000\002\003\037\213\010\000\000\000\000\000\002\003\355\301\001\015\000\000\000\302\240\037\000\302\240\037\213\010\000\000\000\000\000\002\003\355\301' \
   '\037\213\010\000\000\000\000\000\002\003\355\301\001\015\000\000\000\302\240\076\366\017\370\036\016\030\000\000\000\000\000\000\000\000\000\034\010\105\140\104\025\020\047\000\000\037\036\016\030\000\000\000'; do
 
-- 
2.25.1

Subject: inflate fails to reject invalid distance
From: Young Mo Kang <[email-masked]>
To: [email-masked]
Date: Sun, 26 Jun 2022 20:21:09 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Hello gzip devs and maintainers,

I noticed that GNU gzip does not check for error during decompression when the distance value exceeds the current accumulative position, i.e., back reference to position beyond the starting point.

The following shows an example .gz file with invalid distance

```
cat << EOF > file.gz.hex
1f8b0800000000000003738aca3034748c540b8ebc297129888141e1ffff
1f0c131842041818172b5c6169686068706438c0aad0c0c8c0e0c0c0d8e0
e8c0b1802124d94d81218571e1ab8c6f2b4c4dd9579830c82d7cc5c0ae72
e18bffefcab6244e0e4536861486f5e612abda4c336cf6dc5d5da4bd6c4d
ed49a13bffe37813164d39d8aafdb15c25b895937762afaa02c205deff85
c2181818a3241f30303031303231340830b0303032702e60306476b82035
6ff92b379ff625574ca6594d5a9cf7464ebf7ba7d21c0d0fd5ff9dda107f
000040136103cd000000
EOF

xxd -r -ps file.gz.hex | gzip -d > file
```

GNU gzip decompresses it w/o an error, while both macOS’s gzip and zlib reject the file and outputs an error:

macOS gzip: gzip: data stream error
zlib: <fd:0>: invalid distance too far back

I believe GNU gzip also needs to reject this file, since the file is not a valid deflate format.

Thanks,
Young