f3d89c
From 5c44459c3b28a9bd3283aaceab7c615f8020c531 Mon Sep 17 00:00:00 2001
f3d89c
From: Mark Adler <madler@alumni.caltech.edu>
f3d89c
Date: Tue, 17 Apr 2018 22:09:22 -0700
f3d89c
Subject: [PATCH] Fix a bug that can crash deflate on some input when using
f3d89c
 Z_FIXED.
f3d89c
f3d89c
This bug was reported by Danilo Ramos of Eideticom, Inc. It has
f3d89c
lain in wait 13 years before being found! The bug was introduced
f3d89c
in zlib 1.2.2.2, with the addition of the Z_FIXED option. That
f3d89c
option forces the use of fixed Huffman codes. For rare inputs with
f3d89c
a large number of distant matches, the pending buffer into which
f3d89c
the compressed data is written can overwrite the distance symbol
f3d89c
table which it overlays. That results in corrupted output due to
f3d89c
invalid distances, and can result in out-of-bound accesses,
f3d89c
crashing the application.
f3d89c
f3d89c
The fix here combines the distance buffer and literal/length
f3d89c
buffers into a single symbol buffer. Now three bytes of pending
f3d89c
buffer space are opened up for each literal or length/distance
f3d89c
pair consumed, instead of the previous two bytes. This assures
f3d89c
that the pending buffer cannot overwrite the symbol table, since
f3d89c
the maximum fixed code compressed length/distance is 31 bits, and
f3d89c
since there are four bytes of pending space for every three bytes
f3d89c
of symbol space.
f3d89c
---
f3d89c
 deflate.c | 74 ++++++++++++++++++++++++++++++++++++++++---------------
f3d89c
 deflate.h | 25 +++++++++----------
f3d89c
 trees.c   | 50 +++++++++++--------------------------
f3d89c
 3 files changed, 79 insertions(+), 70 deletions(-)
f3d89c
f3d89c
diff --git a/deflate.c b/deflate.c
f3d89c
index 425babc..19cba87 100644
f3d89c
--- a/deflate.c
f3d89c
+++ b/deflate.c
f3d89c
@@ -255,11 +255,6 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
f3d89c
     int wrap = 1;
f3d89c
     static const char my_version[] = ZLIB_VERSION;
f3d89c
 
f3d89c
-    ushf *overlay;
f3d89c
-    /* We overlay pending_buf and d_buf+l_buf. This works since the average
f3d89c
-     * output size for (length,distance) codes is <= 24 bits.
f3d89c
-     */
f3d89c
-
f3d89c
     if (version == Z_NULL || version[0] != my_version[0] ||
f3d89c
         stream_size != sizeof(z_stream)) {
f3d89c
         return Z_VERSION_ERROR;
f3d89c
@@ -329,9 +324,47 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
f3d89c
 
f3d89c
     s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
f3d89c
 
f3d89c
-    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
f3d89c
-    s->pending_buf = (uchf *) overlay;
f3d89c
-    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
f3d89c
+    /* We overlay pending_buf and sym_buf. This works since the average size
f3d89c
+     * for length/distance pairs over any compressed block is assured to be 31
f3d89c
+     * bits or less.
f3d89c
+     *
f3d89c
+     * Analysis: The longest fixed codes are a length code of 8 bits plus 5
f3d89c
+     * extra bits, for lengths 131 to 257. The longest fixed distance codes are
f3d89c
+     * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest
f3d89c
+     * possible fixed-codes length/distance pair is then 31 bits total.
f3d89c
+     *
f3d89c
+     * sym_buf starts one-fourth of the way into pending_buf. So there are
f3d89c
+     * three bytes in sym_buf for every four bytes in pending_buf. Each symbol
f3d89c
+     * in sym_buf is three bytes -- two for the distance and one for the
f3d89c
+     * literal/length. As each symbol is consumed, the pointer to the next
f3d89c
+     * sym_buf value to read moves forward three bytes. From that symbol, up to
f3d89c
+     * 31 bits are written to pending_buf. The closest the written pending_buf
f3d89c
+     * bits gets to the next sym_buf symbol to read is just before the last
f3d89c
+     * code is written. At that time, 31*(n-2) bits have been written, just
f3d89c
+     * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
f3d89c
+     * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
f3d89c
+     * symbols are written.) The closest the writing gets to what is unread is
f3d89c
+     * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
f3d89c
+     * can range from 128 to 32768.
f3d89c
+     *
f3d89c
+     * Therefore, at a minimum, there are 142 bits of space between what is
f3d89c
+     * written and what is read in the overlain buffers, so the symbols cannot
f3d89c
+     * be overwritten by the compressed data. That space is actually 139 bits,
f3d89c
+     * due to the three-bit fixed-code block header.
f3d89c
+     *
f3d89c
+     * That covers the case where either Z_FIXED is specified, forcing fixed
f3d89c
+     * codes, or when the use of fixed codes is chosen, because that choice
f3d89c
+     * results in a smaller compressed block than dynamic codes. That latter
f3d89c
+     * condition then assures that the above analysis also covers all dynamic
f3d89c
+     * blocks. A dynamic-code block will only be chosen to be emitted if it has
f3d89c
+     * fewer bits than a fixed-code block would for the same set of symbols.
f3d89c
+     * Therefore its average symbol length is assured to be less than 31. So
f3d89c
+     * the compressed data for a dynamic block also cannot overwrite the
f3d89c
+     * symbols from which it is being constructed.
f3d89c
+     */
f3d89c
+
f3d89c
+    s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
f3d89c
+    s->pending_buf_size = (ulg)s->lit_bufsize * 4;
f3d89c
 
f3d89c
     if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
f3d89c
         s->pending_buf == Z_NULL) {
f3d89c
@@ -340,8 +373,12 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
f3d89c
         deflateEnd (strm);
f3d89c
         return Z_MEM_ERROR;
f3d89c
     }
