From 380051868a7531830d94d312f0f11b0e19e3284f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 10 Sep 2020 15:26:46 +0200 Subject: add libfuzzer custom mutator, minor enhancements and fixes --- custom_mutators/libfuzzer/FuzzerIO.cpp | 248 +++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 custom_mutators/libfuzzer/FuzzerIO.cpp (limited to 'custom_mutators/libfuzzer/FuzzerIO.cpp') diff --git a/custom_mutators/libfuzzer/FuzzerIO.cpp b/custom_mutators/libfuzzer/FuzzerIO.cpp new file mode 100644 index 00000000..e0c15db4 --- /dev/null +++ b/custom_mutators/libfuzzer/FuzzerIO.cpp @@ -0,0 +1,248 @@ +//===- FuzzerIO.cpp - IO utils. -------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// IO functions. +//===----------------------------------------------------------------------===// + +#include "FuzzerDefs.h" +#include "FuzzerExtFunctions.h" +#include "FuzzerIO.h" +#include "FuzzerUtil.h" +#include +#include +#include +#include +#include +#include + +namespace fuzzer { + +static FILE *OutputFile = stderr; + +long GetEpoch(const std::string &Path) { + + struct stat St; + if (stat(Path.c_str(), &St)) return 0; // Can't stat, be conservative. + return St.st_mtime; + +} + +Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { + + std::ifstream T(Path, std::ios::binary); + if (ExitOnError && !T) { + + Printf("No such directory: %s; exiting\n", Path.c_str()); + exit(1); + + } + + T.seekg(0, T.end); + auto EndPos = T.tellg(); + if (EndPos < 0) return {}; + size_t FileLen = EndPos; + if (MaxSize) FileLen = std::min(FileLen, MaxSize); + + T.seekg(0, T.beg); + Unit Res(FileLen); + T.read(reinterpret_cast(Res.data()), FileLen); + return Res; + +} + +std::string FileToString(const std::string &Path) { + + std::ifstream T(Path, std::ios::binary); + return std::string((std::istreambuf_iterator(T)), + std::istreambuf_iterator()); + +} + +void CopyFileToErr(const std::string &Path) { + + Printf("%s", FileToString(Path).c_str()); + +} + +void WriteToFile(const Unit &U, const std::string &Path) { + + WriteToFile(U.data(), U.size(), Path); + +} + +void WriteToFile(const std::string &Data, const std::string &Path) { + + WriteToFile(reinterpret_cast(Data.c_str()), Data.size(), + Path); + +} + +void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) { + + // Use raw C interface because this function may be called from a sig handler. + FILE *Out = fopen(Path.c_str(), "wb"); + if (!Out) return; + fwrite(Data, sizeof(Data[0]), Size, Out); + fclose(Out); + +} + +void AppendToFile(const std::string &Data, const std::string &Path) { + + AppendToFile(reinterpret_cast(Data.data()), Data.size(), + Path); + +} + +void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) { + + FILE *Out = fopen(Path.c_str(), "a"); + if (!Out) return; + fwrite(Data, sizeof(Data[0]), Size, Out); + fclose(Out); + +} + +void ReadDirToVectorOfUnits(const char *Path, Vector *V, long *Epoch, + size_t MaxSize, bool ExitOnError) { + + long E = Epoch ? *Epoch : 0; + Vector Files; + ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/ true); + size_t NumLoaded = 0; + for (size_t i = 0; i < Files.size(); i++) { + + auto &X = Files[i]; + if (Epoch && GetEpoch(X) < E) continue; + NumLoaded++; + if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024) + Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path); + auto S = FileToVector(X, MaxSize, ExitOnError); + if (!S.empty()) V->push_back(S); + + } + +} + +void GetSizedFilesFromDir(const std::string &Dir, Vector *V) { + + Vector Files; + ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/ true); + for (auto &File : Files) + if (size_t Size = FileSize(File)) V->push_back({File, Size}); + +} + +std::string DirPlusFile(const std::string &DirPath, + const std::string &FileName) { + + return DirPath + GetSeparator() + FileName; + +} + +void DupAndCloseStderr() { + + int OutputFd = DuplicateFile(2); + if (OutputFd >= 0) { + + FILE *NewOutputFile = OpenFile(OutputFd, "w"); + if (NewOutputFile) { + + OutputFile = NewOutputFile; + if (EF->__sanitizer_set_report_fd) + EF->__sanitizer_set_report_fd( + reinterpret_cast(GetHandleFromFd(OutputFd))); + DiscardOutput(2); + + } + + } + +} + +void CloseStdout() { + + DiscardOutput(1); + +} + +void Printf(const char *Fmt, ...) { + + va_list ap; + va_start(ap, Fmt); + vfprintf(OutputFile, Fmt, ap); + va_end(ap); + fflush(OutputFile); + +} + +void VPrintf(bool Verbose, const char *Fmt, ...) { + + if (!Verbose) return; + va_list ap; + va_start(ap, Fmt); + vfprintf(OutputFile, Fmt, ap); + va_end(ap); + fflush(OutputFile); + +} + +static bool MkDirRecursiveInner(const std::string &Leaf) { + + // Prevent chance of potential infinite recursion + if (Leaf == ".") return true; + + const std::string &Dir = DirName(Leaf); + + if (IsDirectory(Dir)) { + + MkDir(Leaf); + return IsDirectory(Leaf); + + } + + bool ret = MkDirRecursiveInner(Dir); + if (!ret) { + + // Give up early if a previous MkDir failed + return ret; + + } + + MkDir(Leaf); + return IsDirectory(Leaf); + +} + +bool MkDirRecursive(const std::string &Dir) { + + if (Dir.empty()) return false; + + if (IsDirectory(Dir)) return true; + + return MkDirRecursiveInner(Dir); + +} + +void RmDirRecursive(const std::string &Dir) { + + IterateDirRecursive( + Dir, [](const std::string &Path) {}, + [](const std::string &Path) { RmDir(Path); }, + [](const std::string &Path) { RemoveFile(Path); }); + +} + +std::string TempPath(const char *Prefix, const char *Extension) { + + return DirPlusFile(TmpDir(), std::string("libFuzzerTemp.") + Prefix + + std::to_string(GetPid()) + Extension); + +} + +} // namespace fuzzer + -- cgit 1.4.1 From 166130324898071a08e178dfeb901af44168236e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 10 Nov 2020 13:43:48 +0100 Subject: fix libfuzzer custom mutator and add introspection function --- custom_mutators/libfuzzer/FuzzerIO.cpp | 7 +++++++ custom_mutators/libfuzzer/FuzzerLoop.cpp | 13 ++++++++++++- custom_mutators/libfuzzer/FuzzerMutate.cpp | 24 ++++++++++++++++++++++-- custom_mutators/libfuzzer/FuzzerMutate.h | 1 + custom_mutators/libfuzzer/Makefile | 5 +++++ custom_mutators/libfuzzer/libfuzzer.cpp | 12 ++++++++++++ 6 files changed, 59 insertions(+), 3 deletions(-) (limited to 'custom_mutators/libfuzzer/FuzzerIO.cpp') diff --git a/custom_mutators/libfuzzer/FuzzerIO.cpp b/custom_mutators/libfuzzer/FuzzerIO.cpp index e0c15db4..d8d52b63 100644 --- a/custom_mutators/libfuzzer/FuzzerIO.cpp +++ b/custom_mutators/libfuzzer/FuzzerIO.cpp @@ -83,6 +83,8 @@ void WriteToFile(const std::string &Data, const std::string &Path) { void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) { + return; + // Use raw C interface because this function may be called from a sig handler. FILE *Out = fopen(Path.c_str(), "wb"); if (!Out) return; @@ -93,6 +95,8 @@ void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) { void AppendToFile(const std::string &Data, const std::string &Path) { + return; + AppendToFile(reinterpret_cast(Data.data()), Data.size(), Path); @@ -100,6 +104,8 @@ void AppendToFile(const std::string &Data, const std::string &Path) { void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) { + return; + FILE *Out = fopen(Path.c_str(), "a"); if (!Out) return; fwrite(Data, sizeof(Data[0]), Size, Out); @@ -182,6 +188,7 @@ void Printf(const char *Fmt, ...) { void VPrintf(bool Verbose, const char *Fmt, ...) { + return; if (!Verbose) return; va_list ap; va_start(ap, Fmt); diff --git a/custom_mutators/libfuzzer/FuzzerLoop.cpp b/custom_mutators/libfuzzer/FuzzerLoop.cpp index 201883f0..08fda520 100644 --- a/custom_mutators/libfuzzer/FuzzerLoop.cpp +++ b/custom_mutators/libfuzzer/FuzzerLoop.cpp @@ -206,6 +206,8 @@ void Fuzzer::StaticDeathCallback() { void Fuzzer::DumpCurrentUnit(const char *Prefix) { + return; + if (!CurrentUnitData) return; // Happens when running individual inputs. ScopedDisableMsanInterceptorChecks S; MD.PrintMutationSequence(); @@ -733,6 +735,7 @@ std::string Fuzzer::WriteToOutputCorpus(const Unit &U) { void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { + return; if (!Options.SaveArtifacts) return; std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); if (!Options.ExactArtifactPath.empty()) @@ -1073,13 +1076,21 @@ void Fuzzer::MinimizeCrashLoop(const Unit &U) { } // namespace fuzzer +#ifdef INTROSPECTION + extern const char *introspection_ptr; +#endif + extern "C" { ATTRIBUTE_INTERFACE size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { assert(fuzzer::F); - return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); + size_t r = fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); +#ifdef INTROSPECTION + introspection_ptr = fuzzer::F->GetMD().WriteMutationSequence(); +#endif + return r; } diff --git a/custom_mutators/libfuzzer/FuzzerMutate.cpp b/custom_mutators/libfuzzer/FuzzerMutate.cpp index eebae39b..edfe0455 100644 --- a/custom_mutators/libfuzzer/FuzzerMutate.cpp +++ b/custom_mutators/libfuzzer/FuzzerMutate.cpp @@ -14,6 +14,8 @@ #include "FuzzerMutate.h" #include "FuzzerOptions.h" #include "FuzzerTracePC.h" +#include +#include namespace fuzzer { @@ -100,15 +102,17 @@ size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, } + size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize) { - if (Size > MaxSize || Size == 0) return 0; size_t ShuffleAmount = Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. size_t ShuffleStart = Rand(Size - ShuffleAmount); assert(ShuffleStart + ShuffleAmount <= Size); - std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); + unsigned num = std::chrono::system_clock::now().time_since_epoch().count(); + std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, std::default_random_engine(num)); + //std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); return Size; } @@ -609,8 +613,24 @@ void MutationDispatcher::PrintRecommendedDictionary() { } +const char *MutationDispatcher::WriteMutationSequence() { + + static std::string buf; + buf = ""; + + for (size_t i = 0; i < CurrentMutatorSequence.size(); i++) { + + buf = buf + " " + CurrentMutatorSequence[i].Name; + + } + + return buf.c_str(); + +} + void MutationDispatcher::PrintMutationSequence(bool Verbose) { + return; Printf("MS: %zd ", CurrentMutatorSequence.size()); size_t EntriesToPrint = Verbose ? CurrentMutatorSequence.size() diff --git a/custom_mutators/libfuzzer/FuzzerMutate.h b/custom_mutators/libfuzzer/FuzzerMutate.h index 37fd6100..6252f265 100644 --- a/custom_mutators/libfuzzer/FuzzerMutate.h +++ b/custom_mutators/libfuzzer/FuzzerMutate.h @@ -26,6 +26,7 @@ public: void StartMutationSequence(); /// Print the current sequence of mutations. Only prints the full sequence /// when Verbose is true. + const char *WriteMutationSequence(); void PrintMutationSequence(bool Verbose = true); /// Return the current sequence of mutations. std::string MutationSequence(); diff --git a/custom_mutators/libfuzzer/Makefile b/custom_mutators/libfuzzer/Makefile index 95402f6c..51263b89 100644 --- a/custom_mutators/libfuzzer/Makefile +++ b/custom_mutators/libfuzzer/Makefile @@ -3,6 +3,11 @@ CFLAGS = -g -O3 -funroll-loops -fPIC -fpermissive -std=c++11 #CFLAGS = -g -O0 -fPIC -fpermissive -std=c++11 CXX ?= clang++ +ifdef INTROSPECTION + $(info Compiling with introspection documentation) + CFLAGS += -DINTROSPECTION=1 +endif + all: libfuzzer-mutator.so FuzzerCrossOver.o: FuzzerCrossOver.cpp diff --git a/custom_mutators/libfuzzer/libfuzzer.cpp b/custom_mutators/libfuzzer/libfuzzer.cpp index 5e37df66..a4f94328 100644 --- a/custom_mutators/libfuzzer/libfuzzer.cpp +++ b/custom_mutators/libfuzzer/libfuzzer.cpp @@ -6,6 +6,10 @@ //#include "debug.h" #include "afl-fuzz.h" +#ifdef INTROSPECTION + const char *introspection_ptr; +#endif + afl_state_t *afl_struct; extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); @@ -133,6 +137,14 @@ extern "C" size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, } +#ifdef INTROSPECTION +extern "C" const char* afl_custom_introspection(my_mutator_t *data) { + + return introspection_ptr; + +} +#endif + /** * Deinitialize everything * -- cgit 1.4.1