From 41d6683c39d3fcaeb005cc13efca9fd82ff89463 Mon Sep 17 00:00:00 2001 From: Mike Aizatsky Date: Tue, 7 Jun 2016 20:22:15 +0000 Subject: [PATCH] [libfuzzer] custom crossover interface function. Differential Revision: http://reviews.llvm.org/D21089 llvm-svn: 272054 --- llvm/lib/Fuzzer/FuzzerExtFunctions.def | 5 ++ llvm/lib/Fuzzer/FuzzerInterface.h | 9 +++ llvm/lib/Fuzzer/FuzzerInternal.h | 2 + llvm/lib/Fuzzer/FuzzerMutate.cpp | 23 ++++++++ llvm/lib/Fuzzer/test/CMakeLists.txt | 1 + llvm/lib/Fuzzer/test/CustomCrossOverTest.cpp | 57 +++++++++++++++++++ .../Fuzzer/test/fuzzer-customcrossover.test | 10 ++++ 7 files changed, 107 insertions(+) create mode 100644 llvm/lib/Fuzzer/test/CustomCrossOverTest.cpp create mode 100644 llvm/lib/Fuzzer/test/fuzzer-customcrossover.test diff --git a/llvm/lib/Fuzzer/FuzzerExtFunctions.def b/llvm/lib/Fuzzer/FuzzerExtFunctions.def index 0a9046258db9..dccec18f4792 100644 --- a/llvm/lib/Fuzzer/FuzzerExtFunctions.def +++ b/llvm/lib/Fuzzer/FuzzerExtFunctions.def @@ -19,5 +19,10 @@ EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false); EXT_FUNC(LLVMFuzzerCustomMutator, size_t, (uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed), false); +EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, + (const uint8_t * Data1, size_t Size1, + const uint8_t * Data2, size_t Size2, + uint8_t * Out, size_t MaxOutSize, unsigned int Seed), + false); // TODO: Sanitizer functions diff --git a/llvm/lib/Fuzzer/FuzzerInterface.h b/llvm/lib/Fuzzer/FuzzerInterface.h index 8d27f2e7f48e..d47e20e3a2b9 100644 --- a/llvm/lib/Fuzzer/FuzzerInterface.h +++ b/llvm/lib/Fuzzer/FuzzerInterface.h @@ -45,6 +45,15 @@ int LLVMFuzzerInitialize(int *argc, char ***argv); size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed); +// Optional user-provided custom cross-over function. +// Combines pieces of Data1 & Data2 together into Out. +// Returns the new size, which is not greater than MaxOutSize. +// Should produce the same mutation given the same Seed. +size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize, + unsigned int Seed); + // Experimental, may go away in future. // libFuzzer-provided function to be used inside LLVMFuzzerTestOneInput. // Mutates raw data in [Data, Data+Size) inplace. diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index ba4ced5b6081..ff1d1387ad0a 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -215,6 +215,8 @@ public: void RecordSuccessfulMutationSequence(); /// Mutates data by invoking user-provided mutator. size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by invoking user-provided crossover. + size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by shuffling bytes. size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by erasing a byte. diff --git a/llvm/lib/Fuzzer/FuzzerMutate.cpp b/llvm/lib/Fuzzer/FuzzerMutate.cpp index 8f1b1c6db97c..e25a00d84ac2 100644 --- a/llvm/lib/Fuzzer/FuzzerMutate.cpp +++ b/llvm/lib/Fuzzer/FuzzerMutate.cpp @@ -41,6 +41,10 @@ MutationDispatcher::MutationDispatcher(Random &Rand) : Rand(Rand) { Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); else Mutators = DefaultMutators; + + if (EF.LLVMFuzzerCustomCrossOver) + Mutators.push_back( + {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); } static char FlipRandomBit(char X, Random &Rand) { @@ -66,6 +70,25 @@ size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, return EF.LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); } +size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (!Corpus || Corpus->size() < 2 || Size == 0) + return 0; + size_t Idx = Rand(Corpus->size()); + const Unit &Other = (*Corpus)[Idx]; + if (Other.empty()) + return 0; + MutateInPlaceHere.resize(MaxSize); + auto &U = MutateInPlaceHere; + size_t NewSize = EF.LLVMFuzzerCustomCrossOver( + Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); + if (!NewSize) + return 0; + assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); + memcpy(Data, U.data(), NewSize); + return NewSize; +} + size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize) { assert(Size); diff --git a/llvm/lib/Fuzzer/test/CMakeLists.txt b/llvm/lib/Fuzzer/test/CMakeLists.txt index 6d05ec1dedf0..85fb62e3345a 100644 --- a/llvm/lib/Fuzzer/test/CMakeLists.txt +++ b/llvm/lib/Fuzzer/test/CMakeLists.txt @@ -66,6 +66,7 @@ set(Tests BufferOverflowOnInput CallerCalleeTest CounterTest + CustomCrossOverTest CustomMutatorTest EmptyTest FourIndependentBranchesTest diff --git a/llvm/lib/Fuzzer/test/CustomCrossOverTest.cpp b/llvm/lib/Fuzzer/test/CustomCrossOverTest.cpp new file mode 100644 index 000000000000..2ab5781155f0 --- /dev/null +++ b/llvm/lib/Fuzzer/test/CustomCrossOverTest.cpp @@ -0,0 +1,57 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a cutom mutator. +#include +#include +#include +#include +#include +#include +#include + +#include "FuzzerInterface.h" + +static const char *Separator = "-_^_-"; +static const char *Target = "012-_^_-abc"; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + std::string Str(reinterpret_cast(Data), Size); + + if (Str.find(Target) != std::string::npos) { + std::cout << "BINGO; Found the target, exiting\n"; + exit(1); + } + return 0; +} + +extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize, + unsigned int Seed) { + static bool Printed; + static size_t SeparatorLen = strlen(Separator); + + if (!Printed) { + std::cerr << "In LLVMFuzzerCustomCrossover\n"; + Printed = true; + } + + std::mt19937 R(Seed); + + size_t Offset1 = 0; + size_t Len1 = R() % (Size1 - Offset1); + size_t Offset2 = 0; + size_t Len2 = R() % (Size2 - Offset2); + size_t Size = Len1 + Len2 + SeparatorLen; + + if (Size > MaxOutSize) + return 0; + + memcpy(Out, Data1 + Offset1, Len1); + memcpy(Out + Len1, Separator, SeparatorLen); + memcpy(Out + Len1 + SeparatorLen, Data2 + Offset2, Len2); + + return Len1 + Len2 + SeparatorLen; +} diff --git a/llvm/lib/Fuzzer/test/fuzzer-customcrossover.test b/llvm/lib/Fuzzer/test/fuzzer-customcrossover.test new file mode 100644 index 000000000000..4be54d3f799e --- /dev/null +++ b/llvm/lib/Fuzzer/test/fuzzer-customcrossover.test @@ -0,0 +1,10 @@ +RUN: rm -rf %t/CustomCrossover +RUN: mkdir -p %t/CustomCrossover +RUN: echo "0123456789" > %t/CustomCrossover/digits +RUN: echo "abcdefghij" > %t/CustomCrossover/chars +RUN: not LLVMFuzzer-CustomCrossOverTest -seed=1 -use_memcmp=0 -runs=100000 -prune_corpus=0 %t/CustomCrossover 2>&1 | FileCheck %s --check-prefix=LLVMFuzzerCustomCrossover +RUN: rm -rf %t/CustomCrossover + +LLVMFuzzerCustomCrossover: In LLVMFuzzerCustomCrossover +LLVMFuzzerCustomCrossover: BINGO +