f3d89c
-    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
f3d89c
-    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
f3d89c
+    s->sym_buf = s->pending_buf + s->lit_bufsize;
f3d89c
+    s->sym_end = (s->lit_bufsize - 1) * 3;
f3d89c
+    /* We avoid equality with lit_bufsize*3 because of wraparound at 64K
f3d89c
+     * on 16 bit machines and because stored blocks are restricted to
f3d89c
+     * 64K-1 bytes.
f3d89c
+     */
f3d89c
 
f3d89c
     s->level = level;
f3d89c
     s->strategy = strategy;
f3d89c
@@ -552,7 +589,7 @@ int ZEXPORT deflatePrime (strm, bits, value)
f3d89c
 
f3d89c
     if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
f3d89c
     s = strm->state;
f3d89c
-    if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
f3d89c
+    if (s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
f3d89c
         return Z_BUF_ERROR;
f3d89c
     do {
f3d89c
         put = Buf_size - s->bi_valid;
f3d89c
@@ -1113,7 +1150,6 @@ int ZEXPORT deflateCopy (dest, source)
f3d89c
 #else
f3d89c
     deflate_state *ds;
f3d89c
     deflate_state *ss;
f3d89c
-    ushf *overlay;
f3d89c
 
f3d89c
 
f3d89c
     if (deflateStateCheck(source) || dest == Z_NULL) {
f3d89c
@@ -1133,8 +1169,7 @@ int ZEXPORT deflateCopy (dest, source)
f3d89c
     ds->window = (Bytef *) ZALLOC_WINDOW(dest, ds->w_size, 2*sizeof(Byte));
f3d89c
     ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
f3d89c
     ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
f3d89c
-    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
f3d89c
-    ds->pending_buf = (uchf *) overlay;
f3d89c
+    ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);
f3d89c
 
f3d89c
     if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
f3d89c
         ds->pending_buf == Z_NULL) {
f3d89c
@@ -1148,8 +1183,7 @@ int ZEXPORT deflateCopy (dest, source)
f3d89c
     zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
f3d89c
 
f3d89c
     ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
f3d89c
-    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
f3d89c
-    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
f3d89c
+    ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
f3d89c
 
f3d89c
     ds->l_desc.dyn_tree = ds->dyn_ltree;
f3d89c
     ds->d_desc.dyn_tree = ds->dyn_dtree;
f3d89c
@@ -1925,7 +1959,7 @@ local block_state deflate_fast(s, flush)
f3d89c
         FLUSH_BLOCK(s, 1);
f3d89c
         return finish_done;
f3d89c
     }
f3d89c
-    if (s->last_lit)
f3d89c
+    if (s->sym_next)
f3d89c
         FLUSH_BLOCK(s, 0);
f3d89c
     return block_done;
f3d89c
 }
f3d89c
@@ -2056,7 +2090,7 @@ local block_state deflate_slow(s, flush)
f3d89c
         FLUSH_BLOCK(s, 1);
f3d89c
         return finish_done;
f3d89c
     }
f3d89c
-    if (s->last_lit)
f3d89c
+    if (s->sym_next)
f3d89c
         FLUSH_BLOCK(s, 0);
f3d89c
     return block_done;
f3d89c
 }
f3d89c
@@ -2131,7 +2165,7 @@ local block_state deflate_rle(s, flush)
f3d89c
         FLUSH_BLOCK(s, 1);
