]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Don't bother computing check value after successful inflateSync().
authorMark Adler <madler@alumni.caltech.edu>
Thu, 3 Jan 2019 02:10:40 +0000 (18:10 -0800)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Tue, 22 Oct 2019 07:57:38 +0000 (09:57 +0200)
inflateSync() is used to skip invalid deflate data, which means
that the check value that was being computed is no longer useful.
This commit turns off the check value computation, and furthermore
allows a successful return if the compressed data terminated in a
graceful manner. This commit also fixes a bug in the case that
inflateSync() is used before a header is ever processed. In that
case, there is no knowledge of a trailer, so the remainder is
treated as raw.

inflate.c
inflate.h
test/example.c
test/fuzz/example_flush_fuzzer.c

index 0b17e318d19b3fa10cc50a51082166508f7dd7fd..2ba094798f8e78d1664d52b3db5cc918edeaee45 100644 (file)
--- a/inflate.c
+++ b/inflate.c
@@ -67,6 +67,7 @@ int ZEXPORT PREFIX(inflateResetKeep)(PREFIX3(stream) *strm) {
     state->check = functable.adler32(0L, NULL, 0);
     state->last = 0;
     state->havedict = 0;
+    state->flags = -1;
     state->dmax = 32768U;
     state->head = NULL;
     state->hold = 0;
@@ -420,7 +421,6 @@ int ZEXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int flush) {
                 state->mode = FLAGS;
                 break;
             }
-            state->flags = 0;           /* expect zlib header */
             if (state->head != NULL)
                 state->head->done = -1;
             if (!(state->wrap & 1) ||   /* check if zlib header allowed */
@@ -447,6 +447,7 @@ int ZEXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int flush) {
                 break;
             }
             state->dmax = 1U << len;
+            state->flags = 0;               /* indicate zlib header */
             Tracev((stderr, "inflate:   zlib header ok\n"));
             strm->adler = state->check = functable.adler32(0L, NULL, 0);
             state->mode = hold & 0x200 ? DICTID : TYPE;
@@ -1039,7 +1040,7 @@ int ZEXPORT PREFIX(inflate)(PREFIX3(stream) *strm, int flush) {
         case LENGTH:
             if (state->wrap && state->flags) {
                 NEEDBITS(32);
-                if (hold != (state->total & 0xffffffffUL)) {
+                if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
                     strm->msg = (char *)"incorrect length check";
                     state->mode = BAD;
                     break;
@@ -1209,6 +1210,7 @@ static uint32_t syncsearch(uint32_t *have, const unsigned char *buf, uint32_t le
 
 int ZEXPORT PREFIX(inflateSync)(PREFIX3(stream) *strm) {
     unsigned len;               /* number of bytes to look at or looked at */
+    int flags;                  /* temporary to save header status */
     size_t in, out;             /* temporary to save total_in and total_out */
     unsigned char buf[4];       /* to restore bit buffer to byte string */
     struct inflate_state *state;
@@ -1244,13 +1246,17 @@ int ZEXPORT PREFIX(inflateSync)(PREFIX3(stream) *strm) {
     /* return no joy or set up to restart inflate() on a new block */
     if (state->have != 4)
         return Z_DATA_ERROR;
-    if (state->mode == HEAD)
-        state->wrap = 0;    /* never processed header, so assume raw */
+    if (state->flags == -1)
+        state->wrap = 0;    /* if no header yet, treat as raw */
+    else
+        state->wrap &= ~4;  /* no point in computing a check value now */
+    flags = state->flags;
     in = strm->total_in;
     out = strm->total_out;
     PREFIX(inflateReset)(strm);
     strm->total_in = in;
     strm->total_out = out;
+    state->flags = flags;
     state->mode = TYPE;
     return Z_OK;
 }
index 846fcdcf32af9fcaad289286a3c7c4896c3a0e94..384459ab2493a592f66ca4557c4036afac954809 100644 (file)
--- a/inflate.h
+++ b/inflate.h
@@ -89,7 +89,8 @@ struct inflate_state {
     int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip,
                                    bit 2 true to validate check value */
     int havedict;               /* true if dictionary provided */
-    int flags;                  /* gzip header method and flags (0 if zlib) */
+    int flags;                  /* gzip header method and flags, 0 if zlib, or
+                                   -1 if raw or no header yet */
     unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
     unsigned long check;        /* protected copy of check value */
     unsigned long total;        /* protected copy of output count */
index cb9e87a3908c741c3c24172e3de9157dad4e1ec6..8309178e0d009eeab8cacdb2e5e665397a790594 100644 (file)
@@ -451,9 +451,8 @@ void test_sync(unsigned char *compr, size_t comprLen, unsigned char *uncompr, si
     CHECK_ERR(err, "inflateSync");
 
     err = PREFIX(inflate)(&d_stream, Z_FINISH);
-    if (err != Z_DATA_ERROR) {
-        fprintf(stderr, "inflate should report DATA_ERROR\n");
-        /* Because of incorrect adler32 */
+    if (err != Z_STREAM_END) {
+        fprintf(stderr, "inflate should report Z_STREAM_END\n");
         exit(1);
     }
     err = PREFIX(inflateEnd)(&d_stream);
index e53ceeca33192182aa40792e8f97370ce5ae48be..bb9f47956e18ad7d5def521a955688d1a7f3fd9e 100644 (file)
@@ -88,9 +88,8 @@ void test_sync(unsigned char *compr, size_t comprLen, unsigned char *uncompr, si
     CHECK_ERR(err, "inflateSync");
 
     err = PREFIX(inflate)(&d_stream, Z_FINISH);
-    if (err != Z_DATA_ERROR) {
-        fprintf(stderr, "inflate should report DATA_ERROR\n");
-        /* Because of incorrect adler32 */
+    if (err != Z_STREAM_END) {
+        fprintf(stderr, "inflate should report Z_STREAM_END\n");
         exit(1);
     }
     err = PREFIX(inflateEnd)(&d_stream);