From 5b0c8f0a7c0db3c449451eeded7cb86562e42000 Mon Sep 17 00:00:00 2001 From: senhuang42 Date: Wed, 18 Nov 2020 10:25:48 -0500 Subject: [PATCH] Add appropriate bound to matchlengths, and reduce srcSize max --- tests/fuzz/sequence_compression_api.c | 29 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/tests/fuzz/sequence_compression_api.c b/tests/fuzz/sequence_compression_api.c index 97667ef5..bc34b391 100644 --- a/tests/fuzz/sequence_compression_api.c +++ b/tests/fuzz/sequence_compression_api.c @@ -9,8 +9,10 @@ */ /** - * This fuzz target performs a zstd round-trip test (compress & decompress), - * compares the result with the original, and calls abort() on corruption. + * This fuzz target performs a zstd round-trip test by generating an arbitrary + * array of sequences, generating the associated source buffer, calling + * ZSTD_compressSequences(), and then decompresses and compares the result with + * the original generated source buffer. */ #define ZSTD_STATIC_LINKING_ONLY @@ -30,12 +32,13 @@ static void* literalsBuffer = NULL; static void* generatedSrc = NULL; static ZSTD_Sequence* generatedSequences = NULL; -#define ZSTD_FUZZ_GENERATED_SRC_MAXSIZE (1 << 25) /* Allow up to 32MB generated data */ +#define ZSTD_FUZZ_GENERATED_SRC_MAXSIZE (1 << 20) /* Allow up to 1MB generated data */ #define ZSTD_FUZZ_MATCHLENGTH_MAXSIZE (1 << 18) /* Allow up to 256KB matches */ #define ZSTD_FUZZ_GENERATED_DICT_MAXSIZE (1 << 18) /* Allow up to a 256KB dict */ #define ZSTD_FUZZ_GENERATED_LITERALS_SIZE (1 << 18) /* Fixed size 256KB literals buffer */ #define ZSTD_FUZZ_MAX_NBSEQ (1 << 17) /* Maximum of 128K sequences */ +/* Deterministic random number generator */ #define FUZZ_RDG_rotl32(x,r) ((x << r) | (x >> (32 - r))) static uint32_t FUZZ_RDG_rand(uint32_t* src) { @@ -50,7 +53,7 @@ static uint32_t FUZZ_RDG_rand(uint32_t* src) } /* Make a pseudorandom string - this simple function exists to avoid - * taking a dependency on datagen.h to have RDG_genBuffer(). We don't need anything fancy. + * taking a dependency on datagen.h to have RDG_genBuffer(). */ static char *generatePseudoRandomString(char *str, size_t size) { const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK1234567890!@#$^&*()_"; @@ -124,7 +127,7 @@ static size_t decodeSequences(void* dst, size_t nbSequences, return generatedSrcBufferSize; } -/* Returns nb sequences generated +/* Returns nb sequences generated * TODO: Add repcode fuzzing once we support repcode match splits */ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer, @@ -141,7 +144,7 @@ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer, uint32_t isFirstSequence = 1; uint32_t windowSize = 1 << windowLog; - while (nbSeqGenerated < ZSTD_FUZZ_MAX_NBSEQ + while (nbSeqGenerated < ZSTD_FUZZ_MAX_NBSEQ && bytesGenerated < ZSTD_FUZZ_GENERATED_SRC_MAXSIZE && !FUZZ_dataProducer_empty(producer)) { matchBound = ZSTD_FUZZ_MATCHLENGTH_MAXSIZE; @@ -154,9 +157,14 @@ static size_t generateRandomSequences(FUZZ_dataProducer_t* producer, offsetBound = bytesGenerated > windowSize ? windowSize : bytesGenerated + dictSize; offset = FUZZ_dataProducer_uint32Range(producer, 1, offsetBound); if (dictSize > 0 && bytesGenerated <= windowSize) { - uint32_t bytesToReachWindowSize = windowSize - bytesGenerated; + /* Prevent match length from being such that it would be associated with an offset too large + * from the decoder's perspective. If not possible (match would be too small), + * then reduce the offset if necessary. + */ + size_t bytesToReachWindowSize = windowSize - bytesGenerated; if (bytesToReachWindowSize < ZSTD_MINMATCH_MIN) { - offset = FUZZ_dataProducer_uint32Range(producer, 1, windowSize); + uint32_t newOffsetBound = offsetBound > windowSize ? windowSize : offsetBound; + offset = FUZZ_dataProducer_uint32Range(producer, 1, newOffsetBound); } else { matchBound = bytesToReachWindowSize > ZSTD_FUZZ_MATCHLENGTH_MAXSIZE ? ZSTD_FUZZ_MATCHLENGTH_MAXSIZE : bytesToReachWindowSize; @@ -241,8 +249,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) dictBuffer = generatePseudoRandomString(dictBuffer, dictSize); } /* Generate window log first so we dont generate offsets too large */ - wLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); - cLevel = FUZZ_dataProducer_int32Range(producer, (int)ZSTD_minCLevel, (int)ZSTD_maxCLevel); + wLog = FUZZ_dataProducer_uint32Range(producer, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX_32); + cLevel = FUZZ_dataProducer_int32Range(producer, -3, 22); if (!generatedSequences) { generatedSequences = FUZZ_malloc(sizeof(ZSTD_Sequence)*ZSTD_FUZZ_MAX_NBSEQ); @@ -252,7 +260,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) } nbSequences = generateRandomSequences(producer, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, dictSize, wLog); generatedSrcSize = decodeSequences(generatedSrc, nbSequences, ZSTD_FUZZ_GENERATED_LITERALS_SIZE, dictBuffer, dictSize); - cBufSize = ZSTD_compressBound(generatedSrcSize); cBuf = FUZZ_malloc(cBufSize);