f3d89c
         return finish_done;
f3d89c
     }
f3d89c
-    if (s->last_lit)
f3d89c
+    if (s->sym_next)
f3d89c
         FLUSH_BLOCK(s, 0);
f3d89c
     return block_done;
f3d89c
 }
f3d89c
@@ -2170,7 +2204,7 @@ local block_state deflate_huff(s, flush)
f3d89c
         FLUSH_BLOCK(s, 1);
f3d89c
         return finish_done;
f3d89c
     }
f3d89c
-    if (s->last_lit)
f3d89c
+    if (s->sym_next)
f3d89c
         FLUSH_BLOCK(s, 0);
f3d89c
     return block_done;
f3d89c
 }
f3d89c
diff --git a/deflate.h b/deflate.h
f3d89c
index 23ecdd3..d4cf1a9 100644
f3d89c
--- a/deflate.h
f3d89c
+++ b/deflate.h
f3d89c
@@ -217,7 +217,7 @@ typedef struct internal_state {
f3d89c
     /* Depth of each subtree used as tie breaker for trees of equal frequency
f3d89c
      */
f3d89c
 
f3d89c
-    uchf *l_buf;          /* buffer for literals or lengths */
f3d89c
+    uchf *sym_buf;        /* buffer for distances and literals/lengths */
f3d89c
 
f3d89c
     uInt  lit_bufsize;
f3d89c
     /* Size of match buffer for literals/lengths.  There are 4 reasons for
f3d89c
@@ -239,13 +239,8 @@ typedef struct internal_state {
f3d89c
      *   - I can't count above 4
f3d89c
      */
f3d89c
 
f3d89c
-    uInt last_lit;      /* running index in l_buf */
f3d89c
-
f3d89c
-    ushf *d_buf;
f3d89c
-    /* Buffer for distances. To simplify the code, d_buf and l_buf have
f3d89c
-     * the same number of elements. To use different lengths, an extra flag
f3d89c
-     * array would be necessary.
f3d89c
-     */
f3d89c
+    uInt sym_next;      /* running index in sym_buf */
f3d89c
+    uInt sym_end;       /* symbol table full when sym_next reaches this */
f3d89c
 
f3d89c
     ulg opt_len;        /* bit length of current block with optimal trees */
f3d89c
     ulg static_len;     /* bit length of current block with static trees */
f3d89c
@@ -325,20 +320,22 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
f3d89c
 
f3d89c
 # define _tr_tally_lit(s, c, flush) \
f3d89c
   { uch cc = (c); \
f3d89c
-    s->d_buf[s->last_lit] = 0; \
f3d89c
-    s->l_buf[s->last_lit++] = cc; \
f3d89c
+    s->sym_buf[s->sym_next++] = 0; \
f3d89c
+    s->sym_buf[s->sym_next++] = 0; \
f3d89c
+    s->sym_buf[s->sym_next++] = cc; \
f3d89c
     s->dyn_ltree[cc].Freq++; \
f3d89c
-    flush = (s->last_lit == s->lit_bufsize-1); \
f3d89c
+    flush = (s->sym_next == s->sym_end); \
f3d89c
    }
f3d89c
 # define _tr_tally_dist(s, distance, length, flush) \
f3d89c
   { uch len = (uch)(length); \
f3d89c
     ush dist = (ush)(distance); \
f3d89c
-    s->d_buf[s->last_lit] = dist; \
f3d89c
-    s->l_buf[s->last_lit++] = len; \
f3d89c
+    s->sym_buf[s->sym_next++] = dist; \
f3d89c
+    s->sym_buf[s->sym_next++] = dist >> 8; \
f3d89c
+    s->sym_buf[s->sym_next++] = len; \
f3d89c
     dist--; \
f3d89c
     s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
f3d89c
     s->dyn_dtree[d_code(dist)].Freq++; \
f3d89c
-    flush = (s->last_lit == s->lit_bufsize-1); \
f3d89c
+    flush = (s->sym_next == s->sym_end); \
f3d89c
   }
f3d89c
 #else
f3d89c
 # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
f3d89c
diff --git a/trees.c b/trees.c
f3d89c
index 4f4a650..decaeb7 100644
f3d89c
--- a/trees.c
f3d89c
+++ b/trees.c
f3d89c
@@ -416,7 +416,7 @@ local void init_block(s)
f3d89c
 
f3d89c
     s->dyn_ltree[END_BLOCK].Freq = 1;
f3d89c
     s->opt_len = s->static_len = 0L;
f3d89c
-    s->last_lit = s->matches = 0;
f3d89c
+    s->sym_next = s->matches = 0;
f3d89c
 }
