summaryrefslogtreecommitdiffstats
path: root/tests/ossfuzz
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ossfuzz')
-rw-r--r--tests/ossfuzz/Makefile18
-rw-r--r--tests/ossfuzz/config/fuzz.dict2
-rw-r--r--tests/ossfuzz/config/fuzz.options2
-rw-r--r--tests/ossfuzz/config/fuzz_decode_alone.options5
-rw-r--r--tests/ossfuzz/config/fuzz_decode_stream.options4
-rw-r--r--tests/ossfuzz/config/fuzz_encode_stream.options4
-rw-r--r--tests/ossfuzz/config/fuzz_lzma.dict22
-rw-r--r--tests/ossfuzz/config/fuzz_xz.dict4
-rw-r--r--tests/ossfuzz/fuzz.c82
-rw-r--r--tests/ossfuzz/fuzz_common.h55
-rw-r--r--tests/ossfuzz/fuzz_decode_alone.c41
-rw-r--r--tests/ossfuzz/fuzz_decode_stream.c53
-rw-r--r--tests/ossfuzz/fuzz_encode_stream.c86
13 files changed, 288 insertions, 90 deletions
diff --git a/tests/ossfuzz/Makefile b/tests/ossfuzz/Makefile
index 747fb66..742e063 100644
--- a/tests/ossfuzz/Makefile
+++ b/tests/ossfuzz/Makefile
@@ -1,7 +1,17 @@
-fuzz: fuzz.c
- $(CC) $(CFLAGS) -c fuzz.c -I ../../src/liblzma/api/
- $(CXX) $(CXXFLAGS) $(LIB_FUZZING_ENGINE) fuzz.o -o $(OUT)/fuzz \
- ../../src/liblzma/.libs/liblzma.a
+# SPDX-License-Identifier: 0BSD
+FUZZ_TARGET_SRCS = $(wildcard *.c)
+FUZZ_TARGET_BINS = $(FUZZ_TARGET_SRCS:.c=)
+
+all: $(FUZZ_TARGET_BINS)
+
+%: %.c
+ $(CC) $(CFLAGS) -c $< -I ../../src/liblzma/api/ ;
+ $(CXX) $(CXXFLAGS) $(LIB_FUZZING_ENGINE) $(<:.c=.o) -o $(OUT)/$@ \
+ ../../src/liblzma/.libs/liblzma.a ;
+
+# The generated binaries are not removed, just the object files. The
+# binaries are created to the $(OUT) directory and must be removed by the
+# fuzzing framework.
clean:
rm -f *.o
diff --git a/tests/ossfuzz/config/fuzz.dict b/tests/ossfuzz/config/fuzz.dict
deleted file mode 100644
index 932d67c..0000000
--- a/tests/ossfuzz/config/fuzz.dict
+++ /dev/null
@@ -1,2 +0,0 @@
-"\xFD7zXZ\x00"
-"YZ"
diff --git a/tests/ossfuzz/config/fuzz.options b/tests/ossfuzz/config/fuzz.options
deleted file mode 100644
index d59dfc1..0000000
--- a/tests/ossfuzz/config/fuzz.options
+++ /dev/null
@@ -1,2 +0,0 @@
-[libfuzzer]
-dict = fuzz.dict
diff --git a/tests/ossfuzz/config/fuzz_decode_alone.options b/tests/ossfuzz/config/fuzz_decode_alone.options
new file mode 100644
index 0000000..1351d96
--- /dev/null
+++ b/tests/ossfuzz/config/fuzz_decode_alone.options
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: 0BSD
+
+[libfuzzer]
+max_len = 4096
+dict = fuzz_lzma.dict
diff --git a/tests/ossfuzz/config/fuzz_decode_stream.options b/tests/ossfuzz/config/fuzz_decode_stream.options
new file mode 100644
index 0000000..bbf43ac
--- /dev/null
+++ b/tests/ossfuzz/config/fuzz_decode_stream.options
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: 0BSD
+
+[libfuzzer]
+dict = fuzz_xz.dict
diff --git a/tests/ossfuzz/config/fuzz_encode_stream.options b/tests/ossfuzz/config/fuzz_encode_stream.options
new file mode 100644
index 0000000..86d4f0c
--- /dev/null
+++ b/tests/ossfuzz/config/fuzz_encode_stream.options
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: 0BSD
+
+[libfuzzer]
+max_len = 4096
diff --git a/tests/ossfuzz/config/fuzz_lzma.dict b/tests/ossfuzz/config/fuzz_lzma.dict
new file mode 100644
index 0000000..b9d5dff
--- /dev/null
+++ b/tests/ossfuzz/config/fuzz_lzma.dict
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: 0BSD
+
+# first 5 header bytes of .lzma archives based on the info from
+# /doc/lzma-file-format.txt
+
+# byte 0 is created by encoding LZMA property values (lc, lp, pb)
+# using the algorithm described in the documentation above.
+
+# lc=3, lp=0, pb=2 and dictionary size = 0x00100000
+"\x5d\x00\x00\x10\x00"
+
+# lc=3, lp=1, pb=3 and dictionary size = 0x00100000
+"\x93\x00\x00\x10\x00"
+
+# lc=2, lp=2, pb=4 and dictionary size = 0x00100000
+"\xc8\x00\x00\x10\x00"
+
+# lc=1, lp=3, pb=1 and dictionary size = 0x00200000
+"\x49\x00\x00\x20\x00"
+
+# lc=0, lp=4, pb=0 and dictionary size = 0x00200000
+"\x24\x00\x00\x20\x00"
diff --git a/tests/ossfuzz/config/fuzz_xz.dict b/tests/ossfuzz/config/fuzz_xz.dict
new file mode 100644
index 0000000..6ba4f24
--- /dev/null
+++ b/tests/ossfuzz/config/fuzz_xz.dict
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: 0BSD
+
+"\xFD7zXZ\x00"
+"YZ"
diff --git a/tests/ossfuzz/fuzz.c b/tests/ossfuzz/fuzz.c
deleted file mode 100644
index 6d89930..0000000
--- a/tests/ossfuzz/fuzz.c
+++ /dev/null
@@ -1,82 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-/// \file fuzz.c
-/// \brief Fuzz test program for liblzma
-//
-// Author: Lasse Collin
-//
-// This file has been put into the public domain.
-// You can do whatever you want with this file.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "lzma.h"
-
-
-// Output buffer for decompressed data. This is write only; nothing cares
-// about the actual data written here.
-static uint8_t outbuf[4096];
-
-
-extern int
-LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
-{
- // Some header values can make liblzma allocate a lot of RAM
- // (up to about 4 GiB with liblzma 5.2.x). We set a limit here to
- // prevent extreme allocations when fuzzing.
- const uint64_t memlimit = 300 << 20; // 300 MiB
-
- // Initialize a .xz decoder using the above memory usage limit.
- // Enable support for concatenated .xz files which is used when
- // decompressing regular .xz files (instead of data embedded inside
- // some other file format). Integrity checks on the uncompressed
- // data are ignored to make fuzzing more effective (incorrect check
- // values won't prevent the decoder from processing more input).
- //
- // The flag LZMA_IGNORE_CHECK doesn't disable verification of header
- // CRC32 values. Those checks are disabled when liblzma is built
- // with the #define FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION.
- lzma_stream strm = LZMA_STREAM_INIT;
- lzma_ret ret = lzma_stream_decoder(&strm, memlimit,
- LZMA_CONCATENATED | LZMA_IGNORE_CHECK);
- if (ret != LZMA_OK) {
- // This should never happen unless the system has
- // no free memory or address space to allow the small
- // allocations that the initialization requires.
- fprintf(stderr, "lzma_stream_decoder() failed (%d)\n", ret);
- abort();
- }
-
- // Give the whole input buffer at once to liblzma.
- // Output buffer isn't initialized as liblzma only writes to it.
- strm.next_in = inbuf;
- strm.avail_in = inbuf_size;
- strm.next_out = outbuf;
- strm.avail_out = sizeof(outbuf);
-
- while ((ret = lzma_code(&strm, LZMA_FINISH)) == LZMA_OK) {
- if (strm.avail_out == 0) {
- // outbuf became full. We don't care about the
- // uncompressed data there, so we simply reuse
- // the outbuf and overwrite the old data.
- strm.next_out = outbuf;
- strm.avail_out = sizeof(outbuf);
- }
- }
-
- // LZMA_PROG_ERROR should never happen as long as the code calling
- // the liblzma functions is correct. Thus LZMA_PROG_ERROR is a sign
- // of a bug in either this function or in liblzma.
- if (ret == LZMA_PROG_ERROR) {
- fprintf(stderr, "lzma_code() returned LZMA_PROG_ERROR\n");
- abort();
- }
-
- // Free the allocated memory.
- lzma_end(&strm);
-
- return 0;
-}
diff --git a/tests/ossfuzz/fuzz_common.h b/tests/ossfuzz/fuzz_common.h
new file mode 100644
index 0000000..4537f1b
--- /dev/null
+++ b/tests/ossfuzz/fuzz_common.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file fuzz_common.h
+/// \brief Common macros and functions needed by the fuzz targets
+//
+// Authors: Maksym Vatsyk
+// Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "lzma.h"
+
+// Some header values can make liblzma allocate a lot of RAM
+// (up to about 4 GiB with liblzma 5.2.x). We set a limit here to
+// prevent extreme allocations when fuzzing.
+#define MEM_LIMIT (300 << 20) // 300 MiB
+
+
+static void
+fuzz_code(lzma_stream *stream, const uint8_t *inbuf, size_t inbuf_size) {
+ // Output buffer for decompressed data. This is write only; nothing
+ // cares about the actual data written here.
+ uint8_t outbuf[4096];
+
+ // Give the whole input buffer at once to liblzma.
+ // Output buffer isn't initialized as liblzma only writes to it.
+ stream->next_in = inbuf;
+ stream->avail_in = inbuf_size;
+ stream->next_out = outbuf;
+ stream->avail_out = sizeof(outbuf);
+
+ lzma_ret ret;
+ while ((ret = lzma_code(stream, LZMA_FINISH)) == LZMA_OK) {
+ if (stream->avail_out == 0) {
+ // outbuf became full. We don't care about the
+ // uncompressed data there, so we simply reuse
+ // the outbuf and overwrite the old data.
+ stream->next_out = outbuf;
+ stream->avail_out = sizeof(outbuf);
+ }
+ }
+
+ // LZMA_PROG_ERROR should never happen as long as the code calling
+ // the liblzma functions is correct. Thus LZMA_PROG_ERROR is a sign
+ // of a bug in either this function or in liblzma.
+ if (ret == LZMA_PROG_ERROR) {
+ fprintf(stderr, "lzma_code() returned LZMA_PROG_ERROR\n");
+ abort();
+ }
+}
diff --git a/tests/ossfuzz/fuzz_decode_alone.c b/tests/ossfuzz/fuzz_decode_alone.c
new file mode 100644
index 0000000..1ef2f9e
--- /dev/null
+++ b/tests/ossfuzz/fuzz_decode_alone.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file fuzz_decode_alone.c
+/// \brief Fuzz test program for liblzma .lzma decoding
+//
+// Authors: Maksym Vatsyk
+// Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "lzma.h"
+#include "fuzz_common.h"
+
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
+{
+ lzma_stream strm = LZMA_STREAM_INIT;
+ // Initialize a LZMA alone decoder using the memory usage limit
+ // defined in fuzz_common.h
+ lzma_ret ret = lzma_alone_decoder(&strm, MEM_LIMIT);
+
+ if (ret != LZMA_OK) {
+ // This should never happen unless the system has
+ // no free memory or address space to allow the small
+ // allocations that the initialization requires.
+ fprintf(stderr, "lzma_alone_decoder() failed (%d)\n", ret);
+ abort();
+ }
+
+ fuzz_code(&strm, inbuf, inbuf_size);
+
+ // Free the allocated memory.
+ lzma_end(&strm);
+ return 0;
+}
diff --git a/tests/ossfuzz/fuzz_decode_stream.c b/tests/ossfuzz/fuzz_decode_stream.c
new file mode 100644
index 0000000..d786061
--- /dev/null
+++ b/tests/ossfuzz/fuzz_decode_stream.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file fuzz_decode_stream.c
+/// \brief Fuzz test program for single threaded .xz decoding
+//
+// Authors: Lasse Collin
+// Maksym Vatsyk
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "lzma.h"
+#include "fuzz_common.h"
+
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
+{
+ lzma_stream strm = LZMA_STREAM_INIT;
+ // Initialize a .xz decoder using the memory usage limit
+ // defined in fuzz_common.h
+ //
+ // Enable support for concatenated .xz files which is used when
+ // decompressing regular .xz files (instead of data embedded inside
+ // some other file format). Integrity checks on the uncompressed
+ // data are ignored to make fuzzing more effective (incorrect check
+ // values won't prevent the decoder from processing more input).
+ //
+ // The flag LZMA_IGNORE_CHECK doesn't disable verification of
+ // header CRC32 values. Those checks are disabled when liblzma is
+ // built with the #define FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION.
+ lzma_ret ret = lzma_stream_decoder(&strm, MEM_LIMIT,
+ LZMA_CONCATENATED | LZMA_IGNORE_CHECK);
+
+ if (ret != LZMA_OK) {
+ // This should never happen unless the system has
+ // no free memory or address space to allow the small
+ // allocations that the initialization requires.
+ fprintf(stderr, "lzma_stream_decoder() failed (%d)\n", ret);
+ abort();
+ }
+
+ fuzz_code(&strm, inbuf, inbuf_size);
+
+ // Free the allocated memory.
+ lzma_end(&strm);
+
+ return 0;
+}
diff --git a/tests/ossfuzz/fuzz_encode_stream.c b/tests/ossfuzz/fuzz_encode_stream.c
new file mode 100644
index 0000000..9438263
--- /dev/null
+++ b/tests/ossfuzz/fuzz_encode_stream.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: 0BSD
+
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file fuzz_encode_stream.c
+/// \brief Fuzz test program for .xz encoding
+//
+// Authors: Maksym Vatsyk
+// Lasse Collin
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "lzma.h"
+#include "fuzz_common.h"
+
+
+extern int
+LLVMFuzzerTestOneInput(const uint8_t *inbuf, size_t inbuf_size)
+{
+ if (inbuf_size == 0) {
+ fprintf(stderr, "no input data provided\n");
+ return 0;
+ }
+
+ // Set the LZMA options based on the first input byte. The fuzzer
+ // will learn through its mutational genetic algorithm with the
+ // code coverage feedback that the first byte must be one of the
+ // values with a switch case label. This allows us to have one fuzz
+ // target cover many critical code paths so the fuzz resources can
+ // be used efficiently.
+ uint32_t preset_level;
+ const uint8_t decider = inbuf[0];
+
+ switch (decider) {
+ case 0:
+ case 1:
+ case 5:
+ preset_level = (uint32_t)decider;
+ break;
+ case 6:
+ preset_level = 0 | LZMA_PRESET_EXTREME;
+ break;
+ case 7:
+ preset_level = 3 | LZMA_PRESET_EXTREME;
+ break;
+ default:
+ return 0;
+ }
+
+ // Initialize lzma_options with the above preset level
+ lzma_options_lzma opt_lzma;
+ if (lzma_lzma_preset(&opt_lzma, preset_level)){
+ fprintf(stderr, "lzma_lzma_preset() failed\n");
+ abort();
+ }
+
+ // Set the filter chain as only LZMA2.
+ lzma_filter filters[2] = {
+ {
+ .id = LZMA_FILTER_LZMA2,
+ .options = &opt_lzma,
+ }, {
+ .id = LZMA_VLI_UNKNOWN,
+ }
+ };
+
+ // initialize empty LZMA stream
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ // Initialize the stream encoder using the above
+ // stream, filter chain and CRC64.
+ lzma_ret ret = lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC64);
+ if (ret != LZMA_OK) {
+ fprintf(stderr, "lzma_stream_encoder() failed (%d)\n", ret);
+ abort();
+ }
+
+ fuzz_code(&strm, inbuf + 1, inbuf_size - 1);
+
+ // Free the allocated memory.
+ lzma_end(&strm);
+ return 0;
+}