From 71ab4acb16a2b4250b363f11eb320f1d839c0c43 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 26 Jan 2019 02:38:56 +0000 Subject: [PATCH] [libFuzzer] add CompressedTest.cpp, a real-life-ish test for a custom mutator llvm-svn: 352265 --- compiler-rt/test/fuzzer/CompressedTest.cpp | 61 ++++++++++++++++++++++++++++++ compiler-rt/test/fuzzer/compressed.test | 6 +++ 2 files changed, 67 insertions(+) create mode 100644 compiler-rt/test/fuzzer/CompressedTest.cpp create mode 100644 compiler-rt/test/fuzzer/compressed.test diff --git a/compiler-rt/test/fuzzer/CompressedTest.cpp b/compiler-rt/test/fuzzer/CompressedTest.cpp new file mode 100644 index 0000000..ec969cb --- /dev/null +++ b/compiler-rt/test/fuzzer/CompressedTest.cpp @@ -0,0 +1,61 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// A fuzz target that consumes a Zlib-compressed input. +// This test verifies that we can find this bug with a custom mutator. +#include +#include +#include +#include +#include + +// The fuzz target. +// Uncompress the data, crash on input starting with "FU". +// Good luck finding this w/o a custom mutator. :) +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + uint8_t Uncompressed[100]; + size_t UncompressedLen = sizeof(Uncompressed); + if (Z_OK != uncompress(Uncompressed, &UncompressedLen, Data, Size)) + return 0; + if (UncompressedLen < 2) return 0; + if (Uncompressed[0] == 'F' && Uncompressed[1] == 'U') + abort(); // Boom + return 0; +} + +#ifdef CUSTOM_MUTATOR + +// Forward-declare the libFuzzer's mutator callback. +extern "C" size_t +LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); + +// The custom mutator: +// * deserialize the data (in this case, uncompress). +// * If the data doesn't deserialize, create a properly serialized dummy. +// * Mutate the deserialized data (in this case, just call LLVMFuzzerMutate). +// * Serialize the mutated data (in this case, compress). +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, + size_t MaxSize, unsigned int Seed) { + uint8_t Uncompressed[100]; + size_t UncompressedLen = sizeof(Uncompressed); + size_t CompressedLen = MaxSize; + if (Z_OK != uncompress(Uncompressed, &UncompressedLen, Data, Size)) { + // The data didn't uncompress. + // So, it's either a broken input and we want to ignore it, + // or we've started fuzzing from an empty corpus and we need to supply + // out first properly compressed input. + uint8_t Dummy[] = {'H', 'i'}; + if (Z_OK != compress(Data, &CompressedLen, Dummy, sizeof(Dummy))) + return 0; + // fprintf(stderr, "Dummy: max %zd res %zd\n", MaxSize, CompressedLen); + return CompressedLen; + } + UncompressedLen = + LLVMFuzzerMutate(Uncompressed, UncompressedLen, sizeof(Uncompressed)); + if (Z_OK != compress(Data, &CompressedLen, Uncompressed, UncompressedLen)) + return 0; + return CompressedLen; +} + +#endif // CUSTOM_MUTATOR diff --git a/compiler-rt/test/fuzzer/compressed.test b/compiler-rt/test/fuzzer/compressed.test new file mode 100644 index 0000000..d5049b7 --- /dev/null +++ b/compiler-rt/test/fuzzer/compressed.test @@ -0,0 +1,6 @@ +REQUIRES: linux +# Custom mutator should find this bug, w/o custom -- no chance. +RUN: %cpp_compiler %S/CompressedTest.cpp -o %t-CompressedTestCustom -DCUSTOM_MUTATOR -lz +RUN: %cpp_compiler %S/CompressedTest.cpp -o %t-CompressedTestPlain -lz +RUN: not %run %t-CompressedTestCustom -seed=1 -runs=1000000 +RUN: %run %t-CompressedTestPlain -seed=1 -runs=1000000 -- 2.7.4