f3d89c
 
f3d89c
 #define SMALLEST 1
f3d89c
@@ -948,7 +948,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
f3d89c
 
f3d89c
         Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
f3d89c
                 opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
f3d89c
-                s->last_lit));
f3d89c
+                s->sym_next / 3));
f3d89c
 
f3d89c
         if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
f3d89c
 
f3d89c
@@ -1017,8 +1017,9 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
f3d89c
     unsigned dist;  /* distance of matched string */
f3d89c
     unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
f3d89c
 {
f3d89c
-    s->d_buf[s->last_lit] = (ush)dist;
f3d89c
-    s->l_buf[s->last_lit++] = (uch)lc;
f3d89c
+    s->sym_buf[s->sym_next++] = dist;
f3d89c
+    s->sym_buf[s->sym_next++] = dist >> 8;
f3d89c
+    s->sym_buf[s->sym_next++] = lc;
f3d89c
     if (dist == 0) {
f3d89c
         /* lc is the unmatched char */
f3d89c
         s->dyn_ltree[lc].Freq++;
f3d89c
@@ -1033,30 +1034,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
f3d89c
         s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
f3d89c
         s->dyn_dtree[d_code(dist)].Freq++;
f3d89c
     }
f3d89c
-
f3d89c
-#ifdef TRUNCATE_BLOCK
f3d89c
-    /* Try to guess if it is profitable to stop the current block here */
f3d89c
-    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
f3d89c
-        /* Compute an upper bound for the compressed length */
f3d89c
-        ulg out_length = (ulg)s->last_lit*8L;
f3d89c
-        ulg in_length = (ulg)((long)s->strstart - s->block_start);
f3d89c
-        int dcode;
f3d89c
-        for (dcode = 0; dcode < D_CODES; dcode++) {
f3d89c
-            out_length += (ulg)s->dyn_dtree[dcode].Freq *
f3d89c
-                (5L+extra_dbits[dcode]);
f3d89c
-        }
f3d89c
-        out_length >>= 3;
f3d89c
-        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
f3d89c
-               s->last_lit, in_length, out_length,
f3d89c
-               100L - out_length*100L/in_length));
f3d89c
-        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
f3d89c
-    }
f3d89c
-#endif
f3d89c
-    return (s->last_lit == s->lit_bufsize-1);
f3d89c
-    /* We avoid equality with lit_bufsize because of wraparound at 64K
f3d89c
-     * on 16 bit machines and because stored blocks are restricted to
f3d89c
-     * 64K-1 bytes.
f3d89c
-     */
f3d89c
+    return (s->sym_next == s->sym_end);
f3d89c
 }
f3d89c
 
f3d89c
 /* ===========================================================================
f3d89c
@@ -1069,13 +1047,14 @@ local void compress_block(s, ltree, dtree)
f3d89c
 {
f3d89c
     unsigned dist;      /* distance of matched string */
f3d89c
     int lc;             /* match length or unmatched char (if dist == 0) */
f3d89c
-    unsigned lx = 0;    /* running index in l_buf */
f3d89c
+    unsigned sx = 0;    /* running index in sym_buf */
f3d89c
     unsigned code;      /* the code to send */
f3d89c
     int extra;          /* number of extra bits to send */
f3d89c
 
f3d89c
-    if (s->last_lit != 0) do {
f3d89c
-        dist = s->d_buf[lx];
f3d89c
-        lc = s->l_buf[lx++];
f3d89c
+    if (s->sym_next != 0) do {
f3d89c
+        dist = s->sym_buf[sx++] & 0xff;
f3d89c
+        dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
f3d89c
+        lc = s->sym_buf[sx++];
f3d89c
         if (dist == 0) {
f3d89c
             send_code(s, lc, ltree); /* send a literal byte */
f3d89c
             Tracecv(isgraph(lc), (stderr," '%c' ", lc));
f3d89c
@@ -1100,11 +1079,10 @@ local void compress_block(s, ltree, dtree)
f3d89c
             }
f3d89c
         } /* literal or match pair ? */
f3d89c
 
f3d89c
-        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
f3d89c
-        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
f3d89c
-               "pendingBuf overflow");
f3d89c
+        /* Check that the overlay between pending_buf and sym_buf is ok: */
f3d89c
+        Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
f3d89c
 
f3d89c
-    } while (lx < s->last_lit);
f3d89c
+    } while (sx < s->sym_next);
f3d89c
 
f3d89c
     send_code(s, END_BLOCK, ltree);
f3d89c
 }
f3d89c
-- 
f3d89c
2.34.1
f3d89c