aboutsummaryrefslogtreecommitdiff
path: root/ossfuzz
diff options
context:
space:
mode:
Diffstat (limited to 'ossfuzz')
-rw-r--r--ossfuzz/.gitignore8
-rw-r--r--ossfuzz/Makefile1
-rw-r--r--ossfuzz/decompress_fuzzer.c20
-rw-r--r--ossfuzz/fuzz_helpers.h5
-rw-r--r--ossfuzz/round_trip_frame_uncompressed_fuzzer.c134
-rw-r--r--ossfuzz/round_trip_fuzzer.c72
6 files changed, 230 insertions, 10 deletions
diff --git a/ossfuzz/.gitignore b/ossfuzz/.gitignore
new file mode 100644
index 00000000..0ef0d2b6
--- /dev/null
+++ b/ossfuzz/.gitignore
@@ -0,0 +1,8 @@
+
+# build artefacts
+round_trip_frame_uncompressed_fuzzer
+
+# test artefacts
+
+# local tests
+
diff --git a/ossfuzz/Makefile b/ossfuzz/Makefile
index 2ec16755..deb2938a 100644
--- a/ossfuzz/Makefile
+++ b/ossfuzz/Makefile
@@ -45,6 +45,7 @@ FUZZERS := \
round_trip_hc_fuzzer \
compress_frame_fuzzer \
round_trip_frame_fuzzer \
+ round_trip_frame_uncompressed_fuzzer \
decompress_frame_fuzzer
.PHONY: all
diff --git a/ossfuzz/decompress_fuzzer.c b/ossfuzz/decompress_fuzzer.c
index 6f48e30e..490b3fd6 100644
--- a/ossfuzz/decompress_fuzzer.c
+++ b/ossfuzz/decompress_fuzzer.c
@@ -39,7 +39,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
/* No dictionary. */
LZ4_decompress_safe_usingDict((char const*)data, dst, size,
dstCapacity, NULL, 0);
- /* Small external dictonary. */
+ /* Small external dictionary. */
LZ4_decompress_safe_usingDict((char const*)data, dst, size,
dstCapacity, smallDict, smallDictSize);
/* Large external dictionary. */
@@ -49,11 +49,27 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
LZ4_decompress_safe_usingDict((char const*)dataAfterDict, dst, size,
dstCapacity, smallDict, smallDictSize);
/* Large prefix. */
- LZ4_decompress_safe_usingDict((char const*)data, dst, size,
+ LZ4_decompress_safe_usingDict((char const*)dataAfterDict, dst, size,
dstCapacity, largeDict, largeDictSize);
/* Partial decompression. */
LZ4_decompress_safe_partial((char const*)data, dst, size,
dstCapacity, dstCapacity);
+ /* Partial decompression using each possible dictionary configuration. */
+ /* Partial decompression with no dictionary. */
+ LZ4_decompress_safe_partial_usingDict((char const*)data, dst, size,
+ dstCapacity, dstCapacity, NULL, 0);
+ /* Partial decompression with small external dictionary. */
+ LZ4_decompress_safe_partial_usingDict((char const*)data, dst, size,
+ dstCapacity, dstCapacity, smallDict, smallDictSize);
+ /* Partial decompression with large external dictionary. */
+ LZ4_decompress_safe_partial_usingDict((char const*)data, dst, size,
+ dstCapacity, dstCapacity, largeDict, largeDictSize);
+ /* Partial decompression with small prefix. */
+ LZ4_decompress_safe_partial_usingDict((char const*)dataAfterDict, dst, size,
+ dstCapacity, dstCapacity, smallDict, smallDictSize);
+ /* Partial decompression wtih large prefix. */
+ LZ4_decompress_safe_partial_usingDict((char const*)dataAfterDict, dst, size,
+ dstCapacity, dstCapacity, largeDict, largeDictSize);
free(dst);
free(dict);
FUZZ_dataProducer_free(producer);
diff --git a/ossfuzz/fuzz_helpers.h b/ossfuzz/fuzz_helpers.h
index c4a8645c..efd9acfe 100644
--- a/ossfuzz/fuzz_helpers.h
+++ b/ossfuzz/fuzz_helpers.h
@@ -4,7 +4,8 @@
*
* This source code is licensed under both the BSD-style license (found in the
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
- * in the COPYING file in the root directory of this source tree).
+ * in the COPYING file in the root directory of this source tree),
+ * meaning you may select, at your option, one of the above-listed licenses.
*/
/**
@@ -81,7 +82,7 @@ FUZZ_STATIC uint32_t FUZZ_rand(uint32_t *state) {
return rand32 >> 5;
}
-/* Returns a random numer in the range [min, max]. */
+/* Returns a random number in the range [min, max]. */
FUZZ_STATIC uint32_t FUZZ_rand32(uint32_t *state, uint32_t min, uint32_t max) {
uint32_t random = FUZZ_rand(state);
return min + (random % (max - min + 1));
diff --git a/ossfuzz/round_trip_frame_uncompressed_fuzzer.c b/ossfuzz/round_trip_frame_uncompressed_fuzzer.c
new file mode 100644
index 00000000..76a99d22
--- /dev/null
+++ b/ossfuzz/round_trip_frame_uncompressed_fuzzer.c
@@ -0,0 +1,134 @@
+/**
+ * This fuzz target performs a lz4 round-trip test (compress & decompress),
+ * compares the result with the original, and calls abort() on corruption.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fuzz_data_producer.h"
+#include "fuzz_helpers.h"
+#include "lz4.h"
+#include "lz4_helpers.h"
+#include "lz4frame.h"
+#include "lz4frame_static.h"
+
+static void decompress(LZ4F_dctx *dctx, void *src, void *dst,
+ size_t dstCapacity, size_t readSize) {
+ size_t ret = 1;
+ const void *srcPtr = (const char *) src;
+ void *dstPtr = (char *) dst;
+ const void *const srcEnd = (const char *) srcPtr + readSize;
+
+ while (ret != 0) {
+ while (srcPtr < srcEnd && ret != 0) {
+ /* Any data within dst has been flushed at this stage */
+ size_t dstSize = dstCapacity;
+ size_t srcSize = (const char *) srcEnd - (const char *) srcPtr;
+ ret = LZ4F_decompress(dctx, dstPtr, &dstSize, srcPtr, &srcSize,
+ /* LZ4F_decompressOptions_t */ NULL);
+ FUZZ_ASSERT(!LZ4F_isError(ret));
+
+ /* Update input */
+ srcPtr = (const char *) srcPtr + srcSize;
+ dstPtr = (char *) dstPtr + dstSize;
+ }
+
+ FUZZ_ASSERT(srcPtr <= srcEnd);
+ }
+}
+
+static void compress_round_trip(const uint8_t *data, size_t size,
+ FUZZ_dataProducer_t *producer, LZ4F_preferences_t const prefs) {
+
+ // Choose random uncompressed offset start and end by producing seeds from random data, calculate the remaining
+ // data size that will be used for compression later and use the seeds to actually calculate the offsets
+ size_t const uncompressedOffsetSeed = FUZZ_dataProducer_retrieve32(producer);
+ size_t const uncompressedEndOffsetSeed = FUZZ_dataProducer_retrieve32(producer);
+ size = FUZZ_dataProducer_remainingBytes(producer);
+
+ size_t const uncompressedOffset = FUZZ_getRange_from_uint32(uncompressedOffsetSeed, 0, size);
+ size_t const uncompressedEndOffset = FUZZ_getRange_from_uint32(uncompressedEndOffsetSeed, uncompressedOffset, size);
+ size_t const uncompressedSize = uncompressedEndOffset - uncompressedOffset;
+ FUZZ_ASSERT(uncompressedOffset <= uncompressedEndOffset);
+ FUZZ_ASSERT(uncompressedEndOffset <= size);
+
+ const uint8_t *const uncompressedData = data + uncompressedOffset;
+
+ size_t const dstCapacity =
+ LZ4F_compressFrameBound(LZ4_compressBound(size), &prefs) +
+ uncompressedSize;
+ char *const dst = (char *) malloc(dstCapacity);
+ size_t rtCapacity = dstCapacity;
+ char *const rt = (char *) malloc(rtCapacity);
+
+ FUZZ_ASSERT(dst);
+ FUZZ_ASSERT(rt);
+
+ /* Compression must succeed and round trip correctly. */
+ LZ4F_compressionContext_t ctx;
+ size_t const ctxCreation = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
+ FUZZ_ASSERT(!LZ4F_isError(ctxCreation));
+
+ size_t const headerSize = LZ4F_compressBegin(ctx, dst, dstCapacity, &prefs);
+ FUZZ_ASSERT(!LZ4F_isError(headerSize));
+ size_t compressedSize = headerSize;
+
+ /* Compress data before uncompressed offset */
+ size_t lz4Return = LZ4F_compressUpdate(ctx, dst + compressedSize, dstCapacity,
+ data, uncompressedOffset, NULL);
+ FUZZ_ASSERT(!LZ4F_isError(lz4Return));
+ compressedSize += lz4Return;
+
+ /* Add uncompressed data */
+ lz4Return = LZ4F_uncompressedUpdate(ctx, dst + compressedSize, dstCapacity,
+ uncompressedData, uncompressedSize, NULL);
+ FUZZ_ASSERT(!LZ4F_isError(lz4Return));
+ compressedSize += lz4Return;
+
+ /* Compress data after uncompressed offset */
+ lz4Return = LZ4F_compressUpdate(ctx, dst + compressedSize, dstCapacity,
+ data + uncompressedEndOffset,
+ size - uncompressedEndOffset, NULL);
+ FUZZ_ASSERT(!LZ4F_isError(lz4Return));
+ compressedSize += lz4Return;
+
+ /* Finish compression */
+ lz4Return = LZ4F_compressEnd(ctx, dst + compressedSize, dstCapacity, NULL);
+ FUZZ_ASSERT(!LZ4F_isError(lz4Return));
+ compressedSize += lz4Return;
+
+ LZ4F_decompressOptions_t opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.stableDst = 1;
+ LZ4F_dctx *dctx;
+ LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
+ FUZZ_ASSERT(dctx);
+
+ decompress(dctx, dst, rt, rtCapacity, compressedSize);
+
+ LZ4F_freeDecompressionContext(dctx);
+
+ FUZZ_ASSERT_MSG(!memcmp(data, rt, size), "Corruption!");
+
+ free(dst);
+ free(rt);
+
+ FUZZ_dataProducer_free(producer);
+ LZ4F_freeCompressionContext(ctx);
+}
+
+static void compress_independent_block_mode(const uint8_t *data, size_t size) {
+ FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size);
+ LZ4F_preferences_t prefs = FUZZ_dataProducer_preferences(producer);
+ prefs.frameInfo.blockMode = LZ4F_blockIndependent;
+ compress_round_trip(data, size, producer, prefs);
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ compress_independent_block_mode(data, size);
+ return 0;
+}
diff --git a/ossfuzz/round_trip_fuzzer.c b/ossfuzz/round_trip_fuzzer.c
index 6307058f..62362013 100644
--- a/ossfuzz/round_trip_fuzzer.c
+++ b/ossfuzz/round_trip_fuzzer.c
@@ -20,11 +20,16 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
size_t const partialCapacity = FUZZ_getRange_from_uint32(partialCapacitySeed, 0, size);
size_t const dstCapacity = LZ4_compressBound(size);
-
- char* const dst = (char*)malloc(dstCapacity);
+ size_t const largeSize = 64 * 1024 - 1;
+ size_t const smallSize = 1024;
+ char* const dstPlusLargePrefix = (char*)malloc(dstCapacity + largeSize);
+ FUZZ_ASSERT(dstPlusLargePrefix);
+ char* const dstPlusSmallPrefix = dstPlusLargePrefix + largeSize - smallSize;
+ char* const largeDict = (char*)malloc(largeSize);
+ FUZZ_ASSERT(largeDict);
+ char* const smallDict = largeDict + largeSize - smallSize;
+ char* const dst = dstPlusLargePrefix + largeSize;
char* const rt = (char*)malloc(size);
-
- FUZZ_ASSERT(dst);
FUZZ_ASSERT(rt);
/* Compression must succeed and round trip correctly. */
@@ -47,9 +52,64 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
free(partial);
}
+ /* Partial decompression using dict with no dict. */
+ {
+ char* const partial = (char*)malloc(partialCapacity);
+ FUZZ_ASSERT(partial);
+ int const partialSize = LZ4_decompress_safe_partial_usingDict(
+ dst, partial, dstSize, partialCapacity, partialCapacity, NULL, 0);
+ FUZZ_ASSERT(partialSize >= 0);
+ FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
+ FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
+ free(partial);
+ }
+ /* Partial decompression using dict with small prefix as dict */
+ {
+ char* const partial = (char*)malloc(partialCapacity);
+ FUZZ_ASSERT(partial);
+ int const partialSize = LZ4_decompress_safe_partial_usingDict(
+ dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusSmallPrefix, smallSize);
+ FUZZ_ASSERT(partialSize >= 0);
+ FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
+ FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
+ free(partial);
+ }
+ /* Partial decompression using dict with large prefix as dict */
+ {
+ char* const partial = (char*)malloc(partialCapacity);
+ FUZZ_ASSERT(partial);
+ int const partialSize = LZ4_decompress_safe_partial_usingDict(
+ dst, partial, dstSize, partialCapacity, partialCapacity, dstPlusLargePrefix, largeSize);
+ FUZZ_ASSERT(partialSize >= 0);
+ FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
+ FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
+ free(partial);
+ }
+ /* Partial decompression using dict with small external dict */
+ {
+ char* const partial = (char*)malloc(partialCapacity);
+ FUZZ_ASSERT(partial);
+ int const partialSize = LZ4_decompress_safe_partial_usingDict(
+ dst, partial, dstSize, partialCapacity, partialCapacity, smallDict, smallSize);
+ FUZZ_ASSERT(partialSize >= 0);
+ FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
+ FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
+ free(partial);
+ }
+ /* Partial decompression using dict with large external dict */
+ {
+ char* const partial = (char*)malloc(partialCapacity);
+ FUZZ_ASSERT(partial);
+ int const partialSize = LZ4_decompress_safe_partial_usingDict(
+ dst, partial, dstSize, partialCapacity, partialCapacity, largeDict, largeSize);
+ FUZZ_ASSERT(partialSize >= 0);
+ FUZZ_ASSERT_MSG(partialSize == partialCapacity, "Incorrect size");
+ FUZZ_ASSERT_MSG(!memcmp(data, partial, partialSize), "Corruption!");
+ free(partial);
+ }
-
- free(dst);
+ free(dstPlusLargePrefix);
+ free(largeDict);
free(rt);
FUZZ_dataProducer_free(producer);