diff options
| author | 2016-09-03 22:46:54 +0000 | |
|---|---|---|
| committer | 2016-09-03 22:46:54 +0000 | |
| commit | b5500b9ca0102f1ccaf32f0e77e96d0739aded9b (patch) | |
| tree | e1b7ebb5a0231f9e6d8d3f6f719582cebd64dc98 /gnu/llvm/lib/Fuzzer | |
| parent | clarify purpose of src/gnu/ directory. (diff) | |
| download | wireguard-openbsd-b5500b9ca0102f1ccaf32f0e77e96d0739aded9b.tar.xz wireguard-openbsd-b5500b9ca0102f1ccaf32f0e77e96d0739aded9b.zip | |
Use the space freed up by sparc and zaurus to import LLVM.
ok hackroom@
Diffstat (limited to 'gnu/llvm/lib/Fuzzer')
55 files changed, 4308 insertions, 0 deletions
diff --git a/gnu/llvm/lib/Fuzzer/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/CMakeLists.txt new file mode 100644 index 00000000000..d4d85041d21 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/CMakeLists.txt @@ -0,0 +1,34 @@ +set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS_RELEASE}") +# Disable the coverage and sanitizer instrumentation for the fuzzer itself. +set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all") +if( LLVM_USE_SANITIZE_COVERAGE ) + add_library(LLVMFuzzerNoMainObjects OBJECT + FuzzerCrossOver.cpp + FuzzerInterface.cpp + FuzzerTraceState.cpp + FuzzerDriver.cpp + FuzzerIO.cpp + FuzzerLoop.cpp + FuzzerMutate.cpp + FuzzerSanitizerOptions.cpp + FuzzerSHA1.cpp + FuzzerUtil.cpp + ) + add_library(LLVMFuzzerNoMain STATIC + $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> + ) + if( HAVE_LIBPTHREAD ) + target_link_libraries(LLVMFuzzerNoMain pthread) + endif() + add_library(LLVMFuzzer STATIC + FuzzerMain.cpp + $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> + ) + if( HAVE_LIBPTHREAD ) + target_link_libraries(LLVMFuzzer pthread) + endif() + + if( LLVM_INCLUDE_TESTS ) + add_subdirectory(test) + endif() +endif() diff --git a/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp b/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp new file mode 100644 index 00000000000..5203deaf912 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp @@ -0,0 +1,51 @@ +//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Cross over test inputs. +//===----------------------------------------------------------------------===// + +#include <cstring> + +#include "FuzzerInternal.h" + +namespace fuzzer { + +// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. +size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize) { + assert(Size1 || Size2); + MaxOutSize = Rand(MaxOutSize) + 1; + size_t OutPos = 0; + size_t Pos1 = 0; + size_t Pos2 = 0; + size_t *InPos = &Pos1; + size_t InSize = Size1; + const uint8_t *Data = Data1; + bool CurrentlyUsingFirstData = true; + while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) { + // Merge a part of Data into Out. + size_t OutSizeLeft = MaxOutSize - OutPos; + if (*InPos < InSize) { + size_t InSizeLeft = InSize - *InPos; + size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft); + size_t ExtraSize = Rand(MaxExtraSize) + 1; + memcpy(Out + OutPos, Data + *InPos, ExtraSize); + OutPos += ExtraSize; + (*InPos) += ExtraSize; + } + // Use the other input data on the next iteration. + InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1; + InSize = CurrentlyUsingFirstData ? Size2 : Size1; + Data = CurrentlyUsingFirstData ? Data2 : Data1; + CurrentlyUsingFirstData = !CurrentlyUsingFirstData; + } + return OutPos; +} + +} // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerDFSan.h b/gnu/llvm/lib/Fuzzer/FuzzerDFSan.h new file mode 100644 index 00000000000..eb206ec61ce --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerDFSan.h @@ -0,0 +1,61 @@ +//===- FuzzerDFSan.h - Internal header for the Fuzzer -----------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// DFSan interface. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_DFSAN_H +#define LLVM_FUZZER_DFSAN_H + +#define LLVM_FUZZER_SUPPORTS_DFSAN 0 +#if defined(__has_include) +# if __has_include(<sanitizer/dfsan_interface.h>) +# if defined (__linux__) +# undef LLVM_FUZZER_SUPPORTS_DFSAN +# define LLVM_FUZZER_SUPPORTS_DFSAN 1 +# include <sanitizer/dfsan_interface.h> +# endif // __linux__ +# endif +#endif // defined(__has_include) + +#if LLVM_FUZZER_SUPPORTS_DFSAN + +extern "C" { +__attribute__((weak)) +dfsan_label dfsan_create_label(const char *desc, void *userdata); +__attribute__((weak)) +void dfsan_set_label(dfsan_label label, void *addr, size_t size); +__attribute__((weak)) +void dfsan_add_label(dfsan_label label, void *addr, size_t size); +__attribute__((weak)) +const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label); +__attribute__((weak)) +dfsan_label dfsan_read_label(const void *addr, size_t size); +} // extern "C" + +namespace fuzzer { +static bool ReallyHaveDFSan() { + return &dfsan_create_label != nullptr; +} +} // namespace fuzzer +#else +// When compiling with a compiler which does not support dfsan, +// this code is still expected to build (but not necessary work). +typedef unsigned short dfsan_label; +struct dfsan_label_info { + dfsan_label l1, l2; + const char *desc; + void *userdata; +}; +namespace fuzzer { +static bool ReallyHaveDFSan() { return false; } +} // namespace fuzzer + +#endif + +#endif // LLVM_FUZZER_DFSAN_H diff --git a/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp b/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp new file mode 100644 index 00000000000..66e46dbf3aa --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp @@ -0,0 +1,336 @@ +//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// FuzzerDriver and flag parsing. +//===----------------------------------------------------------------------===// + +#include "FuzzerInterface.h" +#include "FuzzerInternal.h" + +#include <cstring> +#include <chrono> +#include <unistd.h> +#include <thread> +#include <atomic> +#include <mutex> +#include <string> +#include <sstream> +#include <algorithm> +#include <iterator> + +namespace fuzzer { + +// Program arguments. +struct FlagDescription { + const char *Name; + const char *Description; + int Default; + int *IntFlag; + const char **StrFlag; + unsigned int *UIntFlag; +}; + +struct { +#define FUZZER_FLAG_INT(Name, Default, Description) int Name; +#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; +#define FUZZER_FLAG_STRING(Name, Description) const char *Name; +#include "FuzzerFlags.def" +#undef FUZZER_FLAG_INT +#undef FUZZER_FLAG_UNSIGNED +#undef FUZZER_FLAG_STRING +} Flags; + +static const FlagDescription FlagDescriptions [] { +#define FUZZER_FLAG_INT(Name, Default, Description) \ + {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, +#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ + {#Name, Description, static_cast<int>(Default), \ + nullptr, nullptr, &Flags.Name}, +#define FUZZER_FLAG_STRING(Name, Description) \ + {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, +#include "FuzzerFlags.def" +#undef FUZZER_FLAG_INT +#undef FUZZER_FLAG_UNSIGNED +#undef FUZZER_FLAG_STRING +}; + +static const size_t kNumFlags = + sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); + +static std::vector<std::string> *Inputs; +static std::string *ProgName; + +static void PrintHelp() { + Printf("Usage: %s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", + ProgName->c_str()); + Printf("\nFlags: (strictly in form -flag=value)\n"); + size_t MaxFlagLen = 0; + for (size_t F = 0; F < kNumFlags; F++) + MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); + + for (size_t F = 0; F < kNumFlags; F++) { + const auto &D = FlagDescriptions[F]; + Printf(" %s", D.Name); + for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) + Printf(" "); + Printf("\t"); + Printf("%d\t%s\n", D.Default, D.Description); + } + Printf("\nFlags starting with '--' will be ignored and " + "will be passed verbatim to subprocesses.\n"); +} + +static const char *FlagValue(const char *Param, const char *Name) { + size_t Len = strlen(Name); + if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && + Param[Len + 1] == '=') + return &Param[Len + 2]; + return nullptr; +} + +static bool ParseOneFlag(const char *Param) { + if (Param[0] != '-') return false; + if (Param[1] == '-') { + static bool PrintedWarning = false; + if (!PrintedWarning) { + PrintedWarning = true; + Printf("WARNING: libFuzzer ignores flags that start with '--'\n"); + } + return true; + } + for (size_t F = 0; F < kNumFlags; F++) { + const char *Name = FlagDescriptions[F].Name; + const char *Str = FlagValue(Param, Name); + if (Str) { + if (FlagDescriptions[F].IntFlag) { + int Val = std::stol(Str); + *FlagDescriptions[F].IntFlag = Val; + if (Flags.verbosity >= 2) + Printf("Flag: %s %d\n", Name, Val);; + return true; + } else if (FlagDescriptions[F].UIntFlag) { + unsigned int Val = std::stoul(Str); + *FlagDescriptions[F].UIntFlag = Val; + if (Flags.verbosity >= 2) + Printf("Flag: %s %u\n", Name, Val); + return true; + } else if (FlagDescriptions[F].StrFlag) { + *FlagDescriptions[F].StrFlag = Str; + if (Flags.verbosity >= 2) + Printf("Flag: %s %s\n", Name, Str); + return true; + } + } + } + PrintHelp(); + exit(1); +} + +// We don't use any library to minimize dependencies. +static void ParseFlags(const std::vector<std::string> &Args) { + for (size_t F = 0; F < kNumFlags; F++) { + if (FlagDescriptions[F].IntFlag) + *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; + if (FlagDescriptions[F].UIntFlag) + *FlagDescriptions[F].UIntFlag = + static_cast<unsigned int>(FlagDescriptions[F].Default); + if (FlagDescriptions[F].StrFlag) + *FlagDescriptions[F].StrFlag = nullptr; + } + Inputs = new std::vector<std::string>; + for (size_t A = 1; A < Args.size(); A++) { + if (ParseOneFlag(Args[A].c_str())) continue; + Inputs->push_back(Args[A]); + } +} + +static std::mutex Mu; + +static void PulseThread() { + while (true) { + std::this_thread::sleep_for(std::chrono::seconds(600)); + std::lock_guard<std::mutex> Lock(Mu); + Printf("pulse...\n"); + } +} + +static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter, + int NumJobs, std::atomic<bool> *HasErrors) { + while (true) { + int C = (*Counter)++; + if (C >= NumJobs) break; + std::string Log = "fuzz-" + std::to_string(C) + ".log"; + std::string ToRun = Cmd + " > " + Log + " 2>&1\n"; + if (Flags.verbosity) + Printf("%s", ToRun.c_str()); + int ExitCode = ExecuteCommand(ToRun.c_str()); + if (ExitCode != 0) + *HasErrors = true; + std::lock_guard<std::mutex> Lock(Mu); + Printf("================== Job %d exited with exit code %d ============\n", + C, ExitCode); + fuzzer::CopyFileToErr(Log); + } +} + +static int RunInMultipleProcesses(const std::vector<std::string> &Args, + int NumWorkers, int NumJobs) { + std::atomic<int> Counter(0); + std::atomic<bool> HasErrors(false); + std::string Cmd; + for (auto &S : Args) { + if (FlagValue(S.c_str(), "jobs") || FlagValue(S.c_str(), "workers")) + continue; + Cmd += S + " "; + } + std::vector<std::thread> V; + std::thread Pulse(PulseThread); + Pulse.detach(); + for (int i = 0; i < NumWorkers; i++) + V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors)); + for (auto &T : V) + T.join(); + return HasErrors ? 1 : 0; +} + +int RunOneTest(Fuzzer *F, const char *InputFilePath) { + Unit U = FileToVector(InputFilePath); + Unit PreciseSizedU(U); + assert(PreciseSizedU.size() == PreciseSizedU.capacity()); + F->ExecuteCallback(PreciseSizedU); + return 0; +} + +int FuzzerDriver(int argc, char **argv, UserCallback Callback) { + FuzzerRandomLibc Rand(0); + SimpleUserSuppliedFuzzer SUSF(&Rand, Callback); + return FuzzerDriver(argc, argv, SUSF); +} + +int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) { + std::vector<std::string> Args(argv, argv + argc); + return FuzzerDriver(Args, USF); +} + +int FuzzerDriver(const std::vector<std::string> &Args, UserCallback Callback) { + FuzzerRandomLibc Rand(0); + SimpleUserSuppliedFuzzer SUSF(&Rand, Callback); + return FuzzerDriver(Args, SUSF); +} + +int FuzzerDriver(const std::vector<std::string> &Args, + UserSuppliedFuzzer &USF) { + using namespace fuzzer; + assert(!Args.empty()); + ProgName = new std::string(Args[0]); + ParseFlags(Args); + if (Flags.help) { + PrintHelp(); + return 0; + } + + if (Flags.jobs > 0 && Flags.workers == 0) { + Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); + if (Flags.workers > 1) + Printf("Running %d workers\n", Flags.workers); + } + + if (Flags.workers > 0 && Flags.jobs > 0) + return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); + + Fuzzer::FuzzingOptions Options; + Options.Verbosity = Flags.verbosity; + Options.MaxLen = Flags.max_len; + Options.UnitTimeoutSec = Flags.timeout; + Options.MaxTotalTimeSec = Flags.max_total_time; + Options.DoCrossOver = Flags.cross_over; + Options.MutateDepth = Flags.mutate_depth; + Options.ExitOnFirst = Flags.exit_on_first; + Options.UseCounters = Flags.use_counters; + Options.UseIndirCalls = Flags.use_indir_calls; + Options.UseTraces = Flags.use_traces; + Options.ShuffleAtStartUp = Flags.shuffle; + Options.PreferSmallDuringInitialShuffle = + Flags.prefer_small_during_initial_shuffle; + Options.Reload = Flags.reload; + Options.OnlyASCII = Flags.only_ascii; + Options.OutputCSV = Flags.output_csv; + if (Flags.runs >= 0) + Options.MaxNumberOfRuns = Flags.runs; + if (!Inputs->empty()) + Options.OutputCorpus = (*Inputs)[0]; + if (Flags.sync_command) + Options.SyncCommand = Flags.sync_command; + Options.SyncTimeout = Flags.sync_timeout; + Options.ReportSlowUnits = Flags.report_slow_units; + if (Flags.artifact_prefix) + Options.ArtifactPrefix = Flags.artifact_prefix; + if (Flags.exact_artifact_path) + Options.ExactArtifactPath = Flags.exact_artifact_path; + std::vector<Unit> Dictionary; + if (Flags.dict) + if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) + return 1; + if (Flags.verbosity > 0 && !Dictionary.empty()) + Printf("Dictionary: %zd entries\n", Dictionary.size()); + Options.SaveArtifacts = !Flags.test_single_input; + Options.PrintNewCovPcs = Flags.print_new_cov_pcs; + + Fuzzer F(USF, Options); + + for (auto &U: Dictionary) + USF.GetMD().AddWordToManualDictionary(U); + + // Timer + if (Flags.timeout > 0) + SetTimer(Flags.timeout / 2 + 1); + + if (Flags.test_single_input) { + RunOneTest(&F, Flags.test_single_input); + exit(0); + } + + if (Flags.save_minimized_corpus) { + Printf("The flag -save_minimized_corpus is deprecated; use -merge=1\n"); + exit(1); + } + + if (Flags.merge) { + F.Merge(*Inputs); + exit(0); + } + + unsigned Seed = Flags.seed; + // Initialize Seed. + if (Seed == 0) + Seed = time(0) * 10000 + getpid(); + if (Flags.verbosity) + Printf("Seed: %u\n", Seed); + USF.GetRand().ResetSeed(Seed); + + F.RereadOutputCorpus(); + for (auto &inp : *Inputs) + if (inp != Options.OutputCorpus) + F.ReadDir(inp, nullptr); + + if (F.CorpusSize() == 0) + F.AddToCorpus(Unit()); // Can't fuzz empty corpus, so add an empty input. + F.ShuffleAndMinimize(); + if (Flags.drill) + F.Drill(); + else + F.Loop(); + + if (Flags.verbosity) + Printf("Done %d runs in %zd second(s)\n", F.getTotalNumberOfRuns(), + F.secondsSinceProcessStartUp()); + + exit(0); // Don't let F destroy itself. +} + +} // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerFlags.def b/gnu/llvm/lib/Fuzzer/FuzzerFlags.def new file mode 100644 index 00000000000..977efb76922 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerFlags.def @@ -0,0 +1,72 @@ +//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the +// point of inclusion. We are not using any flag parsing library for better +// portability and independence. +//===----------------------------------------------------------------------===// +FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.") +FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.") +FUZZER_FLAG_INT(runs, -1, + "Number of individual test runs (-1 for infinite runs).") +FUZZER_FLAG_INT(max_len, 64, "Maximum length of the test input.") +FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.") +FUZZER_FLAG_INT(mutate_depth, 5, + "Apply this number of consecutive mutations to each input.") +FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup") +FUZZER_FLAG_INT( + prefer_small_during_initial_shuffle, -1, + "If 1, always prefer smaller inputs during the initial corpus shuffle." + " If 0, never do that. If -1, do it sometimes.") +FUZZER_FLAG_INT(exit_on_first, 0, + "If 1, exit after the first new interesting input is found.") +FUZZER_FLAG_INT( + timeout, 1200, + "Timeout in seconds (if positive). " + "If one unit runs more than this number of seconds the process will abort.") +FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total " + "time in seconds to run the fuzzer.") +FUZZER_FLAG_INT(help, 0, "Print help.") +FUZZER_FLAG_INT(save_minimized_corpus, 0, "Deprecated. Use -merge=1") +FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " + "merged into the 1-st corpus. Only interesting units will be taken.") +FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") +FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters") +FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces") +FUZZER_FLAG_INT(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn" + " this number of jobs in separate worker processes" + " with stdout/stderr redirected to fuzz-JOB.log.") +FUZZER_FLAG_INT(workers, 0, + "Number of simultaneous worker processes to run the jobs." + " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.") +FUZZER_FLAG_INT(reload, 1, + "Reload the main corpus periodically to get new units" + " discovered by other processes.") +FUZZER_FLAG_STRING(sync_command, "Execute an external command " + "\"<sync_command> <test_corpus>\" " + "to synchronize the test corpus.") +FUZZER_FLAG_INT(sync_timeout, 600, "Minimum timeout between syncs.") +FUZZER_FLAG_INT(report_slow_units, 10, + "Report slowest units if they run for more than this number of seconds.") +FUZZER_FLAG_INT(only_ascii, 0, + "If 1, generate only ASCII (isprint+isspace) inputs.") +FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.") +FUZZER_FLAG_STRING(test_single_input, "Use specified file as test input.") +FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, " + "timeout, or slow inputs) as " + "$(artifact_prefix)file") +FUZZER_FLAG_STRING(exact_artifact_path, + "Write the single artifact on failure (crash, timeout) " + "as $(exact_artifact_path). This overrides -artifact_prefix " + "and will not use checksum in the file name. Do not " + "use the same path for several parallel processes.") +FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed " + "corpus, then merge with the initial corpus") +FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.") +FUZZER_FLAG_INT(print_new_cov_pcs, 0, "If 1, print out new covered pcs.") + diff --git a/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp b/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp new file mode 100644 index 00000000000..043fad396d5 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp @@ -0,0 +1,101 @@ +//===- FuzzerIO.cpp - IO utils. -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// IO functions. +//===----------------------------------------------------------------------===// +#include "FuzzerInternal.h" +#include <iterator> +#include <fstream> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <cstdarg> +#include <cstdio> + +namespace fuzzer { + +static 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; +} + +static std::vector<std::string> ListFilesInDir(const std::string &Dir, + long *Epoch) { + std::vector<std::string> V; + if (Epoch) { + auto E = GetEpoch(Dir); + if (*Epoch >= E) return V; + *Epoch = E; + } + DIR *D = opendir(Dir.c_str()); + if (!D) { + Printf("No such directory: %s; exiting\n", Dir.c_str()); + exit(1); + } + while (auto E = readdir(D)) { + if (E->d_type == DT_REG || E->d_type == DT_LNK) + V.push_back(E->d_name); + } + closedir(D); + return V; +} + +Unit FileToVector(const std::string &Path) { + std::ifstream T(Path); + if (!T) { + Printf("No such directory: %s; exiting\n", Path.c_str()); + exit(1); + } + return Unit((std::istreambuf_iterator<char>(T)), + std::istreambuf_iterator<char>()); +} + +std::string FileToString(const std::string &Path) { + std::ifstream T(Path); + return std::string((std::istreambuf_iterator<char>(T)), + std::istreambuf_iterator<char>()); +} + +void CopyFileToErr(const std::string &Path) { + Printf("%s", FileToString(Path).c_str()); +} + +void WriteToFile(const Unit &U, const std::string &Path) { + // Use raw C interface because this function may be called from a sig handler. + FILE *Out = fopen(Path.c_str(), "w"); + if (!Out) return; + fwrite(U.data(), sizeof(U[0]), U.size(), Out); + fclose(Out); +} + +void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, + long *Epoch) { + long E = Epoch ? *Epoch : 0; + for (auto &X : ListFilesInDir(Path, Epoch)) { + auto FilePath = DirPlusFile(Path, X); + if (Epoch && GetEpoch(FilePath) < E) continue; + V->push_back(FileToVector(FilePath)); + } +} + +std::string DirPlusFile(const std::string &DirPath, + const std::string &FileName) { + return DirPath + "/" + FileName; +} + +void Printf(const char *Fmt, ...) { + va_list ap; + va_start(ap, Fmt); + vfprintf(stderr, Fmt, ap); + va_end(ap); +} + +} // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInterface.cpp b/gnu/llvm/lib/Fuzzer/FuzzerInterface.cpp new file mode 100644 index 00000000000..bcd726fc08e --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerInterface.cpp @@ -0,0 +1,30 @@ +//===- FuzzerInterface.cpp - Mutate a test input --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Parts of public interface for libFuzzer. +//===----------------------------------------------------------------------===// + + +#include "FuzzerInterface.h" +#include "FuzzerInternal.h" + +namespace fuzzer { + +void FuzzerRandomLibc::ResetSeed(unsigned int seed) { srand(seed); } + +size_t FuzzerRandomLibc::Rand() { return rand(); } + +UserSuppliedFuzzer::UserSuppliedFuzzer(FuzzerRandomBase *Rand) + : Rand(Rand), MD(*Rand) {} + +UserSuppliedFuzzer::~UserSuppliedFuzzer() { + if (OwnRand) + delete Rand; +} + +} // namespace fuzzer. diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInterface.h b/gnu/llvm/lib/Fuzzer/FuzzerInterface.h new file mode 100644 index 00000000000..e22b27a3dd2 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerInterface.h @@ -0,0 +1,198 @@ +//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Define the interface between the Fuzzer and the library being tested. +//===----------------------------------------------------------------------===// + +// WARNING: keep the interface free of STL or any other header-based C++ lib, +// to avoid bad interactions between the code used in the fuzzer and +// the code used in the target function. + +#ifndef LLVM_FUZZER_INTERFACE_H +#define LLVM_FUZZER_INTERFACE_H + +#include <limits> +#include <cstddef> +#include <cstdint> +#include <vector> +#include <string> + +namespace fuzzer { +typedef std::vector<uint8_t> Unit; + +/// Returns an int 0. Values other than zero are reserved for future. +typedef int (*UserCallback)(const uint8_t *Data, size_t Size); +/** Simple C-like interface with a single user-supplied callback. + +Usage: + +#\code +#include "FuzzerInterface.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + DoStuffWithData(Data, Size); + return 0; +} + +// Implement your own main() or use the one from FuzzerMain.cpp. +int main(int argc, char **argv) { + InitializeMeIfNeeded(); + return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput); +} +#\endcode +*/ +int FuzzerDriver(int argc, char **argv, UserCallback Callback); + +class FuzzerRandomBase { + public: + FuzzerRandomBase(){} + virtual ~FuzzerRandomBase(){}; + virtual void ResetSeed(unsigned int seed) = 0; + // Return a random number. + virtual size_t Rand() = 0; + // Return a random number in range [0,n). + size_t operator()(size_t n) { return n ? Rand() % n : 0; } + bool RandBool() { return Rand() % 2; } +}; + +class FuzzerRandomLibc : public FuzzerRandomBase { + public: + FuzzerRandomLibc(unsigned int seed) { ResetSeed(seed); } + void ResetSeed(unsigned int seed) override; + ~FuzzerRandomLibc() override {} + size_t Rand() override; +}; + +class MutationDispatcher { + public: + MutationDispatcher(FuzzerRandomBase &Rand); + ~MutationDispatcher(); + /// Indicate that we are about to start a new sequence of mutations. + void StartMutationSequence(); + /// Print the current sequence of mutations. + void PrintMutationSequence(); + /// Mutates data by shuffling bytes. + size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by erasing a byte. + size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by inserting a byte. + size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one byte. + size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one bit. + size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Mutates data by adding a word from the manual dictionary. + size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, + size_t MaxSize); + + /// Mutates data by adding a word from the automatic dictionary. + size_t Mutate_AddWordFromAutoDictionary(uint8_t *Data, size_t Size, + size_t MaxSize); + + /// Tries to find an ASCII integer in Data, changes it to another ASCII int. + size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize); + + /// CrossOver Data with some other element of the corpus. + size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Applies one of the above mutations. + /// Returns the new size of data which could be up to MaxSize. + size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Creates a cross-over of two pieces of Data, returns its size. + size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, + size_t Size2, uint8_t *Out, size_t MaxOutSize); + + void AddWordToManualDictionary(const Unit &Word); + + void AddWordToAutoDictionary(const Unit &Word, size_t PositionHint); + void ClearAutoDictionary(); + + void SetCorpus(const std::vector<Unit> *Corpus); + + private: + FuzzerRandomBase &Rand; + struct Impl; + Impl *MDImpl; +}; + +// For backward compatibility only, deprecated. +static inline size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, + FuzzerRandomBase &Rand) { + MutationDispatcher MD(Rand); + return MD.Mutate(Data, Size, MaxSize); +} + +/** An abstract class that allows to use user-supplied mutators with libFuzzer. + +Usage: + +#\code +#include "FuzzerInterface.h" +class MyFuzzer : public fuzzer::UserSuppliedFuzzer { + public: + MyFuzzer(fuzzer::FuzzerRandomBase *Rand); + // Must define the target function. + int TargetFunction(...) { ...; return 0; } + // Optionally define the mutator. + size_t Mutate(...) { ... } + // Optionally define the CrossOver method. + size_t CrossOver(...) { ... } +}; + +int main(int argc, char **argv) { + MyFuzzer F; + fuzzer::FuzzerDriver(argc, argv, F); +} +#\endcode +*/ +class UserSuppliedFuzzer { + public: + UserSuppliedFuzzer(FuzzerRandomBase *Rand); + /// Executes the target function on 'Size' bytes of 'Data'. + virtual int TargetFunction(const uint8_t *Data, size_t Size) = 0; + virtual void StartMutationSequence() { MD.StartMutationSequence(); } + virtual void PrintMutationSequence() { MD.PrintMutationSequence(); } + virtual void SetCorpus(const std::vector<Unit> *Corpus) { + MD.SetCorpus(Corpus); + } + /// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes, + /// returns the new size of the data, which should be positive. + virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { + return MD.Mutate(Data, Size, MaxSize); + } + /// Crosses 'Data1' and 'Data2', writes up to 'MaxOutSize' bytes into Out, + /// returns the number of bytes written, which should be positive. + virtual size_t CrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize) { + return MD.CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize); + } + virtual ~UserSuppliedFuzzer(); + + FuzzerRandomBase &GetRand() { return *Rand; } + + MutationDispatcher &GetMD() { return MD; } + + private: + bool OwnRand = false; + FuzzerRandomBase *Rand; + MutationDispatcher MD; +}; + +/// Runs the fuzzing with the UserSuppliedFuzzer. +int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF); + +/// More C++-ish interface. +int FuzzerDriver(const std::vector<std::string> &Args, UserSuppliedFuzzer &USF); +int FuzzerDriver(const std::vector<std::string> &Args, UserCallback Callback); + +} // namespace fuzzer + +#endif // LLVM_FUZZER_INTERFACE_H diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInternal.h b/gnu/llvm/lib/Fuzzer/FuzzerInternal.h new file mode 100644 index 00000000000..c1e9daac980 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerInternal.h @@ -0,0 +1,207 @@ +//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Define the main class fuzzer::Fuzzer and most functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FUZZER_INTERNAL_H +#define LLVM_FUZZER_INTERNAL_H + +#include <cassert> +#include <climits> +#include <chrono> +#include <cstddef> +#include <cstdlib> +#include <string> +#include <vector> +#include <unordered_set> + +#include "FuzzerInterface.h" + +namespace fuzzer { +using namespace std::chrono; + +std::string FileToString(const std::string &Path); +Unit FileToVector(const std::string &Path); +void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, + long *Epoch); +void WriteToFile(const Unit &U, const std::string &Path); +void CopyFileToErr(const std::string &Path); +// Returns "Dir/FileName" or equivalent for the current OS. +std::string DirPlusFile(const std::string &DirPath, + const std::string &FileName); + +void Printf(const char *Fmt, ...); +void Print(const Unit &U, const char *PrintAfter = ""); +void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); +void PrintASCII(const Unit &U, const char *PrintAfter = ""); +std::string Hash(const Unit &U); +void SetTimer(int Seconds); +std::string Base64(const Unit &U); +int ExecuteCommand(const std::string &Command); + +// Private copy of SHA1 implementation. +static const int kSHA1NumBytes = 20; +// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'. +void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); + +// Changes U to contain only ASCII (isprint+isspace) characters. +// Returns true iff U has been changed. +bool ToASCII(Unit &U); +bool IsASCII(const Unit &U); + +int NumberOfCpuCores(); +int GetPid(); + +// Dictionary. + +// Parses one dictionary entry. +// If successfull, write the enty to Unit and returns true, +// otherwise returns false. +bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); +// Parses the dictionary file, fills Units, returns true iff all lines +// were parsed succesfully. +bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units); + +class Fuzzer { + public: + struct FuzzingOptions { + int Verbosity = 1; + int MaxLen = 0; + int UnitTimeoutSec = 300; + int MaxTotalTimeSec = 0; + bool DoCrossOver = true; + int MutateDepth = 5; + bool ExitOnFirst = false; + bool UseCounters = false; + bool UseIndirCalls = true; + bool UseTraces = false; + bool UseFullCoverageSet = false; + bool Reload = true; + bool ShuffleAtStartUp = true; + int PreferSmallDuringInitialShuffle = -1; + size_t MaxNumberOfRuns = ULONG_MAX; + int SyncTimeout = 600; + int ReportSlowUnits = 10; + bool OnlyASCII = false; + std::string OutputCorpus; + std::string SyncCommand; + std::string ArtifactPrefix = "./"; + std::string ExactArtifactPath; + bool SaveArtifacts = true; + bool PrintNEW = true; // Print a status line when new units are found; + bool OutputCSV = false; + bool PrintNewCovPcs = false; + }; + Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options); + void AddToCorpus(const Unit &U) { Corpus.push_back(U); } + size_t ChooseUnitIdxToMutate(); + const Unit &ChooseUnitToMutate() { return Corpus[ChooseUnitIdxToMutate()]; }; + void Loop(); + void Drill(); + void ShuffleAndMinimize(); + void InitializeTraceState(); + size_t CorpusSize() const { return Corpus.size(); } + void ReadDir(const std::string &Path, long *Epoch) { + Printf("Loading corpus: %s\n", Path.c_str()); + ReadDirToVectorOfUnits(Path.c_str(), &Corpus, Epoch); + } + void RereadOutputCorpus(); + // Save the current corpus to OutputCorpus. + void SaveCorpus(); + + size_t secondsSinceProcessStartUp() { + return duration_cast<seconds>(system_clock::now() - ProcessStartTime) + .count(); + } + + size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; } + + static void StaticAlarmCallback(); + + void ExecuteCallback(const Unit &U); + + // Merge Corpora[1:] into Corpora[0]. + void Merge(const std::vector<std::string> &Corpora); + + private: + void AlarmCallback(); + void MutateAndTestOne(); + void ReportNewCoverage(const Unit &U); + bool RunOne(const Unit &U); + void RunOneAndUpdateCorpus(Unit &U); + void WriteToOutputCorpus(const Unit &U); + void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); + void PrintStats(const char *Where, const char *End = "\n"); + void PrintStatusForNewUnit(const Unit &U); + void PrintUnitInASCII(const Unit &U, const char *PrintAfter = ""); + + void SyncCorpus(); + + size_t RecordBlockCoverage(); + size_t RecordCallerCalleeCoverage(); + void PrepareCoverageBeforeRun(); + bool CheckCoverageAfterRun(); + + + // Trace-based fuzzing: we run a unit with some kind of tracing + // enabled and record potentially useful mutations. Then + // We apply these mutations one by one to the unit and run it again. + + // Start tracing; forget all previously proposed mutations. + void StartTraceRecording(); + // Stop tracing. + void StopTraceRecording(); + + void SetDeathCallback(); + static void StaticDeathCallback(); + void DeathCallback(); + Unit CurrentUnit; + + size_t TotalNumberOfRuns = 0; + size_t TotalNumberOfExecutedTraceBasedMutations = 0; + + std::vector<Unit> Corpus; + std::unordered_set<std::string> UnitHashesAddedToCorpus; + + // For UseCounters + std::vector<uint8_t> CounterBitmap; + size_t TotalBits() { // Slow. Call it only for printing stats. + size_t Res = 0; + for (auto x : CounterBitmap) Res += __builtin_popcount(x); + return Res; + } + + UserSuppliedFuzzer &USF; + FuzzingOptions Options; + system_clock::time_point ProcessStartTime = system_clock::now(); + system_clock::time_point LastExternalSync = system_clock::now(); + system_clock::time_point UnitStartTime; + long TimeOfLongestUnitInSeconds = 0; + long EpochOfLastReadOfOutputCorpus = 0; + size_t LastRecordedBlockCoverage = 0; + size_t LastRecordedCallerCalleeCoverage = 0; + size_t LastCoveragePcBufferLen = 0; +}; + +class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer { + public: + SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, UserCallback Callback) + : UserSuppliedFuzzer(Rand), Callback(Callback) {} + + virtual int TargetFunction(const uint8_t *Data, size_t Size) override { + return Callback(Data, Size); + } + + private: + UserCallback Callback = nullptr; +}; + +}; // namespace fuzzer + +#endif // LLVM_FUZZER_INTERNAL_H diff --git a/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp b/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp new file mode 100644 index 00000000000..5237682ff24 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp @@ -0,0 +1,512 @@ +//===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Fuzzer's main loop. +//===----------------------------------------------------------------------===// + +#include "FuzzerInternal.h" +#include <algorithm> + +#if defined(__has_include) +# if __has_include(<sanitizer/coverage_interface.h>) +# include <sanitizer/coverage_interface.h> +# endif +#endif + +extern "C" { +// Re-declare some of the sanitizer functions as "weak" so that +// libFuzzer can be linked w/o the sanitizers and sanitizer-coverage +// (in which case it will complain at start-up time). +__attribute__((weak)) void __sanitizer_print_stack_trace(); +__attribute__((weak)) void __sanitizer_reset_coverage(); +__attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs(); +__attribute__((weak)) size_t __sanitizer_get_total_unique_coverage(); +__attribute__((weak)) +void __sanitizer_set_death_callback(void (*callback)(void)); +__attribute__((weak)) size_t __sanitizer_get_number_of_counters(); +__attribute__((weak)) +uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); +__attribute__((weak)) uintptr_t +__sanitizer_get_coverage_pc_buffer(uintptr_t **data); +} + +namespace fuzzer { +static const size_t kMaxUnitSizeToPrint = 256; + +static void MissingWeakApiFunction(const char *FnName) { + Printf("ERROR: %s is not defined. Exiting.\n" + "Did you use -fsanitize-coverage=... to build your code?\n", FnName); + exit(1); +} + +#define CHECK_WEAK_API_FUNCTION(fn) \ + do { \ + if (!fn) \ + MissingWeakApiFunction(#fn); \ + } while (false) + +// Only one Fuzzer per process. +static Fuzzer *F; + +Fuzzer::Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options) + : USF(USF), Options(Options) { + SetDeathCallback(); + InitializeTraceState(); + assert(!F); + F = this; +} + +void Fuzzer::SetDeathCallback() { + CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback); + __sanitizer_set_death_callback(StaticDeathCallback); +} + +void Fuzzer::PrintUnitInASCII(const Unit &U, const char *PrintAfter) { + PrintASCII(U, PrintAfter); +} + +void Fuzzer::StaticDeathCallback() { + assert(F); + F->DeathCallback(); +} + +void Fuzzer::DeathCallback() { + Printf("DEATH:\n"); + if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { + Print(CurrentUnit, "\n"); + PrintUnitInASCII(CurrentUnit, "\n"); + } + WriteUnitToFileWithPrefix(CurrentUnit, "crash-"); +} + +void Fuzzer::StaticAlarmCallback() { + assert(F); + F->AlarmCallback(); +} + +void Fuzzer::AlarmCallback() { + assert(Options.UnitTimeoutSec > 0); + size_t Seconds = + duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); + if (Seconds == 0) return; + if (Options.Verbosity >= 2) + Printf("AlarmCallback %zd\n", Seconds); + if (Seconds >= (size_t)Options.UnitTimeoutSec) { + Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); + Printf(" and the timeout value is %d (use -timeout=N to change)\n", + Options.UnitTimeoutSec); + if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { + Print(CurrentUnit, "\n"); + PrintUnitInASCII(CurrentUnit, "\n"); + } + WriteUnitToFileWithPrefix(CurrentUnit, "timeout-"); + Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), + Seconds); + if (__sanitizer_print_stack_trace) + __sanitizer_print_stack_trace(); + Printf("SUMMARY: libFuzzer: timeout\n"); + exit(1); + } +} + +void Fuzzer::PrintStats(const char *Where, const char *End) { + size_t Seconds = secondsSinceProcessStartUp(); + size_t ExecPerSec = (Seconds ? TotalNumberOfRuns / Seconds : 0); + + if (Options.OutputCSV) { + static bool csvHeaderPrinted = false; + if (!csvHeaderPrinted) { + csvHeaderPrinted = true; + Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n"); + } + Printf("%zd,%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns, + LastRecordedBlockCoverage, TotalBits(), + LastRecordedCallerCalleeCoverage, Corpus.size(), ExecPerSec, + TotalNumberOfExecutedTraceBasedMutations, Where); + } + + if (!Options.Verbosity) + return; + Printf("#%zd\t%s", TotalNumberOfRuns, Where); + if (LastRecordedBlockCoverage) + Printf(" cov: %zd", LastRecordedBlockCoverage); + if (auto TB = TotalBits()) + Printf(" bits: %zd", TB); + if (LastRecordedCallerCalleeCoverage) + Printf(" indir: %zd", LastRecordedCallerCalleeCoverage); + Printf(" units: %zd exec/s: %zd", Corpus.size(), ExecPerSec); + if (TotalNumberOfExecutedTraceBasedMutations) + Printf(" tbm: %zd", TotalNumberOfExecutedTraceBasedMutations); + Printf("%s", End); +} + +void Fuzzer::RereadOutputCorpus() { + if (Options.OutputCorpus.empty()) return; + std::vector<Unit> AdditionalCorpus; + ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, + &EpochOfLastReadOfOutputCorpus); + if (Corpus.empty()) { + Corpus = AdditionalCorpus; + return; + } + if (!Options.Reload) return; + if (Options.Verbosity >= 2) + Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); + for (auto &X : AdditionalCorpus) { + if (X.size() > (size_t)Options.MaxLen) + X.resize(Options.MaxLen); + if (UnitHashesAddedToCorpus.insert(Hash(X)).second) { + CurrentUnit.clear(); + CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end()); + if (RunOne(CurrentUnit)) { + Corpus.push_back(X); + PrintStats("RELOAD"); + } + } + } +} + +void Fuzzer::ShuffleAndMinimize() { + bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 || + (Options.PreferSmallDuringInitialShuffle == -1 && + USF.GetRand().RandBool())); + if (Options.Verbosity) + Printf("PreferSmall: %d\n", PreferSmall); + PrintStats("READ "); + std::vector<Unit> NewCorpus; + if (Options.ShuffleAtStartUp) { + std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand()); + if (PreferSmall) + std::stable_sort( + Corpus.begin(), Corpus.end(), + [](const Unit &A, const Unit &B) { return A.size() < B.size(); }); + } + Unit &U = CurrentUnit; + for (const auto &C : Corpus) { + for (size_t First = 0; First < 1; First++) { + U.clear(); + size_t Last = std::min(First + Options.MaxLen, C.size()); + U.insert(U.begin(), C.begin() + First, C.begin() + Last); + if (Options.OnlyASCII) + ToASCII(U); + if (RunOne(U)) { + NewCorpus.push_back(U); + if (Options.Verbosity >= 2) + Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size()); + } + } + } + Corpus = NewCorpus; + for (auto &X : Corpus) + UnitHashesAddedToCorpus.insert(Hash(X)); + PrintStats("INITED"); +} + +bool Fuzzer::RunOne(const Unit &U) { + UnitStartTime = system_clock::now(); + TotalNumberOfRuns++; + + PrepareCoverageBeforeRun(); + ExecuteCallback(U); + bool Res = CheckCoverageAfterRun(); + + auto UnitStopTime = system_clock::now(); + auto TimeOfUnit = + duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); + if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && + secondsSinceProcessStartUp() >= 2) + PrintStats("pulse "); + if (TimeOfUnit > TimeOfLongestUnitInSeconds && + TimeOfUnit >= Options.ReportSlowUnits) { + TimeOfLongestUnitInSeconds = TimeOfUnit; + Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); + WriteUnitToFileWithPrefix(U, "slow-unit-"); + } + return Res; +} + +void Fuzzer::RunOneAndUpdateCorpus(Unit &U) { + if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) + return; + if (Options.OnlyASCII) + ToASCII(U); + if (RunOne(U)) + ReportNewCoverage(U); +} + +void Fuzzer::ExecuteCallback(const Unit &U) { + const uint8_t *Data = U.data(); + uint8_t EmptyData; + if (!Data) + Data = &EmptyData; + int Res = USF.TargetFunction(Data, U.size()); + (void)Res; + assert(Res == 0); +} + +size_t Fuzzer::RecordBlockCoverage() { + CHECK_WEAK_API_FUNCTION(__sanitizer_get_total_unique_coverage); + uintptr_t PrevCoverage = LastRecordedBlockCoverage; + LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); + + if (PrevCoverage == LastRecordedBlockCoverage || !Options.PrintNewCovPcs) + return LastRecordedBlockCoverage; + + uintptr_t PrevBufferLen = LastCoveragePcBufferLen; + uintptr_t *CoverageBuf; + LastCoveragePcBufferLen = __sanitizer_get_coverage_pc_buffer(&CoverageBuf); + assert(CoverageBuf); + for (size_t i = PrevBufferLen; i < LastCoveragePcBufferLen; ++i) { + Printf("0x%x\n", CoverageBuf[i]); + } + + return LastRecordedBlockCoverage; +} + +size_t Fuzzer::RecordCallerCalleeCoverage() { + if (!Options.UseIndirCalls) + return 0; + if (!__sanitizer_get_total_unique_caller_callee_pairs) + return 0; + return LastRecordedCallerCalleeCoverage = + __sanitizer_get_total_unique_caller_callee_pairs(); +} + +void Fuzzer::PrepareCoverageBeforeRun() { + if (Options.UseCounters) { + size_t NumCounters = __sanitizer_get_number_of_counters(); + CounterBitmap.resize(NumCounters); + __sanitizer_update_counter_bitset_and_clear_counters(0); + } + RecordBlockCoverage(); + RecordCallerCalleeCoverage(); +} + +bool Fuzzer::CheckCoverageAfterRun() { + size_t OldCoverage = LastRecordedBlockCoverage; + size_t NewCoverage = RecordBlockCoverage(); + size_t OldCallerCalleeCoverage = LastRecordedCallerCalleeCoverage; + size_t NewCallerCalleeCoverage = RecordCallerCalleeCoverage(); + size_t NumNewBits = 0; + if (Options.UseCounters) + NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters( + CounterBitmap.data()); + return NewCoverage > OldCoverage || + NewCallerCalleeCoverage > OldCallerCalleeCoverage || NumNewBits; +} + +void Fuzzer::WriteToOutputCorpus(const Unit &U) { + if (Options.OutputCorpus.empty()) return; + std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); + WriteToFile(U, Path); + if (Options.Verbosity >= 2) + Printf("Written to %s\n", Path.c_str()); + assert(!Options.OnlyASCII || IsASCII(U)); +} + +void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { + if (!Options.SaveArtifacts) + return; + std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); + if (!Options.ExactArtifactPath.empty()) + Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. + WriteToFile(U, Path); + Printf("artifact_prefix='%s'; Test unit written to %s\n", + Options.ArtifactPrefix.c_str(), Path.c_str()); + if (U.size() <= kMaxUnitSizeToPrint) + Printf("Base64: %s\n", Base64(U).c_str()); +} + +void Fuzzer::SaveCorpus() { + if (Options.OutputCorpus.empty()) return; + for (const auto &U : Corpus) + WriteToFile(U, DirPlusFile(Options.OutputCorpus, Hash(U))); + if (Options.Verbosity) + Printf("Written corpus of %zd files to %s\n", Corpus.size(), + Options.OutputCorpus.c_str()); +} + +void Fuzzer::PrintStatusForNewUnit(const Unit &U) { + if (!Options.PrintNEW) + return; + PrintStats("NEW ", ""); + if (Options.Verbosity) { + Printf(" L: %zd ", U.size()); + USF.PrintMutationSequence(); + Printf("\n"); + } +} + +void Fuzzer::ReportNewCoverage(const Unit &U) { + Corpus.push_back(U); + UnitHashesAddedToCorpus.insert(Hash(U)); + PrintStatusForNewUnit(U); + WriteToOutputCorpus(U); + if (Options.ExitOnFirst) + exit(0); +} + +void Fuzzer::Merge(const std::vector<std::string> &Corpora) { + if (Corpora.size() <= 1) { + Printf("Merge requires two or more corpus dirs\n"); + return; + } + auto InitialCorpusDir = Corpora[0]; + ReadDir(InitialCorpusDir, nullptr); + Printf("Merge: running the initial corpus '%s' of %d units\n", + InitialCorpusDir.c_str(), Corpus.size()); + for (auto &U : Corpus) + RunOne(U); + + std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end()); + + size_t NumTried = 0; + size_t NumMerged = 0; + for (auto &C : ExtraCorpora) { + Corpus.clear(); + ReadDir(C, nullptr); + Printf("Merge: merging the extra corpus '%s' of %zd units\n", C.c_str(), + Corpus.size()); + for (auto &U : Corpus) { + NumTried++; + if (RunOne(U)) { + WriteToOutputCorpus(U); + NumMerged++; + } + } + } + Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried); +} + +void Fuzzer::MutateAndTestOne() { + auto &U = CurrentUnit; + USF.StartMutationSequence(); + + U = ChooseUnitToMutate(); + + for (int i = 0; i < Options.MutateDepth; i++) { + size_t Size = U.size(); + U.resize(Options.MaxLen); + size_t NewSize = USF.Mutate(U.data(), Size, U.size()); + assert(NewSize > 0 && "Mutator returned empty unit"); + assert(NewSize <= (size_t)Options.MaxLen && + "Mutator return overisized unit"); + U.resize(NewSize); + if (i == 0) + StartTraceRecording(); + RunOneAndUpdateCorpus(U); + StopTraceRecording(); + } +} + +// Returns an index of random unit from the corpus to mutate. +// Hypothesis: units added to the corpus last are more likely to be interesting. +// This function gives more wieght to the more recent units. +size_t Fuzzer::ChooseUnitIdxToMutate() { + size_t N = Corpus.size(); + size_t Total = (N + 1) * N / 2; + size_t R = USF.GetRand()(Total); + size_t IdxBeg = 0, IdxEnd = N; + // Binary search. + while (IdxEnd - IdxBeg >= 2) { + size_t Idx = IdxBeg + (IdxEnd - IdxBeg) / 2; + if (R > (Idx + 1) * Idx / 2) + IdxBeg = Idx; + else + IdxEnd = Idx; + } + assert(IdxBeg < N); + return IdxBeg; +} + +// Experimental search heuristic: drilling. +// - Read, shuffle, execute and minimize the corpus. +// - Choose one random unit. +// - Reset the coverage. +// - Start fuzzing as if the chosen unit was the only element of the corpus. +// - When done, reset the coverage again. +// - Merge the newly created corpus into the original one. +void Fuzzer::Drill() { + // The corpus is already read, shuffled, and minimized. + assert(!Corpus.empty()); + Options.PrintNEW = false; // Don't print NEW status lines when drilling. + + Unit U = ChooseUnitToMutate(); + + CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage); + __sanitizer_reset_coverage(); + + std::vector<Unit> SavedCorpus; + SavedCorpus.swap(Corpus); + Corpus.push_back(U); + assert(Corpus.size() == 1); + RunOne(U); + PrintStats("DRILL "); + std::string SavedOutputCorpusPath; // Don't write new units while drilling. + SavedOutputCorpusPath.swap(Options.OutputCorpus); + Loop(); + + __sanitizer_reset_coverage(); + + PrintStats("REINIT"); + SavedOutputCorpusPath.swap(Options.OutputCorpus); + for (auto &U : SavedCorpus) { + CurrentUnit = U; + RunOne(U); + } + PrintStats("MERGE "); + Options.PrintNEW = true; + size_t NumMerged = 0; + for (auto &U : Corpus) { + CurrentUnit = U; + if (RunOne(U)) { + PrintStatusForNewUnit(U); + NumMerged++; + WriteToOutputCorpus(U); + } + } + PrintStats("MERGED"); + if (NumMerged && Options.Verbosity) + Printf("Drilling discovered %zd new units\n", NumMerged); +} + +void Fuzzer::Loop() { + system_clock::time_point LastCorpusReload = system_clock::now(); + if (Options.DoCrossOver) + USF.SetCorpus(&Corpus); + while (true) { + SyncCorpus(); + auto Now = system_clock::now(); + if (duration_cast<seconds>(Now - LastCorpusReload).count()) { + RereadOutputCorpus(); + LastCorpusReload = Now; + } + if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) + break; + if (Options.MaxTotalTimeSec > 0 && + secondsSinceProcessStartUp() > + static_cast<size_t>(Options.MaxTotalTimeSec)) + break; + // Perform several mutations and runs. + MutateAndTestOne(); + } + + PrintStats("DONE ", "\n"); +} + +void Fuzzer::SyncCorpus() { + if (Options.SyncCommand.empty() || Options.OutputCorpus.empty()) return; + auto Now = system_clock::now(); + if (duration_cast<seconds>(Now - LastExternalSync).count() < + Options.SyncTimeout) + return; + LastExternalSync = Now; + ExecuteCommand(Options.SyncCommand + " " + Options.OutputCorpus); +} + +} // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp b/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp new file mode 100644 index 00000000000..c5af5b05909 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp @@ -0,0 +1,20 @@ +//===- FuzzerMain.cpp - main() function and flags -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// main() and flags. +//===----------------------------------------------------------------------===// + +#include "FuzzerInterface.h" +#include "FuzzerInternal.h" + +// This function should be defined by the user. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int main(int argc, char **argv) { + return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput); +} diff --git a/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp b/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp new file mode 100644 index 00000000000..30e5b43c083 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp @@ -0,0 +1,278 @@ +//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Mutate a test input. +//===----------------------------------------------------------------------===// + +#include <cstring> + +#include "FuzzerInternal.h" + +#include <algorithm> + +namespace fuzzer { + +struct Mutator { + size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); + const char *Name; +}; + +struct DictionaryEntry { + Unit Word; + size_t PositionHint; +}; + +struct MutationDispatcher::Impl { + std::vector<DictionaryEntry> ManualDictionary; + std::vector<DictionaryEntry> AutoDictionary; + std::vector<Mutator> Mutators; + std::vector<Mutator> CurrentMutatorSequence; + std::vector<DictionaryEntry> CurrentDictionaryEntrySequence; + const std::vector<Unit> *Corpus = nullptr; + FuzzerRandomBase &Rand; + + void Add(Mutator M) { Mutators.push_back(M); } + Impl(FuzzerRandomBase &Rand) : Rand(Rand) { + Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"}); + Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"}); + Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}); + Add({&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}); + Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}); + Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}); + Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"}); + Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary, + "AddFromManualDict"}); + Add({&MutationDispatcher::Mutate_AddWordFromAutoDictionary, + "AddFromAutoDict"}); + } + void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; } + size_t AddWordFromDictionary(const std::vector<DictionaryEntry> &D, + uint8_t *Data, size_t Size, size_t MaxSize); +}; + +static char FlipRandomBit(char X, FuzzerRandomBase &Rand) { + int Bit = Rand(8); + char Mask = 1 << Bit; + char R; + if (X & (1 << Bit)) + R = X & ~Mask; + else + R = X | Mask; + assert(R != X); + return R; +} + +static char RandCh(FuzzerRandomBase &Rand) { + if (Rand.RandBool()) return Rand(256); + const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~."; + return Special[Rand(sizeof(Special) - 1)]; +} + +size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, + size_t MaxSize) { + assert(Size); + 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::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, + Rand); + return Size; +} + +size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size, + size_t MaxSize) { + assert(Size); + if (Size == 1) return 0; + size_t Idx = Rand(Size); + // Erase Data[Idx]. + memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1); + return Size - 1; +} + +size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, + size_t MaxSize) { + if (Size == MaxSize) return 0; + size_t Idx = Rand(Size + 1); + // Insert new value at Data[Idx]. + memmove(Data + Idx + 1, Data + Idx, Size - Idx); + Data[Idx] = RandCh(Rand); + return Size + 1; +} + +size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, + size_t MaxSize) { + size_t Idx = Rand(Size); + Data[Idx] = RandCh(Rand); + return Size; +} + +size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, + size_t MaxSize) { + size_t Idx = Rand(Size); + Data[Idx] = FlipRandomBit(Data[Idx], Rand); + return Size; +} + +size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, + size_t Size, + size_t MaxSize) { + return MDImpl->AddWordFromDictionary(MDImpl->ManualDictionary, Data, Size, + MaxSize); +} + +size_t MutationDispatcher::Mutate_AddWordFromAutoDictionary(uint8_t *Data, + size_t Size, + size_t MaxSize) { + return MDImpl->AddWordFromDictionary(MDImpl->AutoDictionary, Data, Size, + MaxSize); +} + +size_t MutationDispatcher::Impl::AddWordFromDictionary( + const std::vector<DictionaryEntry> &D, uint8_t *Data, size_t Size, + size_t MaxSize) { + if (D.empty()) return 0; + const DictionaryEntry &DE = D[Rand(D.size())]; + const Unit &Word = DE.Word; + size_t PositionHint = DE.PositionHint; + bool UsePositionHint = PositionHint != std::numeric_limits<size_t>::max() && + PositionHint + Word.size() < Size && Rand.RandBool(); + if (Rand.RandBool()) { // Insert Word. + if (Size + Word.size() > MaxSize) return 0; + size_t Idx = UsePositionHint ? PositionHint : Rand(Size + 1); + memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx); + memcpy(Data + Idx, Word.data(), Word.size()); + Size += Word.size(); + } else { // Overwrite some bytes with Word. + if (Word.size() > Size) return 0; + size_t Idx = UsePositionHint ? PositionHint : Rand(Size - Word.size()); + memcpy(Data + Idx, Word.data(), Word.size()); + } + CurrentDictionaryEntrySequence.push_back(DE); + return Size; +} + +size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, + size_t MaxSize) { + size_t B = Rand(Size); + while (B < Size && !isdigit(Data[B])) B++; + if (B == Size) return 0; + size_t E = B; + while (E < Size && isdigit(Data[E])) E++; + assert(B < E); + // now we have digits in [B, E). + // strtol and friends don't accept non-zero-teminated data, parse it manually. + uint64_t Val = Data[B] - '0'; + for (size_t i = B + 1; i < E; i++) + Val = Val * 10 + Data[i] - '0'; + + // Mutate the integer value. + switch(Rand(5)) { + case 0: Val++; break; + case 1: Val--; break; + case 2: Val /= 2; break; + case 3: Val *= 2; break; + case 4: Val = Rand(Val * Val); break; + default: assert(0); + } + // Just replace the bytes with the new ones, don't bother moving bytes. + for (size_t i = B; i < E; i++) { + size_t Idx = E + B - i - 1; + assert(Idx >= B && Idx < E); + Data[Idx] = (Val % 10) + '0'; + Val /= 10; + } + return Size; +} + +size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, + size_t MaxSize) { + auto Corpus = MDImpl->Corpus; + 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; + Unit U(MaxSize); + size_t NewSize = + CrossOver(Data, Size, Other.data(), Other.size(), U.data(), U.size()); + assert(NewSize > 0 && "CrossOver returned empty unit"); + assert(NewSize <= MaxSize && "CrossOver returned overisized unit"); + memcpy(Data, U.data(), NewSize); + return NewSize; +} + +void MutationDispatcher::StartMutationSequence() { + MDImpl->CurrentMutatorSequence.clear(); + MDImpl->CurrentDictionaryEntrySequence.clear(); +} + +void MutationDispatcher::PrintMutationSequence() { + Printf("MS: %zd ", MDImpl->CurrentMutatorSequence.size()); + for (auto M : MDImpl->CurrentMutatorSequence) + Printf("%s-", M.Name); + if (!MDImpl->CurrentDictionaryEntrySequence.empty()) { + Printf(" DE: "); + for (auto DE : MDImpl->CurrentDictionaryEntrySequence) { + Printf("\""); + PrintASCII(DE.Word, "\"-"); + } + } +} + +// Mutates Data in place, returns new size. +size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { + assert(MaxSize > 0); + assert(Size <= MaxSize); + if (Size == 0) { + for (size_t i = 0; i < MaxSize; i++) + Data[i] = RandCh(Rand); + return MaxSize; + } + assert(Size > 0); + // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), + // in which case they will return 0. + // Try several times before returning un-mutated data. + for (int Iter = 0; Iter < 10; Iter++) { + size_t MutatorIdx = Rand(MDImpl->Mutators.size()); + auto M = MDImpl->Mutators[MutatorIdx]; + size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); + if (NewSize) { + MDImpl->CurrentMutatorSequence.push_back(M); + return NewSize; + } + } + return Size; +} + +void MutationDispatcher::SetCorpus(const std::vector<Unit> *Corpus) { + MDImpl->SetCorpus(Corpus); +} + +void MutationDispatcher::AddWordToManualDictionary(const Unit &Word) { + MDImpl->ManualDictionary.push_back( + {Word, std::numeric_limits<size_t>::max()}); +} + +void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word, + size_t PositionHint) { + static const size_t kMaxAutoDictSize = 1 << 14; + if (MDImpl->AutoDictionary.size() >= kMaxAutoDictSize) return; + MDImpl->AutoDictionary.push_back({Word, PositionHint}); +} + +void MutationDispatcher::ClearAutoDictionary() { + MDImpl->AutoDictionary.clear(); +} + +MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) { + MDImpl = new Impl(Rand); +} + +MutationDispatcher::~MutationDispatcher() { delete MDImpl; } + +} // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp b/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp new file mode 100644 index 00000000000..b42a04854cd --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp @@ -0,0 +1,202 @@ +//===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This code is taken from public domain +// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c) +// and modified by adding anonymous namespace, adding an interface +// function fuzzer::ComputeSHA1() and removing unnecessary code. +// +// lib/Fuzzer can not use SHA1 implementation from openssl because +// openssl may not be available and because we may be fuzzing openssl itself. +// For the same reason we do not want to depend on SHA1 from LLVM tree. +//===----------------------------------------------------------------------===// + +#include "FuzzerInternal.h" + +/* This code is public-domain - it is based on libcrypt + * placed in the public domain by Wei Dai and other contributors. + */ + +#include <stdint.h> +#include <string.h> + +namespace { // Added for LibFuzzer + +#ifdef __BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +#elif defined __LITTLE_ENDIAN__ +/* override */ +#elif defined __BYTE_ORDER +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +# endif +#else // ! defined __LITTLE_ENDIAN__ +# include <endian.h> // machine/endian.h +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +# endif +#endif + + +/* header */ + +#define HASH_LENGTH 20 +#define BLOCK_LENGTH 64 + +typedef struct sha1nfo { + uint32_t buffer[BLOCK_LENGTH/4]; + uint32_t state[HASH_LENGTH/4]; + uint32_t byteCount; + uint8_t bufferOffset; + uint8_t keyBuffer[BLOCK_LENGTH]; + uint8_t innerHash[HASH_LENGTH]; +} sha1nfo; + +/* public API - prototypes - TODO: doxygen*/ + +/** + */ +void sha1_init(sha1nfo *s); +/** + */ +void sha1_writebyte(sha1nfo *s, uint8_t data); +/** + */ +void sha1_write(sha1nfo *s, const char *data, size_t len); +/** + */ +uint8_t* sha1_result(sha1nfo *s); + + +/* code */ +#define SHA1_K0 0x5a827999 +#define SHA1_K20 0x6ed9eba1 +#define SHA1_K40 0x8f1bbcdc +#define SHA1_K60 0xca62c1d6 + +void sha1_init(sha1nfo *s) { + s->state[0] = 0x67452301; + s->state[1] = 0xefcdab89; + s->state[2] = 0x98badcfe; + s->state[3] = 0x10325476; + s->state[4] = 0xc3d2e1f0; + s->byteCount = 0; + s->bufferOffset = 0; +} + +uint32_t sha1_rol32(uint32_t number, uint8_t bits) { + return ((number << bits) | (number >> (32-bits))); +} + +void sha1_hashBlock(sha1nfo *s) { + uint8_t i; + uint32_t a,b,c,d,e,t; + + a=s->state[0]; + b=s->state[1]; + c=s->state[2]; + d=s->state[3]; + e=s->state[4]; + for (i=0; i<80; i++) { + if (i>=16) { + t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15]; + s->buffer[i&15] = sha1_rol32(t,1); + } + if (i<20) { + t = (d ^ (b & (c ^ d))) + SHA1_K0; + } else if (i<40) { + t = (b ^ c ^ d) + SHA1_K20; + } else if (i<60) { + t = ((b & c) | (d & (b | c))) + SHA1_K40; + } else { + t = (b ^ c ^ d) + SHA1_K60; + } + t+=sha1_rol32(a,5) + e + s->buffer[i&15]; + e=d; + d=c; + c=sha1_rol32(b,30); + b=a; + a=t; + } + s->state[0] += a; + s->state[1] += b; + s->state[2] += c; + s->state[3] += d; + s->state[4] += e; +} + +void sha1_addUncounted(sha1nfo *s, uint8_t data) { + uint8_t * const b = (uint8_t*) s->buffer; +#ifdef SHA_BIG_ENDIAN + b[s->bufferOffset] = data; +#else + b[s->bufferOffset ^ 3] = data; +#endif + s->bufferOffset++; + if (s->bufferOffset == BLOCK_LENGTH) { + sha1_hashBlock(s); + s->bufferOffset = 0; + } +} + +void sha1_writebyte(sha1nfo *s, uint8_t data) { + ++s->byteCount; + sha1_addUncounted(s, data); +} + +void sha1_write(sha1nfo *s, const char *data, size_t len) { + for (;len--;) sha1_writebyte(s, (uint8_t) *data++); +} + +void sha1_pad(sha1nfo *s) { + // Implement SHA-1 padding (fips180-2 §5.1.1) + + // Pad with 0x80 followed by 0x00 until the end of the block + sha1_addUncounted(s, 0x80); + while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); + + // Append length in the last 8 bytes + sha1_addUncounted(s, 0); // We're only using 32 bit lengths + sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths + sha1_addUncounted(s, 0); // So zero pad the top bits + sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 + sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as + sha1_addUncounted(s, s->byteCount >> 13); // byte. + sha1_addUncounted(s, s->byteCount >> 5); + sha1_addUncounted(s, s->byteCount << 3); +} + +uint8_t* sha1_result(sha1nfo *s) { + // Pad to complete the last block + sha1_pad(s); + +#ifndef SHA_BIG_ENDIAN + // Swap byte order back + int i; + for (i=0; i<5; i++) { + s->state[i]= + (((s->state[i])<<24)& 0xff000000) + | (((s->state[i])<<8) & 0x00ff0000) + | (((s->state[i])>>8) & 0x0000ff00) + | (((s->state[i])>>24)& 0x000000ff); + } +#endif + + // Return pointer to hash (20 characters) + return (uint8_t*) s->state; +} + +} // namespace; Added for LibFuzzer + +// The rest is added for LibFuzzer +void fuzzer::ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { + sha1nfo s; + sha1_init(&s); + sha1_write(&s, (const char*)Data, Len); + memcpy(Out, sha1_result(&s), HASH_LENGTH); +} diff --git a/gnu/llvm/lib/Fuzzer/FuzzerSanitizerOptions.cpp b/gnu/llvm/lib/Fuzzer/FuzzerSanitizerOptions.cpp new file mode 100644 index 00000000000..b2f20dd4ddf --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerSanitizerOptions.cpp @@ -0,0 +1,19 @@ +//===- FuzzerSanitizerOptions.cpp - default flags for sanitizers ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Set default options for sanitizers while running the fuzzer. +// Options reside in a separate file, so if we don't want to set the default +// options we simply do not link this file in. +// ASAN options: +// * don't dump the coverage to disk. +// * enable coverage by default. +// * enable handle_abort. +//===----------------------------------------------------------------------===// +extern "C" const char *__asan_default_options() { + return "coverage_pcs=0:coverage=1:handle_abort=1"; +} diff --git a/gnu/llvm/lib/Fuzzer/FuzzerTraceState.cpp b/gnu/llvm/lib/Fuzzer/FuzzerTraceState.cpp new file mode 100644 index 00000000000..b2006fa3aa4 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerTraceState.cpp @@ -0,0 +1,604 @@ +//===- FuzzerTraceState.cpp - Trace-based fuzzer mutator ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This file implements a mutation algorithm based on instruction traces and +// on taint analysis feedback from DFSan. +// +// Instruction traces are special hooks inserted by the compiler around +// interesting instructions. Currently supported traces: +// * __sanitizer_cov_trace_cmp -- inserted before every ICMP instruction, +// receives the type, size and arguments of ICMP. +// +// Every time a traced event is intercepted we analyse the data involved +// in the event and suggest a mutation for future executions. +// For example if 4 bytes of data that derive from input bytes {4,5,6,7} +// are compared with a constant 12345, +// we try to insert 12345, 12344, 12346 into bytes +// {4,5,6,7} of the next fuzzed inputs. +// +// The fuzzer can work only with the traces, or with both traces and DFSan. +// +// DataFlowSanitizer (DFSan) is a tool for +// generalised dynamic data flow (taint) analysis: +// http://clang.llvm.org/docs/DataFlowSanitizer.html . +// +// The approach with DFSan-based fuzzing has some similarity to +// "Taint-based Directed Whitebox Fuzzing" +// by Vijay Ganesh & Tim Leek & Martin Rinard: +// http://dspace.mit.edu/openaccess-disseminate/1721.1/59320, +// but it uses a full blown LLVM IR taint analysis and separate instrumentation +// to analyze all of the "attack points" at once. +// +// Workflow with DFSan: +// * lib/Fuzzer/Fuzzer*.cpp is compiled w/o any instrumentation. +// * The code under test is compiled with DFSan *and* with instruction traces. +// * Every call to HOOK(a,b) is replaced by DFSan with +// __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK +// gets all the taint labels for the arguments. +// * At the Fuzzer startup we assign a unique DFSan label +// to every byte of the input string (Fuzzer::CurrentUnit) so that for any +// chunk of data we know which input bytes it has derived from. +// * The __dfsw_* functions (implemented in this file) record the +// parameters (i.e. the application data and the corresponding taint labels) +// in a global state. +// +// Parts of this code will not function when DFSan is not linked in. +// Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer +// we redeclare the dfsan_* interface functions as weak and check if they +// are nullptr before calling. +// If this approach proves to be useful we may add attribute(weak) to the +// dfsan declarations in dfsan_interface.h +// +// This module is in the "proof of concept" stage. +// It is capable of solving only the simplest puzzles +// like test/dfsan/DFSanSimpleCmpTest.cpp. +//===----------------------------------------------------------------------===// + +/* Example of manual usage (-fsanitize=dataflow is optional): +( + cd $LLVM/lib/Fuzzer/ + clang -fPIC -c -g -O2 -std=c++11 Fuzzer*.cpp + clang++ -O0 -std=c++11 -fsanitize-coverage=edge,trace-cmp \ + -fsanitize=dataflow \ + test/SimpleCmpTest.cpp Fuzzer*.o + ./a.out -use_traces=1 +) +*/ + +#include "FuzzerDFSan.h" +#include "FuzzerInternal.h" + +#include <algorithm> +#include <cstring> +#include <thread> +#include <map> + +#if !LLVM_FUZZER_SUPPORTS_DFSAN +// Stubs for dfsan for platforms where dfsan does not exist and weak +// functions don't work. +extern "C" { +dfsan_label dfsan_create_label(const char *desc, void *userdata) { return 0; } +void dfsan_set_label(dfsan_label label, void *addr, size_t size) {} +void dfsan_add_label(dfsan_label label, void *addr, size_t size) {} +const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label) { + return nullptr; +} +dfsan_label dfsan_read_label(const void *addr, size_t size) { return 0; } +} // extern "C" +#endif // !LLVM_FUZZER_SUPPORTS_DFSAN + +namespace fuzzer { + +// These values are copied from include/llvm/IR/InstrTypes.h. +// We do not include the LLVM headers here to remain independent. +// If these values ever change, an assertion in ComputeCmp will fail. +enum Predicate { + ICMP_EQ = 32, ///< equal + ICMP_NE = 33, ///< not equal + ICMP_UGT = 34, ///< unsigned greater than + ICMP_UGE = 35, ///< unsigned greater or equal + ICMP_ULT = 36, ///< unsigned less than + ICMP_ULE = 37, ///< unsigned less or equal + ICMP_SGT = 38, ///< signed greater than + ICMP_SGE = 39, ///< signed greater or equal + ICMP_SLT = 40, ///< signed less than + ICMP_SLE = 41, ///< signed less or equal +}; + +template <class U, class S> +bool ComputeCmp(size_t CmpType, U Arg1, U Arg2) { + switch(CmpType) { + case ICMP_EQ : return Arg1 == Arg2; + case ICMP_NE : return Arg1 != Arg2; + case ICMP_UGT: return Arg1 > Arg2; + case ICMP_UGE: return Arg1 >= Arg2; + case ICMP_ULT: return Arg1 < Arg2; + case ICMP_ULE: return Arg1 <= Arg2; + case ICMP_SGT: return (S)Arg1 > (S)Arg2; + case ICMP_SGE: return (S)Arg1 >= (S)Arg2; + case ICMP_SLT: return (S)Arg1 < (S)Arg2; + case ICMP_SLE: return (S)Arg1 <= (S)Arg2; + default: assert(0 && "unsupported CmpType"); + } + return false; +} + +static bool ComputeCmp(size_t CmpSize, size_t CmpType, uint64_t Arg1, + uint64_t Arg2) { + if (CmpSize == 8) return ComputeCmp<uint64_t, int64_t>(CmpType, Arg1, Arg2); + if (CmpSize == 4) return ComputeCmp<uint32_t, int32_t>(CmpType, Arg1, Arg2); + if (CmpSize == 2) return ComputeCmp<uint16_t, int16_t>(CmpType, Arg1, Arg2); + if (CmpSize == 1) return ComputeCmp<uint8_t, int8_t>(CmpType, Arg1, Arg2); + // Other size, == + if (CmpType == ICMP_EQ) return Arg1 == Arg2; + // assert(0 && "unsupported cmp and type size combination"); + return true; +} + +// As a simplification we use the range of input bytes instead of a set of input +// bytes. +struct LabelRange { + uint16_t Beg, End; // Range is [Beg, End), thus Beg==End is an empty range. + + LabelRange(uint16_t Beg = 0, uint16_t End = 0) : Beg(Beg), End(End) {} + + static LabelRange Join(LabelRange LR1, LabelRange LR2) { + if (LR1.Beg == LR1.End) return LR2; + if (LR2.Beg == LR2.End) return LR1; + return {std::min(LR1.Beg, LR2.Beg), std::max(LR1.End, LR2.End)}; + } + LabelRange &Join(LabelRange LR) { + return *this = Join(*this, LR); + } + static LabelRange Singleton(const dfsan_label_info *LI) { + uint16_t Idx = (uint16_t)(uintptr_t)LI->userdata; + assert(Idx > 0); + return {(uint16_t)(Idx - 1), Idx}; + } +}; + +// For now, very simple: put Size bytes of Data at position Pos. +struct TraceBasedMutation { + static const size_t kMaxSize = 28; + uint32_t Pos : 24; + uint32_t Size : 8; + uint8_t Data[kMaxSize]; +}; + +const size_t TraceBasedMutation::kMaxSize; + +class TraceState { + public: + TraceState(UserSuppliedFuzzer &USF, + const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit) + : USF(USF), Options(Options), CurrentUnit(CurrentUnit) { + // Current trace collection is not thread-friendly and it probably + // does not have to be such, but at least we should not crash in presence + // of threads. So, just ignore all traces coming from all threads but one. + IsMyThread = true; + } + + LabelRange GetLabelRange(dfsan_label L); + void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, + uint64_t Arg1, uint64_t Arg2, dfsan_label L1, + dfsan_label L2); + void DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1, + const uint8_t *Data2, dfsan_label L1, + dfsan_label L2); + void DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, uint64_t Val, + size_t NumCases, uint64_t *Cases, dfsan_label L); + void TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, + uint64_t Arg1, uint64_t Arg2); + void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, + const uint8_t *Data2); + + void TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val, + size_t NumCases, uint64_t *Cases); + int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, + size_t DataSize); + int TryToAddDesiredData(const uint8_t *PresentData, + const uint8_t *DesiredData, size_t DataSize); + + void StartTraceRecording() { + if (!Options.UseTraces) return; + RecordingTraces = true; + NumMutations = 0; + USF.GetMD().ClearAutoDictionary(); + } + + void StopTraceRecording() { + if (!RecordingTraces) return; + RecordingTraces = false; + for (size_t i = 0; i < NumMutations; i++) { + auto &M = Mutations[i]; + Unit U(M.Data, M.Data + M.Size); + if (Options.Verbosity >= 2) { + AutoDictUnitCounts[U]++; + AutoDictAdds++; + if ((AutoDictAdds & (AutoDictAdds - 1)) == 0) { + typedef std::pair<size_t, Unit> CU; + std::vector<CU> CountedUnits; + for (auto &I : AutoDictUnitCounts) + CountedUnits.push_back(std::make_pair(I.second, I.first)); + std::sort(CountedUnits.begin(), CountedUnits.end(), + [](const CU &a, const CU &b) { return a.first > b.first; }); + Printf("AutoDict:\n"); + for (auto &I : CountedUnits) { + Printf(" %zd ", I.first); + PrintASCII(I.second); + Printf("\n"); + } + } + } + USF.GetMD().AddWordToAutoDictionary(U, M.Pos); + } + } + + void AddMutation(uint32_t Pos, uint32_t Size, const uint8_t *Data) { + if (NumMutations >= kMaxMutations) return; + assert(Size <= TraceBasedMutation::kMaxSize); + auto &M = Mutations[NumMutations++]; + M.Pos = Pos; + M.Size = Size; + memcpy(M.Data, Data, Size); + } + + void AddMutation(uint32_t Pos, uint32_t Size, uint64_t Data) { + assert(Size <= sizeof(Data)); + AddMutation(Pos, Size, reinterpret_cast<uint8_t*>(&Data)); + } + + private: + bool IsTwoByteData(uint64_t Data) { + int64_t Signed = static_cast<int64_t>(Data); + Signed >>= 16; + return Signed == 0 || Signed == -1L; + } + bool RecordingTraces = false; + static const size_t kMaxMutations = 1 << 16; + size_t NumMutations; + TraceBasedMutation Mutations[kMaxMutations]; + LabelRange LabelRanges[1 << (sizeof(dfsan_label) * 8)]; + UserSuppliedFuzzer &USF; + const Fuzzer::FuzzingOptions &Options; + const Unit &CurrentUnit; + std::map<Unit, size_t> AutoDictUnitCounts; + size_t AutoDictAdds = 0; + static thread_local bool IsMyThread; +}; + +thread_local bool TraceState::IsMyThread; + +LabelRange TraceState::GetLabelRange(dfsan_label L) { + LabelRange &LR = LabelRanges[L]; + if (LR.Beg < LR.End || L == 0) + return LR; + const dfsan_label_info *LI = dfsan_get_label_info(L); + if (LI->l1 || LI->l2) + return LR = LabelRange::Join(GetLabelRange(LI->l1), GetLabelRange(LI->l2)); + return LR = LabelRange::Singleton(LI); +} + +void TraceState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, + uint64_t Arg1, uint64_t Arg2, dfsan_label L1, + dfsan_label L2) { + assert(ReallyHaveDFSan()); + if (!RecordingTraces || !IsMyThread) return; + if (L1 == 0 && L2 == 0) + return; // Not actionable. + if (L1 != 0 && L2 != 0) + return; // Probably still actionable. + bool Res = ComputeCmp(CmpSize, CmpType, Arg1, Arg2); + uint64_t Data = L1 ? Arg2 : Arg1; + LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2); + + for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) { + AddMutation(Pos, CmpSize, Data); + AddMutation(Pos, CmpSize, Data + 1); + AddMutation(Pos, CmpSize, Data - 1); + } + + if (CmpSize > LR.End - LR.Beg) + AddMutation(LR.Beg, (unsigned)(LR.End - LR.Beg), Data); + + + if (Options.Verbosity >= 3) + Printf("DFSanCmpCallback: PC %lx S %zd T %zd A1 %llx A2 %llx R %d L1 %d L2 " + "%d MU %zd\n", + PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, NumMutations); +} + +void TraceState::DFSanMemcmpCallback(size_t CmpSize, const uint8_t *Data1, + const uint8_t *Data2, dfsan_label L1, + dfsan_label L2) { + + assert(ReallyHaveDFSan()); + if (!RecordingTraces || !IsMyThread) return; + if (L1 == 0 && L2 == 0) + return; // Not actionable. + if (L1 != 0 && L2 != 0) + return; // Probably still actionable. + + const uint8_t *Data = L1 ? Data2 : Data1; + LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2); + for (size_t Pos = LR.Beg; Pos + CmpSize <= LR.End; Pos++) { + AddMutation(Pos, CmpSize, Data); + if (Options.Verbosity >= 3) + Printf("DFSanMemcmpCallback: Pos %d Size %d\n", Pos, CmpSize); + } +} + +void TraceState::DFSanSwitchCallback(uint64_t PC, size_t ValSizeInBits, + uint64_t Val, size_t NumCases, + uint64_t *Cases, dfsan_label L) { + assert(ReallyHaveDFSan()); + if (!RecordingTraces || !IsMyThread) return; + if (!L) return; // Not actionable. + LabelRange LR = GetLabelRange(L); + size_t ValSize = ValSizeInBits / 8; + bool TryShort = IsTwoByteData(Val); + for (size_t i = 0; i < NumCases; i++) + TryShort &= IsTwoByteData(Cases[i]); + + for (size_t Pos = LR.Beg; Pos + ValSize <= LR.End; Pos++) + for (size_t i = 0; i < NumCases; i++) + AddMutation(Pos, ValSize, Cases[i]); + + if (TryShort) + for (size_t Pos = LR.Beg; Pos + 2 <= LR.End; Pos++) + for (size_t i = 0; i < NumCases; i++) + AddMutation(Pos, 2, Cases[i]); + + if (Options.Verbosity >= 3) + Printf("DFSanSwitchCallback: PC %lx Val %zd SZ %zd # %zd L %d: {%d, %d} " + "TryShort %d\n", + PC, Val, ValSize, NumCases, L, LR.Beg, LR.End, TryShort); +} + +int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData, + size_t DataSize) { + int Res = 0; + const uint8_t *Beg = CurrentUnit.data(); + const uint8_t *End = Beg + CurrentUnit.size(); + for (const uint8_t *Cur = Beg; Cur < End; Cur++) { + Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize); + if (!Cur) + break; + size_t Pos = Cur - Beg; + assert(Pos < CurrentUnit.size()); + AddMutation(Pos, DataSize, DesiredData); + AddMutation(Pos, DataSize, DesiredData + 1); + AddMutation(Pos, DataSize, DesiredData - 1); + Res++; + } + return Res; +} + +int TraceState::TryToAddDesiredData(const uint8_t *PresentData, + const uint8_t *DesiredData, + size_t DataSize) { + int Res = 0; + const uint8_t *Beg = CurrentUnit.data(); + const uint8_t *End = Beg + CurrentUnit.size(); + for (const uint8_t *Cur = Beg; Cur < End; Cur++) { + Cur = (uint8_t *)memmem(Cur, End - Cur, PresentData, DataSize); + if (!Cur) + break; + size_t Pos = Cur - Beg; + assert(Pos < CurrentUnit.size()); + AddMutation(Pos, DataSize, DesiredData); + Res++; + } + return Res; +} + +void TraceState::TraceCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, + uint64_t Arg1, uint64_t Arg2) { + if (!RecordingTraces || !IsMyThread) return; + if ((CmpType == ICMP_EQ || CmpType == ICMP_NE) && Arg1 == Arg2) + return; // No reason to mutate. + int Added = 0; + Added += TryToAddDesiredData(Arg1, Arg2, CmpSize); + Added += TryToAddDesiredData(Arg2, Arg1, CmpSize); + if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) { + Added += TryToAddDesiredData(Arg1, Arg2, 2); + Added += TryToAddDesiredData(Arg2, Arg1, 2); + } + if (Options.Verbosity >= 3 && Added) + Printf("TraceCmp %zd/%zd: %p %zd %zd\n", CmpSize, CmpType, PC, Arg1, Arg2); +} + +void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1, + const uint8_t *Data2) { + if (!RecordingTraces || !IsMyThread) return; + CmpSize = std::min(CmpSize, TraceBasedMutation::kMaxSize); + int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize); + int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize); + if ((Added1 || Added2) && Options.Verbosity >= 3) { + Printf("MemCmp Added %d%d: ", Added1, Added2); + if (Added1) PrintASCII(Data1, CmpSize); + if (Added2) PrintASCII(Data2, CmpSize); + Printf("\n"); + } +} + +void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, + uint64_t Val, size_t NumCases, + uint64_t *Cases) { + if (!RecordingTraces || !IsMyThread) return; + size_t ValSize = ValSizeInBits / 8; + bool TryShort = IsTwoByteData(Val); + for (size_t i = 0; i < NumCases; i++) + TryShort &= IsTwoByteData(Cases[i]); + + if (Options.Verbosity >= 3) + Printf("TraceSwitch: %p %zd # %zd; TryShort %d\n", PC, Val, NumCases, + TryShort); + + for (size_t i = 0; i < NumCases; i++) { + TryToAddDesiredData(Val, Cases[i], ValSize); + if (TryShort) + TryToAddDesiredData(Val, Cases[i], 2); + } +} + +static TraceState *TS; + +void Fuzzer::StartTraceRecording() { + if (!TS) return; + if (ReallyHaveDFSan()) + for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) + dfsan_set_label(i + 1, &CurrentUnit[i], 1); + TS->StartTraceRecording(); +} + +void Fuzzer::StopTraceRecording() { + if (!TS) return; + TS->StopTraceRecording(); +} + +void Fuzzer::InitializeTraceState() { + if (!Options.UseTraces) return; + TS = new TraceState(USF, Options, CurrentUnit); + CurrentUnit.resize(Options.MaxLen); + // The rest really requires DFSan. + if (!ReallyHaveDFSan()) return; + for (size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) { + dfsan_label L = dfsan_create_label("input", (void*)(i + 1)); + // We assume that no one else has called dfsan_create_label before. + if (L != i + 1) { + Printf("DFSan labels are not starting from 1, exiting\n"); + exit(1); + } + } +} + +static size_t InternalStrnlen(const char *S, size_t MaxLen) { + size_t Len = 0; + for (; Len < MaxLen && S[Len]; Len++) {} + return Len; +} + +} // namespace fuzzer + +using fuzzer::TS; + +extern "C" { +void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, + uint64_t Arg2, dfsan_label L0, + dfsan_label L1, dfsan_label L2) { + if (!TS) return; + assert(L0 == 0); + uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uint64_t CmpSize = (SizeAndType >> 32) / 8; + uint64_t Type = (SizeAndType << 32) >> 32; + TS->DFSanCmpCallback(PC, CmpSize, Type, Arg1, Arg2, L1, L2); +} + +void __dfsw___sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases, + dfsan_label L1, dfsan_label L2) { + if (!TS) return; + uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + TS->DFSanSwitchCallback(PC, Cases[1], Val, Cases[0], Cases+2, L1); +} + +void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, + size_t n, dfsan_label s1_label, + dfsan_label s2_label, dfsan_label n_label) { + if (!TS) return; + dfsan_label L1 = dfsan_read_label(s1, n); + dfsan_label L2 = dfsan_read_label(s2, n); + TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1), + reinterpret_cast<const uint8_t *>(s2), L1, L2); +} + +void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, + size_t n, dfsan_label s1_label, + dfsan_label s2_label, dfsan_label n_label) { + if (!TS) return; + n = std::min(n, fuzzer::InternalStrnlen(s1, n)); + n = std::min(n, fuzzer::InternalStrnlen(s2, n)); + dfsan_label L1 = dfsan_read_label(s1, n); + dfsan_label L2 = dfsan_read_label(s2, n); + TS->DFSanMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1), + reinterpret_cast<const uint8_t *>(s2), L1, L2); +} + +void dfsan_weak_hook_strcmp(void *caller_pc, const char *s1, const char *s2, + dfsan_label s1_label, dfsan_label s2_label) { + if (!TS) return; + size_t Len1 = strlen(s1); + size_t Len2 = strlen(s2); + size_t N = std::min(Len1, Len2); + if (N <= 1) return; // Not interesting. + dfsan_label L1 = dfsan_read_label(s1, Len1); + dfsan_label L2 = dfsan_read_label(s2, Len2); + TS->DFSanMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1), + reinterpret_cast<const uint8_t *>(s2), L1, L2); +} + +// We may need to avoid defining weak hooks to stay compatible with older clang. +#ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS +# define LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS 1 +#endif + +#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS +void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, + const void *s2, size_t n, int result) { + if (!TS) return; + if (result == 0) return; // No reason to mutate. + if (n <= 1) return; // Not interesting. + TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1), + reinterpret_cast<const uint8_t *>(s2)); +} + +void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, + const char *s2, size_t n, int result) { + if (!TS) return; + if (result == 0) return; // No reason to mutate. + size_t Len1 = fuzzer::InternalStrnlen(s1, n); + size_t Len2 = fuzzer::InternalStrnlen(s2, n); + n = std::min(n, Len1); + n = std::min(n, Len2); + if (n <= 1) return; // Not interesting. + TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1), + reinterpret_cast<const uint8_t *>(s2)); +} + +void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, + const char *s2, int result) { + if (!TS) return; + if (result == 0) return; // No reason to mutate. + size_t Len1 = strlen(s1); + size_t Len2 = strlen(s2); + size_t N = std::min(Len1, Len2); + if (N <= 1) return; // Not interesting. + TS->TraceMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1), + reinterpret_cast<const uint8_t *>(s2)); +} + +#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS + +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, + uint64_t Arg2) { + if (!TS) return; + uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + uint64_t CmpSize = (SizeAndType >> 32) / 8; + uint64_t Type = (SizeAndType << 32) >> 32; + TS->TraceCmpCallback(PC, CmpSize, Type, Arg1, Arg2); +} + +__attribute__((visibility("default"))) +void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { + if (!TS) return; + uintptr_t PC = reinterpret_cast<uintptr_t>(__builtin_return_address(0)); + TS->TraceSwitchCallback(PC, Cases[1], Val, Cases[0], Cases + 2); +} + +} // extern "C" diff --git a/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp b/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp new file mode 100644 index 00000000000..d7226cfce96 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp @@ -0,0 +1,212 @@ +//===- FuzzerUtil.cpp - Misc utils ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Misc utils. +//===----------------------------------------------------------------------===// + +#include "FuzzerInternal.h" +#include <sstream> +#include <iomanip> +#include <sys/time.h> +#include <cassert> +#include <cstring> +#include <signal.h> +#include <sstream> +#include <unistd.h> + +namespace fuzzer { + +void Print(const Unit &v, const char *PrintAfter) { + for (auto x : v) + Printf("0x%x,", (unsigned) x); + Printf("%s", PrintAfter); +} + +void PrintASCIIByte(uint8_t Byte) { + if (Byte == '\\') + Printf("\\\\"); + else if (Byte == '"') + Printf("\\\""); + else if (Byte >= 32 && Byte < 127) + Printf("%c", Byte); + else + Printf("\\x%02x", Byte); +} + +void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { + for (size_t i = 0; i < Size; i++) + PrintASCIIByte(Data[i]); + Printf("%s", PrintAfter); +} + +void PrintASCII(const Unit &U, const char *PrintAfter) { + for (auto X : U) + PrintASCIIByte(X); + Printf("%s", PrintAfter); +} + +std::string Hash(const Unit &U) { + uint8_t Hash[kSHA1NumBytes]; + ComputeSHA1(U.data(), U.size(), Hash); + std::stringstream SS; + for (int i = 0; i < kSHA1NumBytes; i++) + SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Hash[i]; + return SS.str(); +} + +static void AlarmHandler(int, siginfo_t *, void *) { + Fuzzer::StaticAlarmCallback(); +} + +void SetTimer(int Seconds) { + struct itimerval T {{Seconds, 0}, {Seconds, 0}}; + int Res = setitimer(ITIMER_REAL, &T, nullptr); + assert(Res == 0); + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = AlarmHandler; + Res = sigaction(SIGALRM, &sigact, 0); + assert(Res == 0); +} + +int NumberOfCpuCores() { + FILE *F = popen("nproc", "r"); + int N = 0; + fscanf(F, "%d", &N); + fclose(F); + return N; +} + +int ExecuteCommand(const std::string &Command) { + return system(Command.c_str()); +} + +bool ToASCII(Unit &U) { + bool Changed = false; + for (auto &X : U) { + auto NewX = X; + NewX &= 127; + if (!isspace(NewX) && !isprint(NewX)) + NewX = ' '; + Changed |= NewX != X; + X = NewX; + } + return Changed; +} + +bool IsASCII(const Unit &U) { + for (auto X : U) + if (!(isprint(X) || isspace(X))) return false; + return true; +} + +bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { + U->clear(); + if (Str.empty()) return false; + size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R]. + // Skip spaces from both sides. + while (L < R && isspace(Str[L])) L++; + while (R > L && isspace(Str[R])) R--; + if (R - L < 2) return false; + // Check the closing " + if (Str[R] != '"') return false; + R--; + // Find the opening " + while (L < R && Str[L] != '"') L++; + if (L >= R) return false; + assert(Str[L] == '\"'); + L++; + assert(L <= R); + for (size_t Pos = L; Pos <= R; Pos++) { + uint8_t V = (uint8_t)Str[Pos]; + if (!isprint(V) && !isspace(V)) return false; + if (V =='\\') { + // Handle '\\' + if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) { + U->push_back(Str[Pos + 1]); + Pos++; + continue; + } + // Handle '\xAB' + if (Pos + 3 <= R && Str[Pos + 1] == 'x' + && isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) { + char Hex[] = "0xAA"; + Hex[2] = Str[Pos + 2]; + Hex[3] = Str[Pos + 3]; + U->push_back(strtol(Hex, nullptr, 16)); + Pos += 3; + continue; + } + return false; // Invalid escape. + } else { + // Any other character. + U->push_back(V); + } + } + return true; +} + +bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) { + if (Text.empty()) { + Printf("ParseDictionaryFile: file does not exist or is empty\n"); + return false; + } + std::istringstream ISS(Text); + Units->clear(); + Unit U; + int LineNo = 0; + std::string S; + while (std::getline(ISS, S, '\n')) { + LineNo++; + size_t Pos = 0; + while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces. + if (Pos == S.size()) continue; // Empty line. + if (S[Pos] == '#') continue; // Comment line. + if (ParseOneDictionaryEntry(S, &U)) { + Units->push_back(U); + } else { + Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo, + S.c_str()); + return false; + } + } + return true; +} + +int GetPid() { return getpid(); } + + +std::string Base64(const Unit &U) { + static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + std::string Res; + size_t i; + for (i = 0; i + 2 < U.size(); i += 3) { + uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2]; + Res += Table[(x >> 18) & 63]; + Res += Table[(x >> 12) & 63]; + Res += Table[(x >> 6) & 63]; + Res += Table[x & 63]; + } + if (i + 1 == U.size()) { + uint32_t x = (U[i] << 16); + Res += Table[(x >> 18) & 63]; + Res += Table[(x >> 12) & 63]; + Res += "=="; + } else if (i + 2 == U.size()) { + uint32_t x = (U[i] << 16) + (U[i + 1] << 8); + Res += Table[(x >> 18) & 63]; + Res += Table[(x >> 12) & 63]; + Res += Table[(x >> 6) & 63]; + Res += "="; + } + return Res; +} + +} // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/README.txt b/gnu/llvm/lib/Fuzzer/README.txt new file mode 100644 index 00000000000..79f49b55090 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/README.txt @@ -0,0 +1,2 @@ +Move to http://llvm.org/docs/LibFuzzer.html + diff --git a/gnu/llvm/lib/Fuzzer/cxx.dict b/gnu/llvm/lib/Fuzzer/cxx.dict new file mode 100644 index 00000000000..41350f47558 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/cxx.dict @@ -0,0 +1,122 @@ +"++" +"--" +"<<" +">>" +"+=" +"-=" +"*=" +"/=" +">>=" +"<<=" +"&=" +"|=" +"^=" +"%=" +"!=" +"&&" +"||" +"==" +">=" +"<=" +"->" +"alignas" +"alignof" +"and" +"and_eq" +"asm" +"auto" +"bitand" +"bitor" +"bool" +"break" +"case" +"catch" +"char" +"char16_t" +"char32_t" +"class" +"compl" +"concept" +"const" +"constexpr" +"const_cast" +"continue" +"decltype" +"default" +"delete" +"do" +"double" +"dynamic_cast" +"else" +"enum" +"explicit" +"export" +"extern" +"false" +"float" +"for" +"friend" +"goto" +"if" +"inline" +"int" +"long" +"mutable" +"namespace" +"new" +"noexcept" +"not" +"not_eq" +"nullptr" +"operator" +"or" +"or_eq" +"private" +"protected" +"public" +"register" +"reinterpret_cast" +"requires" +"return" +"short" +"signed" +"sizeof" +"static" +"static_assert" +"static_cast" +"struct" +"switch" +"template" +"this" +"thread_local" +"throw" +"true" +"try" +"typedef" +"typeid" +"typename" +"union" +"unsigned" +"using" +"virtual" +"void" +"volatile" +"wchar_t" +"while" +"xor" +"xor_eq" +"if" +"elif" +"else" +"endif" +"defined" +"ifdef" +"ifndef" +"define" +"undef" +"include" +"line" +"error" +"pragma" +"override" +"final" diff --git a/gnu/llvm/lib/Fuzzer/pull_and_push_fuzz_corpus.sh b/gnu/llvm/lib/Fuzzer/pull_and_push_fuzz_corpus.sh new file mode 100755 index 00000000000..05c322c6e5b --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/pull_and_push_fuzz_corpus.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# A simple script to synchronise a fuzz test corpus +# with an external git repository. +# Usage: +# pull_and_push_fuzz_corpus.sh DIR +# It assumes that DIR is inside a git repo and push +# can be done w/o typing a password. +cd $1 +git add * +git commit -m "fuzz test corpus" +git pull --rebase --no-edit +for((attempt=0; attempt<5; attempt++)); do + echo GIT PUSH $1 ATTEMPT $attempt + if $(git push); then break; fi + git pull --rebase --no-edit +done + diff --git a/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt new file mode 100644 index 00000000000..cd0b167eb38 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt @@ -0,0 +1,118 @@ +# Build all these tests with -O0, otherwise optimizations may merge some +# basic blocks and we'll fail to discover the targets. +# Also enable the coverage instrumentation back (it is disabled +# for the Fuzzer lib) +set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O0 -fsanitize-coverage=edge,indirect-calls") + +set(DFSanTests + MemcmpTest + SimpleCmpTest + StrcmpTest + StrncmpTest + SwitchTest + ) + +set(Tests + CallerCalleeTest + CounterTest + FourIndependentBranchesTest + FullCoverageSetTest + MemcmpTest + NullDerefTest + SimpleCmpTest + SimpleDictionaryTest + SimpleHashTest + SimpleTest + StrcmpTest + StrncmpTest + SwitchTest + ThreadedTest + TimeoutTest + ) + +set(CustomMainTests + UserSuppliedFuzzerTest + ) + +set(UninstrumentedTests + UninstrumentedTest + ) + +set(TraceBBTests + SimpleTest + ) + +set(TestBinaries) + +foreach(Test ${Tests}) + add_executable(LLVMFuzzer-${Test} + ${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test} + LLVMFuzzer + ) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}) +endforeach() + +foreach(Test ${CustomMainTests}) + add_executable(LLVMFuzzer-${Test} + ${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test} + LLVMFuzzerNoMain + ) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}) +endforeach() + + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + ) + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg + ) + +include_directories(..) +include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include) + +add_executable(LLVMFuzzer-Unittest + FuzzerUnittest.cpp + $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> + ) + +target_link_libraries(LLVMFuzzer-Unittest + gtest + gtest_main + ) + +set(TestBinaries ${TestBinaries} LLVMFuzzer-Unittest) + +add_subdirectory(dfsan) + +foreach(Test ${DFSanTests}) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-DFSan) +endforeach() + +add_subdirectory(uninstrumented) + +foreach(Test ${UninstrumentedTests}) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-Uninstrumented) +endforeach() + +add_subdirectory(trace-bb) + +foreach(Test ${TraceBBTests}) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-TraceBB) +endforeach() + +set_target_properties(${TestBinaries} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + +add_lit_testsuite(check-fuzzer "Running Fuzzer tests" + ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${TestBinaries} FileCheck not + ) diff --git a/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp b/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp new file mode 100644 index 00000000000..150b2fc0405 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp @@ -0,0 +1,56 @@ +// Simple test for a fuzzer. +// Try to find the target using the indirect caller-callee pairs. +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <cstring> +#include <iostream> + +typedef void (*F)(); +static F t[256]; + +void f34() { + std::cerr << "BINGO\n"; + exit(1); +} +void f23() { t[(unsigned)'d'] = f34;} +void f12() { t[(unsigned)'c'] = f23;} +void f01() { t[(unsigned)'b'] = f12;} +void f00() {} + +static F t0[256] = { + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, + f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, f00, +}; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 4) return 0; + // Spoof the counters. + for (int i = 0; i < 200; i++) { + f23(); + f12(); + f01(); + } + memcpy(t, t0, sizeof(t)); + t[(unsigned)'a'] = f01; + t[Data[0]](); + t[Data[1]](); + t[Data[2]](); + t[Data[3]](); + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp b/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp new file mode 100644 index 00000000000..b61f419c499 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp @@ -0,0 +1,15 @@ +// Test for a fuzzer: must find the case where a particular basic block is +// executed many times. +#include <iostream> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int Num = 0; + for (size_t i = 0; i < Size; i++) + if (Data[i] == 'A' + i) + Num++; + if (Num >= 4) { + std::cerr << "BINGO!\n"; + exit(1); + } + return 0; +} diff --git a/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp b/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp new file mode 100644 index 00000000000..6007dd4a027 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp @@ -0,0 +1,19 @@ +// Simple test for a fuzzer. The fuzzer must find the string "FUZZ". +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <iostream> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int bits = 0; + if (Size > 0 && Data[0] == 'F') bits |= 1; + if (Size > 1 && Data[1] == 'U') bits |= 2; + if (Size > 2 && Data[2] == 'Z') bits |= 4; + if (Size > 3 && Data[3] == 'Z') bits |= 8; + if (bits == 15) { + std::cerr << "BINGO!\n"; + exit(1); + } + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp b/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp new file mode 100644 index 00000000000..a868084a0ce --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp @@ -0,0 +1,21 @@ +// Simple test for a fuzzer. The fuzzer must find the string "FUZZER". +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <iostream> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + int bits = 0; + if (Size > 0 && Data[0] == 'F') bits |= 1; + if (Size > 1 && Data[1] == 'U') bits |= 2; + if (Size > 2 && Data[2] == 'Z') bits |= 4; + if (Size > 3 && Data[3] == 'Z') bits |= 8; + if (Size > 4 && Data[4] == 'E') bits |= 16; + if (Size > 5 && Data[5] == 'R') bits |= 32; + if (bits == 63) { + std::cerr << "BINGO!\n"; + exit(1); + } + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp b/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp new file mode 100644 index 00000000000..b33e0c96145 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -0,0 +1,402 @@ +#include "FuzzerInternal.h" +#include "gtest/gtest.h" +#include <set> + +using namespace fuzzer; + +// For now, have LLVMFuzzerTestOneInput just to make it link. +// Later we may want to make unittests that actually call LLVMFuzzerTestOneInput. +extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + abort(); +} + +TEST(Fuzzer, CrossOver) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + Unit A({0, 1, 2}), B({5, 6, 7}); + Unit C; + Unit Expected[] = { + { 0 }, + { 0, 1 }, + { 0, 5 }, + { 0, 1, 2 }, + { 0, 1, 5 }, + { 0, 5, 1 }, + { 0, 5, 6 }, + { 0, 1, 2, 5 }, + { 0, 1, 5, 2 }, + { 0, 1, 5, 6 }, + { 0, 5, 1, 2 }, + { 0, 5, 1, 6 }, + { 0, 5, 6, 1 }, + { 0, 5, 6, 7 }, + { 0, 1, 2, 5, 6 }, + { 0, 1, 5, 2, 6 }, + { 0, 1, 5, 6, 2 }, + { 0, 1, 5, 6, 7 }, + { 0, 5, 1, 2, 6 }, + { 0, 5, 1, 6, 2 }, + { 0, 5, 1, 6, 7 }, + { 0, 5, 6, 1, 2 }, + { 0, 5, 6, 1, 7 }, + { 0, 5, 6, 7, 1 }, + { 0, 1, 2, 5, 6, 7 }, + { 0, 1, 5, 2, 6, 7 }, + { 0, 1, 5, 6, 2, 7 }, + { 0, 1, 5, 6, 7, 2 }, + { 0, 5, 1, 2, 6, 7 }, + { 0, 5, 1, 6, 2, 7 }, + { 0, 5, 1, 6, 7, 2 }, + { 0, 5, 6, 1, 2, 7 }, + { 0, 5, 6, 1, 7, 2 }, + { 0, 5, 6, 7, 1, 2 } + }; + for (size_t Len = 1; Len < 8; Len++) { + std::set<Unit> FoundUnits, ExpectedUnitsWitThisLength; + for (int Iter = 0; Iter < 3000; Iter++) { + C.resize(Len); + size_t NewSize = MD.CrossOver(A.data(), A.size(), B.data(), B.size(), + C.data(), C.size()); + C.resize(NewSize); + FoundUnits.insert(C); + } + for (const Unit &U : Expected) + if (U.size() <= Len) + ExpectedUnitsWitThisLength.insert(U); + EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits); + } +} + +TEST(Fuzzer, Hash) { + uint8_t A[] = {'a', 'b', 'c'}; + fuzzer::Unit U(A, A + sizeof(A)); + EXPECT_EQ("a9993e364706816aba3e25717850c26c9cd0d89d", fuzzer::Hash(U)); + U.push_back('d'); + EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U)); +} + +typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size, + size_t MaxSize); + +void TestEraseByte(Mutator M, int NumIter) { + uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77}; + uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77}; + uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77}; + uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, sizeof(T), sizeof(T)); + if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4; + if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5; + if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6; + if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, EraseByte1) { + TestEraseByte(&MutationDispatcher::Mutate_EraseByte, 100); +} +TEST(FuzzerMutate, EraseByte2) { + TestEraseByte(&MutationDispatcher::Mutate, 1000); +} + +void TestInsertByte(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + int FoundMask = 0; + uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66}; + uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66}; + uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66}; + uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66}; + uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + size_t NewSize = (MD.*M)(T, 7, 8); + if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0; + if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1; + if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2; + if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3; + if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4; + if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, InsertByte1) { + TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15); +} +TEST(FuzzerMutate, InsertByte2) { + TestInsertByte(&MutationDispatcher::Mutate, 1 << 17); +} + +void TestChangeByte(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + int FoundMask = 0; + uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77}; + uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77}; + uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77}; + uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, 8, 9); + if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; + if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; + if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; + if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; + if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; + if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, ChangeByte1) { + TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15); +} +TEST(FuzzerMutate, ChangeByte2) { + TestChangeByte(&MutationDispatcher::Mutate, 1 << 17); +} + +void TestChangeBit(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + int FoundMask = 0; + uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77}; + uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77}; + uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77}; + uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77}; + uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = (MD.*M)(T, 8, 9); + if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; + if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; + if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; + if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; + if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; + if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, ChangeBit1) { + TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16); +} +TEST(FuzzerMutate, ChangeBit2) { + TestChangeBit(&MutationDispatcher::Mutate, 1 << 18); +} + +void TestShuffleBytes(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + int FoundMask = 0; + uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66}; + uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66}; + uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66}; + uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33}; + uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + size_t NewSize = (MD.*M)(T, 7, 7); + if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4; + } + EXPECT_EQ(FoundMask, 31); +} + +TEST(FuzzerMutate, ShuffleBytes1) { + TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 15); +} +TEST(FuzzerMutate, ShuffleBytes2) { + TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 19); +} + +void TestAddWordFromDictionary(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD}; + uint8_t Word2[3] = {0xFF, 0xEE, 0xEF}; + MD.AddWordToManualDictionary(Unit(Word1, Word1 + sizeof(Word1))); + MD.AddWordToManualDictionary(Unit(Word2, Word2 + sizeof(Word2))); + int FoundMask = 0; + uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD}; + uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22}; + uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22}; + uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22}; + uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF}; + uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22}; + uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22}; + uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22}; + for (int i = 0; i < NumIter; i++) { + uint8_t T[7] = {0x00, 0x11, 0x22}; + size_t NewSize = (MD.*M)(T, 3, 7); + if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4; + if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5; + if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6; + if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, AddWordFromDictionary1) { + TestAddWordFromDictionary( + &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15); +} + +TEST(FuzzerMutate, AddWordFromDictionary2) { + TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15); +} + +void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + uint8_t Word[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF}; + size_t PosHint = 7777; + MD.AddWordToAutoDictionary(Unit(Word, Word + sizeof(Word)), PosHint); + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[10000]; + memset(T, 0, sizeof(T)); + size_t NewSize = (MD.*M)(T, 9000, 10000); + if (NewSize >= PosHint + sizeof(Word) && + !memcmp(Word, T + PosHint, sizeof(Word))) + FoundMask = 1; + } + EXPECT_EQ(FoundMask, 1); +} + +TEST(FuzzerMutate, AddWordFromDictionaryWithHint1) { + TestAddWordFromDictionaryWithHint( + &MutationDispatcher::Mutate_AddWordFromAutoDictionary, 1 << 5); +} + +TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) { + TestAddWordFromDictionaryWithHint(&MutationDispatcher::Mutate, 1 << 10); +} + +void TestChangeASCIIInteger(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + + uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'}; + uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'}; + uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'}; + uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'}; + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'}; + size_t NewSize = (MD.*M)(T, 8, 8); + /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; + else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; + else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; + else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; + else if (NewSize == 8) FoundMask |= 1 << 4; + } + EXPECT_EQ(FoundMask, 31); +} + +TEST(FuzzerMutate, ChangeASCIIInteger1) { + TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger, + 1 << 15); +} + +TEST(FuzzerMutate, ChangeASCIIInteger2) { + TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15); +} + + +TEST(FuzzerDictionary, ParseOneDictionaryEntry) { + Unit U; + EXPECT_FALSE(ParseOneDictionaryEntry("", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry("\t ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" \" ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" zz\" ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" \"zz ", &U)); + EXPECT_FALSE(ParseOneDictionaryEntry(" \"\" ", &U)); + EXPECT_TRUE(ParseOneDictionaryEntry("\"a\"", &U)); + EXPECT_EQ(U, Unit({'a'})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"abc\"", &U)); + EXPECT_EQ(U, Unit({'a', 'b', 'c'})); + EXPECT_TRUE(ParseOneDictionaryEntry("abc=\"abc\"", &U)); + EXPECT_EQ(U, Unit({'a', 'b', 'c'})); + EXPECT_FALSE(ParseOneDictionaryEntry("\"\\\"", &U)); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\\\"", &U)); + EXPECT_EQ(U, Unit({'\\'})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xAB\"", &U)); + EXPECT_EQ(U, Unit({0xAB})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\xABz\\xDE\"", &U)); + EXPECT_EQ(U, Unit({0xAB, 'z', 0xDE})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"#\"", &U)); + EXPECT_EQ(U, Unit({'#'})); + EXPECT_TRUE(ParseOneDictionaryEntry("\"\\\"\"", &U)); + EXPECT_EQ(U, Unit({'"'})); +} + +TEST(FuzzerDictionary, ParseDictionaryFile) { + std::vector<Unit> Units; + EXPECT_FALSE(ParseDictionaryFile("zzz\n", &Units)); + EXPECT_FALSE(ParseDictionaryFile("", &Units)); + EXPECT_TRUE(ParseDictionaryFile("\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile("#zzzz a b c d\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile(" #zzzz\n", &Units)); + EXPECT_EQ(Units.size(), 0U); + EXPECT_TRUE(ParseDictionaryFile(" #zzzz\naaa=\"aa\"", &Units)); + EXPECT_EQ(Units, std::vector<Unit>({Unit({'a', 'a'})})); + EXPECT_TRUE( + ParseDictionaryFile(" #zzzz\naaa=\"aa\"\n\nabc=\"abc\"", &Units)); + EXPECT_EQ(Units, + std::vector<Unit>({Unit({'a', 'a'}), Unit({'a', 'b', 'c'})})); +} + +TEST(FuzzerUtil, Base64) { + EXPECT_EQ("", Base64({})); + EXPECT_EQ("YQ==", Base64({'a'})); + EXPECT_EQ("eA==", Base64({'x'})); + EXPECT_EQ("YWI=", Base64({'a', 'b'})); + EXPECT_EQ("eHk=", Base64({'x', 'y'})); + EXPECT_EQ("YWJj", Base64({'a', 'b', 'c'})); + EXPECT_EQ("eHl6", Base64({'x', 'y', 'z'})); + EXPECT_EQ("YWJjeA==", Base64({'a', 'b', 'c', 'x'})); + EXPECT_EQ("YWJjeHk=", Base64({'a', 'b', 'c', 'x', 'y'})); + EXPECT_EQ("YWJjeHl6", Base64({'a', 'b', 'c', 'x', 'y', 'z'})); +} diff --git a/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp new file mode 100644 index 00000000000..c19c95717bb --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp @@ -0,0 +1,28 @@ +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include <cstring> +#include <cstdint> +#include <cstdio> +#include <cstdlib> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + // TODO: check other sizes. + if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) { + if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) { + if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) { + if (Size >= 16 && memcmp(Data + 14, "KLM", 3) == 0) { + if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){ + fprintf(stderr, "BINGO %zd\n", Size); + for (size_t i = 0; i < Size; i++) { + uint8_t C = Data[i]; + if (C >= 32 && C < 127) + fprintf(stderr, "%c", C); + } + fprintf(stderr, "\n"); + exit(1); + } + } + } + } + } + return 0; +} diff --git a/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp b/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp new file mode 100644 index 00000000000..200c56ccbbc --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp @@ -0,0 +1,23 @@ +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <iostream> + +static volatile int Sink; +static volatile int *Null = 0; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'H') { + Sink = 1; + if (Size > 1 && Data[1] == 'i') { + Sink = 2; + if (Size > 2 && Data[2] == '!') { + std::cout << "Found the target, dereferencing NULL\n"; + *Null = 1; + } + } + } + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp new file mode 100644 index 00000000000..8568c737efb --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp @@ -0,0 +1,31 @@ +// Simple test for a fuzzer. The fuzzer must find several narrow ranges. +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <cstdio> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 14) return 0; + uint64_t x = 0; + int64_t y = 0; + int z = 0; + unsigned short a = 0; + memcpy(&x, Data, 8); + memcpy(&y, Data + Size - 8, 8); + memcpy(&z, Data + Size / 2, sizeof(z)); + memcpy(&a, Data + Size / 2 + 4, sizeof(a)); + + if (x > 1234567890 && + x < 1234567895 && + y >= 987654321 && + y <= 987654325 && + z < -10000 && + z >= -10005 && + z != -10003 && + a == 4242) { + fprintf(stderr, "BINGO; Found the target: size %zd (%zd, %zd, %d, %d), exiting.\n", + Size, x, y, z, a); + exit(1); + } + return 0; +} diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp new file mode 100644 index 00000000000..b9cb2f0270a --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp @@ -0,0 +1,26 @@ +// Simple test for a fuzzer. +// The fuzzer must find a string based on dictionary words: +// "Elvis" +// "Presley" +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <cstring> +#include <iostream> + +static volatile int Zero = 0; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + const char *Expected = "ElvisPresley"; + if (Size < strlen(Expected)) return 0; + size_t Match = 0; + for (size_t i = 0; Expected[i]; i++) + if (Expected[i] + Zero == Data[i]) + Match++; + if (Match == strlen(Expected)) { + std::cout << "BINGO; Found the target, exiting\n"; + exit(1); + } + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp new file mode 100644 index 00000000000..5bab3fa7f64 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp @@ -0,0 +1,37 @@ +// This test computes a checksum of the data (all but the last 4 bytes), +// and then compares the last 4 bytes with the computed value. +// A fuzzer with cmp traces is expected to defeat this check. +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <cstdio> + +// A modified jenkins_one_at_a_time_hash initialized by non-zero, +// so that simple_hash(0) != 0. See also +// https://en.wikipedia.org/wiki/Jenkins_hash_function +static uint32_t simple_hash(const uint8_t *Data, size_t Size) { + uint32_t Hash = 0x12039854; + for (uint32_t i = 0; i < Size; i++) { + Hash += Data[i]; + Hash += (Hash << 10); + Hash ^= (Hash >> 6); + } + Hash += (Hash << 3); + Hash ^= (Hash >> 11); + Hash += (Hash << 15); + return Hash; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 14) + return 0; + + uint32_t Hash = simple_hash(&Data[0], Size - 4); + uint32_t Want = reinterpret_cast<const uint32_t *>(&Data[Size - 4])[0]; + if (Hash != Want) + return 0; + fprintf(stderr, "BINGO; simple_hash defeated: %x == %x\n", (unsigned int)Hash, + (unsigned int)Want); + exit(1); + return 0; +} diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp new file mode 100644 index 00000000000..04225a889f5 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp @@ -0,0 +1,24 @@ +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include <assert.h> +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <iostream> + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + if (Size > 0 && Data[0] == 'H') { + Sink = 1; + if (Size > 1 && Data[1] == 'i') { + Sink = 2; + if (Size > 2 && Data[2] == '!') { + std::cout << "BINGO; Found the target, exiting\n"; + exit(0); + } + } + } + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp new file mode 100644 index 00000000000..835819ae2f4 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp @@ -0,0 +1,29 @@ +// Break through a series of strcmp. +#include <cstring> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cassert> + +bool Eq(const uint8_t *Data, size_t Size, const char *Str) { + char Buff[1024]; + size_t Len = strlen(Str); + if (Size < Len) return false; + if (Len >= sizeof(Buff)) return false; + memcpy(Buff, (char*)Data, Len); + Buff[Len] = 0; + int res = strcmp(Buff, Str); + return res == 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Eq(Data, Size, "AAA") && + Size >= 3 && Eq(Data + 3, Size - 3, "BBBB") && + Size >= 7 && Eq(Data + 7, Size - 7, "CCCCCC") && + Size >= 14 && Data[13] == 42 + ) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + return 0; +} diff --git a/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp new file mode 100644 index 00000000000..55344d75e0b --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp @@ -0,0 +1,25 @@ +// Simple test for a fuzzer. The fuzzer must find a particular string. +#include <cstring> +#include <cstdint> +#include <cstdio> +#include <cstdlib> + +static volatile int sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + // TODO: check other sizes. + char *S = (char*)Data; + if (Size >= 8 && strncmp(S, "123", 8)) + sink = 1; + if (Size >= 8 && strncmp(S, "01234567", 8) == 0) { + if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) { + if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) { + if (Size >= 16 && strncmp(S + 14, "KLM", 3) == 0) { + fprintf(stderr, "BINGO\n"); + exit(1); + } + } + } + } + return 0; +} diff --git a/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp b/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp new file mode 100644 index 00000000000..5de7fff7452 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp @@ -0,0 +1,55 @@ +// Simple test for a fuzzer. The fuzzer must find the interesting switch value. +#include <cstdint> +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <cstddef> + +static volatile int Sink; + +template<class T> +bool Switch(const uint8_t *Data, size_t Size) { + T X; + if (Size < sizeof(X)) return false; + memcpy(&X, Data, sizeof(X)); + switch (X) { + case 1: Sink = __LINE__; break; + case 101: Sink = __LINE__; break; + case 1001: Sink = __LINE__; break; + case 10001: Sink = __LINE__; break; + case 100001: Sink = __LINE__; break; + case 1000001: Sink = __LINE__; break; + case 10000001: Sink = __LINE__; break; + case 100000001: return true; + } + return false; +} + +bool ShortSwitch(const uint8_t *Data, size_t Size) { + short X; + if (Size < sizeof(short)) return false; + memcpy(&X, Data, sizeof(short)); + switch(X) { + case 42: Sink = __LINE__; break; + case 402: Sink = __LINE__; break; + case 4002: Sink = __LINE__; break; + case 5002: Sink = __LINE__; break; + case 7002: Sink = __LINE__; break; + case 9002: Sink = __LINE__; break; + case 14002: Sink = __LINE__; break; + case 21402: return true; + } + return false; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size >= 4 && Switch<int>(Data, Size) && + Size >= 12 && Switch<uint64_t>(Data + 4, Size - 4) && + Size >= 14 && ShortSwitch(Data + 12, 2) + ) { + fprintf(stderr, "BINGO; Found the target, exiting\n"); + exit(1); + } + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp b/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp new file mode 100644 index 00000000000..7aa114a41f3 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp @@ -0,0 +1,23 @@ +// Threaded test for a fuzzer. The fuzzer should not crash. +#include <assert.h> +#include <cstdint> +#include <cstddef> +#include <cstring> +#include <thread> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size < 8) return 0; + assert(Data); + auto C = [&] { + size_t Res = 0; + for (size_t i = 0; i < Size / 2; i++) + Res += memcmp(Data, Data + Size / 2, 4); + return Res; + }; + std::thread T[] = {std::thread(C), std::thread(C), std::thread(C), + std::thread(C), std::thread(C), std::thread(C)}; + for (auto &X : T) + X.join(); + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp b/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp new file mode 100644 index 00000000000..71790ded95a --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp @@ -0,0 +1,23 @@ +// Simple test for a fuzzer. The fuzzer must find the string "Hi!". +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <iostream> + +static volatile int Sink; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size > 0 && Data[0] == 'H') { + Sink = 1; + if (Size > 1 && Data[1] == 'i') { + Sink = 2; + if (Size > 2 && Data[2] == '!') { + Sink = 2; + while (Sink) + ; + } + } + } + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/UninstrumentedTest.cpp b/gnu/llvm/lib/Fuzzer/test/UninstrumentedTest.cpp new file mode 100644 index 00000000000..c1730198d83 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/UninstrumentedTest.cpp @@ -0,0 +1,8 @@ +// This test should not be instrumented. +#include <cstdint> +#include <cstddef> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + return 0; +} + diff --git a/gnu/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp b/gnu/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp new file mode 100644 index 00000000000..59f83b57bfa --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp @@ -0,0 +1,51 @@ +// Simple test for a fuzzer. +// The fuzzer must find the string "Hi!" preceded by a magic value. +// Uses UserSuppliedFuzzer which ensures that the magic is present. +#include <cstdint> +#include <cassert> +#include <cstdlib> +#include <cstddef> +#include <cstring> +#include <iostream> + +#include "FuzzerInterface.h" + +static const uint64_t kMagic = 8860221463604ULL; + +class MyFuzzer : public fuzzer::UserSuppliedFuzzer { + public: + MyFuzzer(fuzzer::FuzzerRandomBase *Rand) + : fuzzer::UserSuppliedFuzzer(Rand) {} + int TargetFunction(const uint8_t *Data, size_t Size) { + if (Size <= 10) return 0; + if (memcmp(Data, &kMagic, sizeof(kMagic))) return 0; + // It's hard to get here w/o advanced fuzzing techniques (e.g. cmp tracing). + // So, we simply 'fix' the data in the custom mutator. + if (Data[8] == 'H') { + if (Data[9] == 'i') { + if (Data[10] == '!') { + std::cout << "BINGO; Found the target, exiting\n"; + exit(1); + } + } + } + return 0; + } + // Custom mutator. + virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { + assert(MaxSize > sizeof(kMagic)); + if (Size < sizeof(kMagic)) + Size = sizeof(kMagic); + // "Fix" the data, then mutate. + memcpy(Data, &kMagic, std::min(MaxSize, sizeof(kMagic))); + return fuzzer::UserSuppliedFuzzer::Mutate( + Data + sizeof(kMagic), Size - sizeof(kMagic), MaxSize - sizeof(kMagic)); + } + // No need to redefine CrossOver() here. +}; + +int main(int argc, char **argv) { + fuzzer::FuzzerRandomLibc Rand(0); + MyFuzzer F(&Rand); + fuzzer::FuzzerDriver(argc, argv, F); +} diff --git a/gnu/llvm/lib/Fuzzer/test/dfsan/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/dfsan/CMakeLists.txt new file mode 100644 index 00000000000..2b49831fcdb --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/dfsan/CMakeLists.txt @@ -0,0 +1,14 @@ +# These tests depend on both coverage and dfsan instrumentation. + +set(CMAKE_CXX_FLAGS_RELEASE + "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize=all -fsanitize=dataflow") + +foreach(Test ${DFSanTests}) + add_executable(LLVMFuzzer-${Test}-DFSan + ../${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test}-DFSan + LLVMFuzzer + ) +endforeach() + diff --git a/gnu/llvm/lib/Fuzzer/test/dict1.txt b/gnu/llvm/lib/Fuzzer/test/dict1.txt new file mode 100644 index 00000000000..520d0cc7b7d --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/dict1.txt @@ -0,0 +1,4 @@ +# Dictionary for SimpleDictionaryTest + +a="Elvis" +b="Presley" diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-dfsan.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-dfsan.test new file mode 100644 index 00000000000..567086ed65a --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-dfsan.test @@ -0,0 +1,23 @@ +CHECK1: BINGO +CHECK2: BINGO +CHECK3: BINGO +CHECK4: BINGO + +CHECK_DFSanCmpCallback: DFSanCmpCallback: PC +CHECK_DFSanSwitchCallback: DFSanSwitchCallback: PC +CHECK_DFSanMemcmpCallback: DFSanMemcmpCallback: Pos + +RUN: not LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK1 +RUN: LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=100 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback + +RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK2 +RUN: LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback + +RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3 +RUN: LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback + +RUN: not LLVMFuzzer-StrcmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3 +RUN: LLVMFuzzer-StrcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback + +RUN: not LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=100000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK4 +RUN: LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanSwitchCallback diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-dict.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-dict.test new file mode 100644 index 00000000000..dec002f6a37 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-dict.test @@ -0,0 +1,6 @@ +CHECK: BINGO +Done1000000: Done 1000000 runs in + +RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003 2>&1 | FileCheck %s +RUN: LLVMFuzzer-SimpleDictionaryTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-drill.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-drill.test new file mode 100644 index 00000000000..b2fc1fecd27 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-drill.test @@ -0,0 +1,8 @@ +CHECK: BINGO +RUN: rm -rf FourIndependentBranchesTestCORPUS +RUN: mkdir FourIndependentBranchesTestCORPUS +RUN: LLVMFuzzer-FourIndependentBranchesTest -seed=1 -runs=100000 FourIndependentBranchesTestCORPUS +RUN: not LLVMFuzzer-FourIndependentBranchesTest -runs=100000 -drill=1 -jobs=200 FourIndependentBranchesTestCORPUS 2>&1 | FileCheck %s +RUN: rm -rf FourIndependentBranchesTestCORPUS + + diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-threaded.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-threaded.test new file mode 100644 index 00000000000..c58a33456cc --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-threaded.test @@ -0,0 +1,7 @@ +CHECK: Done 1000 runs in + +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-ThreadedTest -use_traces=1 -runs=1000 2>&1 | FileCheck %s + diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test new file mode 100644 index 00000000000..c3a9e8a3a9e --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test @@ -0,0 +1,13 @@ +RUN: not LLVMFuzzer-TimeoutTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutTest +TimeoutTest: ALARM: working on the last Unit for +TimeoutTest: Test unit written to ./timeout- +TimeoutTest: == ERROR: libFuzzer: timeout after +TimeoutTest: #0 +TimeoutTest: #1 +TimeoutTest: #2 +TimeoutTest: SUMMARY: libFuzzer: timeout + +RUN: not LLVMFuzzer-TimeoutTest -timeout=1 -test_single_input=%S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest +SingleInputTimeoutTest: ALARM: working on the last Unit for +SingleInputTimeoutTest-NOT: Test unit written to ./timeout- + diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-traces.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-traces.test new file mode 100644 index 00000000000..3b8639b8e94 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-traces.test @@ -0,0 +1,20 @@ +CHECK: BINGO +Done1000000: Done 1000000 runs in +Done10000000: Done 10000000 runs in + +RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=10000001 2>&1 | FileCheck %s + +RUN: not LLVMFuzzer-MemcmpTest -use_traces=1 -seed=4294967295 -runs=100000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-MemcmpTest -seed=4294967295 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + +RUN: not LLVMFuzzer-StrncmpTest -use_traces=1 -seed=1 -runs=100000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-StrncmpTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + +RUN: not LLVMFuzzer-StrcmpTest -use_traces=1 -seed=1 -runs=200000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-StrcmpTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + +RUN: not LLVMFuzzer-SwitchTest -use_traces=1 -seed=1 -runs=1000002 2>&1 | FileCheck %s +RUN: LLVMFuzzer-SwitchTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + +RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=1 -runs=10000000 2>&1 | FileCheck %s +RUN: LLVMFuzzer-SimpleHashTest -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=Done10000000 diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer.test b/gnu/llvm/lib/Fuzzer/test/fuzzer.test new file mode 100644 index 00000000000..c63014f59d6 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer.test @@ -0,0 +1,36 @@ +CHECK: BINGO +Done1000000: Done 1000000 runs in + +RUN: LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-NullDerefTest -test_single_input=%S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput +SingleInput-NOT: Test unit written to ./crash- + +RUN: LLVMFuzzer-SimpleCmpTest -max_total_time=1 2>&1 | FileCheck %s --check-prefix=MaxTotalTime +MaxTotalTime: Done {{.*}} runs in {{.}} second(s) + +RUN: not LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest +NullDerefTest: Test unit written to ./crash- +RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix +NullDerefTestPrefix: Test unit written to ZZZcrash- +RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath +NullDerefTestExactPath: Test unit written to FOOBAR + +#not LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s + +RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s + +RUN: not LLVMFuzzer-CallerCalleeTest -cross_over=0 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s +# This one is flaky, may actually find the goal even w/o use_indir_calls. +# LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 + + +RUN: not LLVMFuzzer-UserSuppliedFuzzerTest -seed=1 -timeout=15 2>&1 | FileCheck %s + +RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED +UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. + +RUN: LLVMFuzzer-SimpleTest -print_new_cov_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS +PCS:{{^0x[a-f0-9]+}} +PCS:NEW +PCS:BINGO + diff --git a/gnu/llvm/lib/Fuzzer/test/hi.txt b/gnu/llvm/lib/Fuzzer/test/hi.txt new file mode 100644 index 00000000000..2f9031f0ec7 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/hi.txt @@ -0,0 +1 @@ +Hi!
\ No newline at end of file diff --git a/gnu/llvm/lib/Fuzzer/test/lit.cfg b/gnu/llvm/lib/Fuzzer/test/lit.cfg new file mode 100644 index 00000000000..2140a97668b --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/lit.cfg @@ -0,0 +1,15 @@ +import lit.formats + +config.name = "LLVMFuzzer" +config.test_format = lit.formats.ShTest(True) +config.suffixes = ['.test'] +config.test_source_root = os.path.dirname(__file__) + +# Tweak PATH to include llvm tools dir and current exec dir. +llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) +if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): + lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir) +path = os.path.pathsep.join((llvm_tools_dir, config.test_exec_root, + config.environment['PATH'])) +config.environment['PATH'] = path + diff --git a/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in b/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in new file mode 100644 index 00000000000..e520db8e881 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in @@ -0,0 +1,3 @@ +config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" +lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") diff --git a/gnu/llvm/lib/Fuzzer/test/merge.test b/gnu/llvm/lib/Fuzzer/test/merge.test new file mode 100644 index 00000000000..57ecc141bbf --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/merge.test @@ -0,0 +1,29 @@ +CHECK: BINGO + +RUN: rm -rf %tmp/T1 %tmp/T2 +RUN: mkdir -p %tmp/T1 %tmp/T2 +RUN: echo F..... > %tmp/T1/1 +RUN: echo .U.... > %tmp/T1/2 +RUN: echo ..Z... > %tmp/T1/3 + +# T1 has 3 elements, T2 is empty. +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 +CHECK1: Merge: running the initial corpus {{.*}} of 3 units +CHECK1: Merge: written 0 out of 0 units + +RUN: echo ...Z.. > %tmp/T2/1 +RUN: echo ....E. > %tmp/T2/2 +RUN: echo .....R > %tmp/T2/3 +RUN: echo F..... > %tmp/T2/a +RUN: echo .U.... > %tmp/T2/b +RUN: echo ..Z... > %tmp/T2/c + +# T1 has 3 elements, T2 has 6 elements, only 3 are new. +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 +CHECK2: Merge: running the initial corpus {{.*}} of 3 units +CHECK2: Merge: written 3 out of 6 units + +# Now, T1 has 6 units and T2 has no new interesting units. +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 +CHECK3: Merge: running the initial corpus {{.*}} of 6 units +CHECK3: Merge: written 0 out of 6 units diff --git a/gnu/llvm/lib/Fuzzer/test/trace-bb/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/trace-bb/CMakeLists.txt new file mode 100644 index 00000000000..99af019565b --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/trace-bb/CMakeLists.txt @@ -0,0 +1,14 @@ +# These tests are not instrumented with coverage. + +set(CMAKE_CXX_FLAGS_RELEASE + "${LIBFUZZER_FLAGS_BASE} -fsanitize-coverage=edge,trace-bb") + +foreach(Test ${TraceBBTests}) + add_executable(LLVMFuzzer-${Test}-TraceBB + ../${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test}-TraceBB + LLVMFuzzer + ) +endforeach() + diff --git a/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt new file mode 100644 index 00000000000..443ba3716f6 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt @@ -0,0 +1,14 @@ +# These tests are not instrumented with coverage. + +set(CMAKE_CXX_FLAGS_RELEASE + "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize=all") + +foreach(Test ${UninstrumentedTests}) + add_executable(LLVMFuzzer-${Test}-Uninstrumented + ../${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test}-Uninstrumented + LLVMFuzzer + ) +endforeach() + diff --git a/gnu/llvm/lib/Fuzzer/test/unit/lit.cfg b/gnu/llvm/lib/Fuzzer/test/unit/lit.cfg new file mode 100644 index 00000000000..0cc31939c55 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/unit/lit.cfg @@ -0,0 +1,7 @@ +import lit.formats + +config.name = "LLVMFuzzer-Unittest" +print config.test_exec_root +config.test_format = lit.formats.GoogleTest(".", "Unittest") +config.suffixes = [] +config.test_source_root = config.test_exec_root diff --git a/gnu/llvm/lib/Fuzzer/test/unit/lit.site.cfg.in b/gnu/llvm/lib/Fuzzer/test/unit/lit.site.cfg.in new file mode 100644 index 00000000000..114daf474b6 --- /dev/null +++ b/gnu/llvm/lib/Fuzzer/test/unit/lit.site.cfg.in @@ -0,0 +1,2 @@ +config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" +lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/unit/lit.cfg") |
