]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
[fuzz] Allow zero sized buffers for streaming fuzzers (#1945)
authorNick Terrell <terrelln@fb.com>
Thu, 9 Jan 2020 19:38:50 +0000 (11:38 -0800)
committerGitHub <noreply@github.com>
Thu, 9 Jan 2020 19:38:50 +0000 (11:38 -0800)
* Allow zero sized buffers in `stream_decompress`. Ensure that we never have two
  zero sized buffers in a row so we guarantee forwards progress.
* Make case 4 in `stream_round_trip` do a zero sized buffers call followed by
  a full call to guarantee forwards progress.
* Fix `limitCopy()` in legacy decoders.
* Fix memcpy in `zstdmt_compress.c`.

Catches the bug fixed in PR #1939

lib/compress/zstdmt_compress.c
lib/legacy/zstd_v04.c
lib/legacy/zstd_v05.c
lib/legacy/zstd_v06.c
lib/legacy/zstd_v07.c
tests/fuzz/stream_decompress.c
tests/fuzz/stream_round_trip.c

index d054256297666252eacc1a723c65735435c7fd98..4eaa3fcddea5b55da0354d033d8b99ccd9907c2d 100644 (file)
@@ -1714,9 +1714,11 @@ static size_t ZSTDMT_flushProduced(ZSTDMT_CCtx* mtctx, ZSTD_outBuffer* output, u
             assert(mtctx->doneJobID < mtctx->nextJobID);
             assert(cSize >= mtctx->jobs[wJobID].dstFlushed);
             assert(mtctx->jobs[wJobID].dstBuff.start != NULL);
-            memcpy((char*)output->dst + output->pos,
-                   (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
-                   toFlush);
+            if (toFlush > 0) {
+                memcpy((char*)output->dst + output->pos,
+                    (const char*)mtctx->jobs[wJobID].dstBuff.start + mtctx->jobs[wJobID].dstFlushed,
+                    toFlush);
+            }
             output->pos += toFlush;
             mtctx->jobs[wJobID].dstFlushed += toFlush;  /* can write : this value is only used by mtctx */
 
index 4dec308168efbcf6ac5a63055b545bc6dc71ea0e..0150c9fb4828c20d6af2f6c6875a6c728284fb26 100644 (file)
@@ -3407,7 +3407,9 @@ static size_t ZBUFF_decompressWithDictionary(ZBUFF_DCtx* zbc, const void* src, s
 static size_t ZBUFF_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
 {
     size_t length = MIN(maxDstSize, srcSize);
-    memcpy(dst, src, length);
+    if (length > 0) {
+        memcpy(dst, src, length);
+    }
     return length;
 }
 
index 570e0ff86ee8cb4174cd0ec9d203a244efa549e9..aa564b415b9474601a3cbb614df58fbeb219cdb2 100644 (file)
@@ -3791,7 +3791,9 @@ static size_t ZBUFFv05_blockHeaderSize = 3;
 static size_t ZBUFFv05_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize)
 {
     size_t length = MIN(maxDstSize, srcSize);
-    memcpy(dst, src, length);
+    if (length > 0) {
+        memcpy(dst, src, length);
+    }
     return length;
 }
 
index 2a08e8dee8421e250161e49290144a6d01c726f5..d5d778fce14f19bcddcb69f2c24753a05c797fe5 100644 (file)
@@ -4000,7 +4000,9 @@ size_t ZBUFFv06_decompressInit(ZBUFFv06_DCtx* zbd)
 MEM_STATIC size_t ZBUFFv06_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
 {
     size_t length = MIN(dstCapacity, srcSize);
-    memcpy(dst, src, length);
+    if (length > 0) {
+        memcpy(dst, src, length);
+    }
     return length;
 }
 
index a2eeff808e0e3df7cbc503e721901353ccb7fe2d..14a93655e1958ff1aad0482fc60c82b3b1c3d1f1 100644 (file)
@@ -4378,7 +4378,9 @@ size_t ZBUFFv07_decompressInit(ZBUFFv07_DCtx* zbd)
 MEM_STATIC size_t ZBUFFv07_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
 {
     size_t const length = MIN(dstCapacity, srcSize);
-    memcpy(dst, src, length);
+    if (length > 0) {
+        memcpy(dst, src, length);
+    }
     return length;
 }
 
index c71cc9d3ec6f728e802c67c178906f0bd707032b..aff9fcec78514124c990ea523c58db27980b0624 100644 (file)
@@ -27,27 +27,36 @@ static ZSTD_DStream *dstream = NULL;
 static void* buf = NULL;
 uint32_t seed;
 
-static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer)
+static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer, uint32_t min)
 {
   ZSTD_outBuffer buffer = { buf, 0, 0 };
 
-  buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, kBufSize));
+  buffer.size = (FUZZ_dataProducer_uint32Range(producer, min, kBufSize));
   FUZZ_ASSERT(buffer.size <= kBufSize);
 
