]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
Exercise ZSTD_findDecompressedSize() in the simple decompression fuzzer (#3959)
authorElliot Gorokhovsky <embg@fb.com>
Tue, 12 Mar 2024 21:07:06 +0000 (17:07 -0400)
committerGitHub <noreply@github.com>
Tue, 12 Mar 2024 21:07:06 +0000 (17:07 -0400)
* Improve decompression fuzzer

* Fix legacy frame header fuzzer crash, add unit test

lib/decompress/zstd_decompress.c
tests/fuzz/simple_decompress.c
tests/zstreamtest.c

index 173059085405c69c1b8e3f1f9db4e9110deba205..42636d5780ced6410f0623aba5851c426459ce0b 100644 (file)
@@ -1093,6 +1093,15 @@ size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
             decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
             if (ZSTD_isError(decodedSize)) return decodedSize;
 
+            {
+                unsigned long long const expectedSize = ZSTD_getFrameContentSize(src, srcSize);
+                RETURN_ERROR_IF(expectedSize == ZSTD_CONTENTSIZE_ERROR, corruption_detected, "Corrupted frame header!");
+                if (expectedSize != ZSTD_CONTENTSIZE_UNKNOWN) {
+                    RETURN_ERROR_IF(expectedSize != decodedSize, corruption_detected,
+                        "Frame header size does not match decoded size!");
+                }
+            }
+
             assert(decodedSize <= dstCapacity);
             dst = (BYTE*)dst + decodedSize;
             dstCapacity -= decodedSize;
index ce5f9f0981bee4930302c0414553a97613e03741..0ee61902cdb2dd230440034a7c25333a7743f57a 100644 (file)
@@ -37,7 +37,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
     size_t const bufSize = FUZZ_dataProducer_uint32Range(producer, 0, 10 * size);
     void *rBuf = FUZZ_malloc(bufSize);
 
-    ZSTD_decompressDCtx(dctx, rBuf, bufSize, src, size);
+    size_t const dSize = ZSTD_decompressDCtx(dctx, rBuf, bufSize, src, size);
+    if (!ZSTD_isError(dSize)) {
+        /* If decompression was successful, the content size from the frame header(s) should be valid. */
+        size_t const expectedSize = ZSTD_findDecompressedSize(src, size);
+        FUZZ_ASSERT(expectedSize != ZSTD_CONTENTSIZE_ERROR);
+        FUZZ_ASSERT(expectedSize == ZSTD_CONTENTSIZE_UNKNOWN || expectedSize == dSize);
+    }
     free(rBuf);
 
     FUZZ_dataProducer_free(producer);
index 82aaf3db50c6eaf940cc1eaeba41c0375bc98b82..7cc4068bc094661d1ff8cb3e87b19b7dbfbae980 100644 (file)
@@ -2408,6 +2408,15 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests)
     }
     DISPLAYLEVEL(3, "OK \n");
 
+    DISPLAYLEVEL(3, "test%3i : Decoder should reject invalid frame header on legacy frames: ", testNb++);
+    {
+        const unsigned char compressed[] = { 0x26,0xb5,0x2f,0xfd,0x50,0x91,0xfd,0xd8,0xb5 };
+        const size_t compressedSize = 9;
+        size_t const dSize = ZSTD_decompress(NULL, 0, compressed, compressedSize);
+        CHECK(!ZSTD_isError(dSize), "must reject when legacy frame header is invalid");
+    }
+    DISPLAYLEVEL(3, "OK \n");
+
 _end:
     FUZ_freeDictionary(dictionary);
     ZSTD_freeCStream(zc);