+  if (buffer.size == 0) {
+    buffer.dst = NULL;
+  }
+
   return buffer;
 }
 
 static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size,
-                                  FUZZ_dataProducer_t *producer)
+                                  FUZZ_dataProducer_t *producer,
+                                  uint32_t min)
 {
   ZSTD_inBuffer buffer = { *src, 0, 0 };
 
   FUZZ_ASSERT(*size > 0);
-  buffer.size = (FUZZ_dataProducer_uint32Range(producer, 1, *size));
+  buffer.size = (FUZZ_dataProducer_uint32Range(producer, min, *size));
   FUZZ_ASSERT(buffer.size <= *size);
   *src += buffer.size;
   *size -= buffer.size;
 
+  if (buffer.size == 0) {
+    buffer.src = NULL;
+  }
+
   return buffer;
 }
 
@@ -56,6 +65,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
     /* Give a random portion of src data to the producer, to use for
     parameter generation. The rest will be used for (de)compression */
     FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
+    /* Guarantee forward progress by refusing to generate 2 zero sized
+     * buffers in a row. */
+    int prevInWasZero = 0;
+    int prevOutWasZero = 0;
     size = FUZZ_dataProducer_reserveDataPrefix(producer);
 
     /* Allocate all buffers and contexts if not already allocated */
@@ -72,9 +85,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
     }
 
     while (size > 0) {
-        ZSTD_inBuffer in = makeInBuffer(&src, &size, producer);
+        ZSTD_inBuffer in = makeInBuffer(&src, &size, producer, prevInWasZero ? 1 : 0);
+        prevInWasZero = in.size == 0;
         while (in.pos != in.size) {
-            ZSTD_outBuffer out = makeOutBuffer(producer);
+            ZSTD_outBuffer out = makeOutBuffer(producer, prevOutWasZero ? 1 : 0);
+            prevOutWasZero = out.size == 0;
             size_t const rc = ZSTD_decompressStream(dstream, &out, &in);
             if (ZSTD_isError(rc)) goto error;
         }
index 703b11713364baf036b4daff48e9a8285daf21fe..810ed05eb9f91cfdcf7778bfbb342ae9ff1aeb45 100644 (file)
@@ -96,6 +96,13 @@ static size_t compress(uint8_t *dst, size_t capacity,
                     }
                     break;
                 }
+                case 4: {
+                    ZSTD_inBuffer nullIn = { NULL, 0, 0 };
+                    ZSTD_outBuffer nullOut = { NULL, 0, 0 };
+                    size_t const ret = ZSTD_compressStream2(cctx, &nullOut, &nullIn, ZSTD_e_continue);
+                    FUZZ_ZASSERT(ret);
+                }
+                /* fall-through */
                 default: {
                     size_t const ret =
                         ZSTD_compressStream2(cctx, &out, &in, ZSTD_e_continue);