Home | History | Annotate | Line # | Download | only in fuzzer
      1  1.1  kamil //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
      2  1.1  kamil //
      3  1.1  kamil //                     The LLVM Compiler Infrastructure
      4  1.1  kamil //
      5  1.1  kamil // This file is distributed under the University of Illinois Open Source
      6  1.1  kamil // License. See LICENSE.TXT for details.
      7  1.1  kamil //
      8  1.1  kamil //===----------------------------------------------------------------------===//
      9  1.1  kamil // FuzzerDriver and flag parsing.
     10  1.1  kamil //===----------------------------------------------------------------------===//
     11  1.1  kamil 
     12  1.1  kamil #include "FuzzerCommand.h"
     13  1.1  kamil #include "FuzzerCorpus.h"
     14  1.1  kamil #include "FuzzerIO.h"
     15  1.1  kamil #include "FuzzerInterface.h"
     16  1.1  kamil #include "FuzzerInternal.h"
     17  1.1  kamil #include "FuzzerMutate.h"
     18  1.1  kamil #include "FuzzerRandom.h"
     19  1.1  kamil #include "FuzzerShmem.h"
     20  1.1  kamil #include "FuzzerTracePC.h"
     21  1.1  kamil #include <algorithm>
     22  1.1  kamil #include <atomic>
     23  1.1  kamil #include <chrono>
     24  1.1  kamil #include <cstdlib>
     25  1.1  kamil #include <cstring>
     26  1.1  kamil #include <mutex>
     27  1.1  kamil #include <string>
     28  1.1  kamil #include <thread>
     29  1.1  kamil 
     30  1.1  kamil // This function should be present in the libFuzzer so that the client
     31  1.1  kamil // binary can test for its existence.
     32  1.1  kamil extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
     33  1.1  kamil 
     34  1.1  kamil namespace fuzzer {
     35  1.1  kamil 
     36  1.1  kamil // Program arguments.
     37  1.1  kamil struct FlagDescription {
     38  1.1  kamil   const char *Name;
     39  1.1  kamil   const char *Description;
     40  1.1  kamil   int   Default;
     41  1.1  kamil   int   *IntFlag;
     42  1.1  kamil   const char **StrFlag;
     43  1.1  kamil   unsigned int *UIntFlag;
     44  1.1  kamil };
     45  1.1  kamil 
     46  1.1  kamil struct {
     47  1.1  kamil #define FUZZER_DEPRECATED_FLAG(Name)
     48  1.1  kamil #define FUZZER_FLAG_INT(Name, Default, Description) int Name;
     49  1.1  kamil #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
     50  1.1  kamil #define FUZZER_FLAG_STRING(Name, Description) const char *Name;
     51  1.1  kamil #include "FuzzerFlags.def"
     52  1.1  kamil #undef FUZZER_DEPRECATED_FLAG
     53  1.1  kamil #undef FUZZER_FLAG_INT
     54  1.1  kamil #undef FUZZER_FLAG_UNSIGNED
     55  1.1  kamil #undef FUZZER_FLAG_STRING
     56  1.1  kamil } Flags;
     57  1.1  kamil 
     58  1.1  kamil static const FlagDescription FlagDescriptions [] {
     59  1.1  kamil #define FUZZER_DEPRECATED_FLAG(Name)                                           \
     60  1.1  kamil   {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
     61  1.1  kamil #define FUZZER_FLAG_INT(Name, Default, Description)                            \
     62  1.1  kamil   {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
     63  1.1  kamil #define FUZZER_FLAG_UNSIGNED(Name, Default, Description)                       \
     64  1.1  kamil   {#Name,   Description, static_cast<int>(Default),                            \
     65  1.1  kamil    nullptr, nullptr, &Flags.Name},
     66  1.1  kamil #define FUZZER_FLAG_STRING(Name, Description)                                  \
     67  1.1  kamil   {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
     68  1.1  kamil #include "FuzzerFlags.def"
     69  1.1  kamil #undef FUZZER_DEPRECATED_FLAG
     70  1.1  kamil #undef FUZZER_FLAG_INT
     71  1.1  kamil #undef FUZZER_FLAG_UNSIGNED
     72  1.1  kamil #undef FUZZER_FLAG_STRING
     73  1.1  kamil };
     74  1.1  kamil 
     75  1.1  kamil static const size_t kNumFlags =
     76  1.1  kamil     sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
     77  1.1  kamil 
     78  1.1  kamil static Vector<std::string> *Inputs;
     79  1.1  kamil static std::string *ProgName;
     80  1.1  kamil 
     81  1.1  kamil static void PrintHelp() {
     82  1.1  kamil   Printf("Usage:\n");
     83  1.1  kamil   auto Prog = ProgName->c_str();
     84  1.1  kamil   Printf("\nTo run fuzzing pass 0 or more directories.\n");
     85  1.1  kamil   Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
     86  1.1  kamil 
     87  1.1  kamil   Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n");
     88  1.1  kamil   Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog);
     89  1.1  kamil 
     90  1.1  kamil   Printf("\nFlags: (strictly in form -flag=value)\n");
     91  1.1  kamil   size_t MaxFlagLen = 0;
     92  1.1  kamil   for (size_t F = 0; F < kNumFlags; F++)
     93  1.1  kamil     MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
     94  1.1  kamil 
     95  1.1  kamil   for (size_t F = 0; F < kNumFlags; F++) {
     96  1.1  kamil     const auto &D = FlagDescriptions[F];
     97  1.1  kamil     if (strstr(D.Description, "internal flag") == D.Description) continue;
     98  1.1  kamil     Printf(" %s", D.Name);
     99  1.1  kamil     for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
    100  1.1  kamil       Printf(" ");
    101  1.1  kamil     Printf("\t");
    102  1.1  kamil     Printf("%d\t%s\n", D.Default, D.Description);
    103  1.1  kamil   }
    104  1.1  kamil   Printf("\nFlags starting with '--' will be ignored and "
    105  1.1  kamil             "will be passed verbatim to subprocesses.\n");
    106  1.1  kamil }
    107  1.1  kamil 
    108  1.1  kamil static const char *FlagValue(const char *Param, const char *Name) {
    109  1.1  kamil   size_t Len = strlen(Name);
    110  1.1  kamil   if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
    111  1.1  kamil       Param[Len + 1] == '=')
    112  1.1  kamil       return &Param[Len + 2];
    113  1.1  kamil   return nullptr;
    114  1.1  kamil }
    115  1.1  kamil 
    116  1.1  kamil // Avoid calling stol as it triggers a bug in clang/glibc build.
    117  1.1  kamil static long MyStol(const char *Str) {
    118  1.1  kamil   long Res = 0;
    119  1.1  kamil   long Sign = 1;
    120  1.1  kamil   if (*Str == '-') {
    121  1.1  kamil     Str++;
    122  1.1  kamil     Sign = -1;
    123  1.1  kamil   }
    124  1.1  kamil   for (size_t i = 0; Str[i]; i++) {
    125  1.1  kamil     char Ch = Str[i];
    126  1.1  kamil     if (Ch < '0' || Ch > '9')
    127  1.1  kamil       return Res;
    128  1.1  kamil     Res = Res * 10 + (Ch - '0');
    129  1.1  kamil   }
    130  1.1  kamil   return Res * Sign;
    131  1.1  kamil }
    132  1.1  kamil 
    133  1.1  kamil static bool ParseOneFlag(const char *Param) {
    134  1.1  kamil   if (Param[0] != '-') return false;
    135  1.1  kamil   if (Param[1] == '-') {
    136  1.1  kamil     static bool PrintedWarning = false;
    137  1.1  kamil     if (!PrintedWarning) {
    138  1.1  kamil       PrintedWarning = true;
    139  1.1  kamil       Printf("INFO: libFuzzer ignores flags that start with '--'\n");
    140  1.1  kamil     }
    141  1.1  kamil     for (size_t F = 0; F < kNumFlags; F++)
    142  1.1  kamil       if (FlagValue(Param + 1, FlagDescriptions[F].Name))
    143  1.1  kamil         Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1);
    144  1.1  kamil     return true;
    145  1.1  kamil   }
    146  1.1  kamil   for (size_t F = 0; F < kNumFlags; F++) {
    147  1.1  kamil     const char *Name = FlagDescriptions[F].Name;
    148  1.1  kamil     const char *Str = FlagValue(Param, Name);
    149  1.1  kamil     if (Str)  {
    150  1.1  kamil       if (FlagDescriptions[F].IntFlag) {
    151  1.1  kamil         int Val = MyStol(Str);
    152  1.1  kamil         *FlagDescriptions[F].IntFlag = Val;
    153  1.1  kamil         if (Flags.verbosity >= 2)
    154  1.1  kamil           Printf("Flag: %s %d\n", Name, Val);
    155  1.1  kamil         return true;
    156  1.1  kamil       } else if (FlagDescriptions[F].UIntFlag) {
    157  1.1  kamil         unsigned int Val = std::stoul(Str);
    158  1.1  kamil         *FlagDescriptions[F].UIntFlag = Val;
    159  1.1  kamil         if (Flags.verbosity >= 2)
    160  1.1  kamil           Printf("Flag: %s %u\n", Name, Val);
    161  1.1  kamil         return true;
    162  1.1  kamil       } else if (FlagDescriptions[F].StrFlag) {
    163  1.1  kamil         *FlagDescriptions[F].StrFlag = Str;
    164  1.1  kamil         if (Flags.verbosity >= 2)
    165  1.1  kamil           Printf("Flag: %s %s\n", Name, Str);
    166  1.1  kamil         return true;
    167  1.1  kamil       } else {  // Deprecated flag.
    168  1.1  kamil         Printf("Flag: %s: deprecated, don't use\n", Name);
    169  1.1  kamil         return true;
    170  1.1  kamil       }
    171  1.1  kamil     }
    172  1.1  kamil   }
    173  1.1  kamil   Printf("\n\nWARNING: unrecognized flag '%s'; "
    174  1.1  kamil          "use -help=1 to list all flags\n\n", Param);
    175  1.1  kamil   return true;
    176  1.1  kamil }
    177  1.1  kamil 
    178  1.1  kamil // We don't use any library to minimize dependencies.
    179  1.1  kamil static void ParseFlags(const Vector<std::string> &Args) {
    180  1.1  kamil   for (size_t F = 0; F < kNumFlags; F++) {
    181  1.1  kamil     if (FlagDescriptions[F].IntFlag)
    182  1.1  kamil       *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
    183  1.1  kamil     if (FlagDescriptions[F].UIntFlag)
    184  1.1  kamil       *FlagDescriptions[F].UIntFlag =
    185  1.1  kamil           static_cast<unsigned int>(FlagDescriptions[F].Default);
    186  1.1  kamil     if (FlagDescriptions[F].StrFlag)
    187  1.1  kamil       *FlagDescriptions[F].StrFlag = nullptr;
    188  1.1  kamil   }
    189  1.1  kamil   Inputs = new Vector<std::string>;
    190  1.1  kamil   for (size_t A = 1; A < Args.size(); A++) {
    191  1.1  kamil     if (ParseOneFlag(Args[A].c_str())) {
    192  1.1  kamil       if (Flags.ignore_remaining_args)
    193  1.1  kamil         break;
    194  1.1  kamil       continue;
    195  1.1  kamil     }
    196  1.1  kamil     Inputs->push_back(Args[A]);
    197  1.1  kamil   }
    198  1.1  kamil }
    199  1.1  kamil 
    200  1.1  kamil static std::mutex Mu;
    201  1.1  kamil 
    202  1.1  kamil static void PulseThread() {
    203  1.1  kamil   while (true) {
    204  1.1  kamil     SleepSeconds(600);
    205  1.1  kamil     std::lock_guard<std::mutex> Lock(Mu);
    206  1.1  kamil     Printf("pulse...\n");
    207  1.1  kamil   }
    208  1.1  kamil }
    209  1.1  kamil 
    210  1.1  kamil static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
    211  1.1  kamil                          unsigned NumJobs, std::atomic<bool> *HasErrors) {
    212  1.1  kamil   while (true) {
    213  1.1  kamil     unsigned C = (*Counter)++;
    214  1.1  kamil     if (C >= NumJobs) break;
    215  1.1  kamil     std::string Log = "fuzz-" + std::to_string(C) + ".log";
    216  1.1  kamil     Command Cmd(BaseCmd);
    217  1.1  kamil     Cmd.setOutputFile(Log);
    218  1.1  kamil     Cmd.combineOutAndErr();
    219  1.1  kamil     if (Flags.verbosity) {
    220  1.1  kamil       std::string CommandLine = Cmd.toString();
    221  1.1  kamil       Printf("%s\n", CommandLine.c_str());
    222  1.1  kamil     }
    223  1.1  kamil     int ExitCode = ExecuteCommand(Cmd);
    224  1.1  kamil     if (ExitCode != 0)
    225  1.1  kamil       *HasErrors = true;
    226  1.1  kamil     std::lock_guard<std::mutex> Lock(Mu);
    227  1.1  kamil     Printf("================== Job %u exited with exit code %d ============\n",
    228  1.1  kamil            C, ExitCode);
    229  1.1  kamil     fuzzer::CopyFileToErr(Log);
    230  1.1  kamil   }
    231  1.1  kamil }
    232  1.1  kamil 
    233  1.1  kamil std::string CloneArgsWithoutX(const Vector<std::string> &Args,
    234  1.1  kamil                               const char *X1, const char *X2) {
    235  1.1  kamil   std::string Cmd;
    236  1.1  kamil   for (auto &S : Args) {
    237  1.1  kamil     if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
    238  1.1  kamil       continue;
    239  1.1  kamil     Cmd += S + " ";
    240  1.1  kamil   }
    241  1.1  kamil   return Cmd;
    242  1.1  kamil }
    243  1.1  kamil 
    244  1.1  kamil static int RunInMultipleProcesses(const Vector<std::string> &Args,
    245  1.1  kamil                                   unsigned NumWorkers, unsigned NumJobs) {
    246  1.1  kamil   std::atomic<unsigned> Counter(0);
    247  1.1  kamil   std::atomic<bool> HasErrors(false);
    248  1.1  kamil   Command Cmd(Args);
    249  1.1  kamil   Cmd.removeFlag("jobs");
    250  1.1  kamil   Cmd.removeFlag("workers");
    251  1.1  kamil   Vector<std::thread> V;
    252  1.1  kamil   std::thread Pulse(PulseThread);
    253  1.1  kamil   Pulse.detach();
    254  1.1  kamil   for (unsigned i = 0; i < NumWorkers; i++)
    255  1.1  kamil     V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors));
    256  1.1  kamil   for (auto &T : V)
    257  1.1  kamil     T.join();
    258  1.1  kamil   return HasErrors ? 1 : 0;
    259  1.1  kamil }
    260  1.1  kamil 
    261  1.1  kamil static void RssThread(Fuzzer *F, size_t RssLimitMb) {
    262  1.1  kamil   while (true) {
    263  1.1  kamil     SleepSeconds(1);
    264  1.1  kamil     size_t Peak = GetPeakRSSMb();
    265  1.1  kamil     if (Peak > RssLimitMb)
    266  1.1  kamil       F->RssLimitCallback();
    267  1.1  kamil   }
    268  1.1  kamil }
    269  1.1  kamil 
    270  1.1  kamil static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
    271  1.1  kamil   if (!RssLimitMb) return;
    272  1.1  kamil   std::thread T(RssThread, F, RssLimitMb);
    273  1.1  kamil   T.detach();
    274  1.1  kamil }
    275  1.1  kamil 
    276  1.1  kamil int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
    277  1.1  kamil   Unit U = FileToVector(InputFilePath);
    278  1.1  kamil   if (MaxLen && MaxLen < U.size())
    279  1.1  kamil     U.resize(MaxLen);
    280  1.1  kamil   F->ExecuteCallback(U.data(), U.size());
    281  1.1  kamil   F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
    282  1.1  kamil   return 0;
    283  1.1  kamil }
    284  1.1  kamil 
    285  1.1  kamil static bool AllInputsAreFiles() {
    286  1.1  kamil   if (Inputs->empty()) return false;
    287  1.1  kamil   for (auto &Path : *Inputs)
    288  1.1  kamil     if (!IsFile(Path))
    289  1.1  kamil       return false;
    290  1.1  kamil   return true;
    291  1.1  kamil }
    292  1.1  kamil 
    293  1.1  kamil static std::string GetDedupTokenFromFile(const std::string &Path) {
    294  1.1  kamil   auto S = FileToString(Path);
    295  1.1  kamil   auto Beg = S.find("DEDUP_TOKEN:");
    296  1.1  kamil   if (Beg == std::string::npos)
    297  1.1  kamil     return "";
    298  1.1  kamil   auto End = S.find('\n', Beg);
    299  1.1  kamil   if (End == std::string::npos)
    300  1.1  kamil     return "";
    301  1.1  kamil   return S.substr(Beg, End - Beg);
    302  1.1  kamil }
    303  1.1  kamil 
    304  1.1  kamil int CleanseCrashInput(const Vector<std::string> &Args,
    305  1.1  kamil                        const FuzzingOptions &Options) {
    306  1.1  kamil   if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
    307  1.1  kamil     Printf("ERROR: -cleanse_crash should be given one input file and"
    308  1.1  kamil           " -exact_artifact_path\n");
    309  1.1  kamil     exit(1);
    310  1.1  kamil   }
    311  1.1  kamil   std::string InputFilePath = Inputs->at(0);
    312  1.1  kamil   std::string OutputFilePath = Flags.exact_artifact_path;
    313  1.1  kamil   Command Cmd(Args);
    314  1.1  kamil   Cmd.removeFlag("cleanse_crash");
    315  1.1  kamil 
    316  1.1  kamil   assert(Cmd.hasArgument(InputFilePath));
    317  1.1  kamil   Cmd.removeArgument(InputFilePath);
    318  1.1  kamil 
    319  1.1  kamil   auto LogFilePath = DirPlusFile(
    320  1.1  kamil       TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
    321  1.1  kamil   auto TmpFilePath = DirPlusFile(
    322  1.1  kamil       TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro");
    323  1.1  kamil   Cmd.addArgument(TmpFilePath);
    324  1.1  kamil   Cmd.setOutputFile(LogFilePath);
    325  1.1  kamil   Cmd.combineOutAndErr();
    326  1.1  kamil 
    327  1.1  kamil   std::string CurrentFilePath = InputFilePath;
    328  1.1  kamil   auto U = FileToVector(CurrentFilePath);
    329  1.1  kamil   size_t Size = U.size();
    330  1.1  kamil 
    331  1.1  kamil   const Vector<uint8_t> ReplacementBytes = {' ', 0xff};
    332  1.1  kamil   for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
    333  1.1  kamil     bool Changed = false;
    334  1.1  kamil     for (size_t Idx = 0; Idx < Size; Idx++) {
    335  1.1  kamil       Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts,
    336  1.1  kamil              Idx, Size);
    337  1.1  kamil       uint8_t OriginalByte = U[Idx];
    338  1.1  kamil       if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(),
    339  1.1  kamil                                               ReplacementBytes.end(),
    340  1.1  kamil                                               OriginalByte))
    341  1.1  kamil         continue;
    342  1.1  kamil       for (auto NewByte : ReplacementBytes) {
    343  1.1  kamil         U[Idx] = NewByte;
    344  1.1  kamil         WriteToFile(U, TmpFilePath);
    345  1.1  kamil         auto ExitCode = ExecuteCommand(Cmd);
    346  1.1  kamil         RemoveFile(TmpFilePath);
    347  1.1  kamil         if (!ExitCode) {
    348  1.1  kamil           U[Idx] = OriginalByte;
    349  1.1  kamil         } else {
    350  1.1  kamil           Changed = true;
    351  1.1  kamil           Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte);
    352  1.1  kamil           WriteToFile(U, OutputFilePath);
    353  1.1  kamil           break;
    354  1.1  kamil         }
    355  1.1  kamil       }
    356  1.1  kamil     }
    357  1.1  kamil     if (!Changed) break;
    358  1.1  kamil   }
    359  1.1  kamil   RemoveFile(LogFilePath);
    360  1.1  kamil   return 0;
    361  1.1  kamil }
    362  1.1  kamil 
    363  1.1  kamil int MinimizeCrashInput(const Vector<std::string> &Args,
    364  1.1  kamil                        const FuzzingOptions &Options) {
    365  1.1  kamil   if (Inputs->size() != 1) {
    366  1.1  kamil     Printf("ERROR: -minimize_crash should be given one input file\n");
    367  1.1  kamil     exit(1);
    368  1.1  kamil   }
    369  1.1  kamil   std::string InputFilePath = Inputs->at(0);
    370  1.1  kamil   Command BaseCmd(Args);
    371  1.1  kamil   BaseCmd.removeFlag("minimize_crash");
    372  1.1  kamil   BaseCmd.removeFlag("exact_artifact_path");
    373  1.1  kamil   assert(BaseCmd.hasArgument(InputFilePath));
    374  1.1  kamil   BaseCmd.removeArgument(InputFilePath);
    375  1.1  kamil   if (Flags.runs <= 0 && Flags.max_total_time == 0) {
    376  1.1  kamil     Printf("INFO: you need to specify -runs=N or "
    377  1.1  kamil            "-max_total_time=N with -minimize_crash=1\n"
    378  1.1  kamil            "INFO: defaulting to -max_total_time=600\n");
    379  1.1  kamil     BaseCmd.addFlag("max_total_time", "600");
    380  1.1  kamil   }
    381  1.1  kamil 
    382  1.1  kamil   auto LogFilePath = DirPlusFile(
    383  1.1  kamil       TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt");
    384  1.1  kamil   BaseCmd.setOutputFile(LogFilePath);
    385  1.1  kamil   BaseCmd.combineOutAndErr();
    386  1.1  kamil 
    387  1.1  kamil   std::string CurrentFilePath = InputFilePath;
    388  1.1  kamil   while (true) {
    389  1.1  kamil     Unit U = FileToVector(CurrentFilePath);
    390  1.1  kamil     Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
    391  1.1  kamil            CurrentFilePath.c_str(), U.size());
    392  1.1  kamil 
    393  1.1  kamil     Command Cmd(BaseCmd);
    394  1.1  kamil     Cmd.addArgument(CurrentFilePath);
    395  1.1  kamil 
    396  1.1  kamil     std::string CommandLine = Cmd.toString();
    397  1.1  kamil     Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str());
    398  1.1  kamil     int ExitCode = ExecuteCommand(Cmd);
    399  1.1  kamil     if (ExitCode == 0) {
    400  1.1  kamil       Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
    401  1.1  kamil       exit(1);
    402  1.1  kamil     }
    403  1.1  kamil     Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
    404  1.1  kamil            "it further\n",
    405  1.1  kamil            CurrentFilePath.c_str(), U.size());
    406  1.1  kamil     auto DedupToken1 = GetDedupTokenFromFile(LogFilePath);
    407  1.1  kamil     if (!DedupToken1.empty())
    408  1.1  kamil       Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str());
    409  1.1  kamil 
    410  1.1  kamil     std::string ArtifactPath =
    411  1.1  kamil         Flags.exact_artifact_path
    412  1.1  kamil             ? Flags.exact_artifact_path
    413  1.1  kamil             : Options.ArtifactPrefix + "minimized-from-" + Hash(U);
    414  1.1  kamil     Cmd.addFlag("minimize_crash_internal_step", "1");
    415  1.1  kamil     Cmd.addFlag("exact_artifact_path", ArtifactPath);
    416  1.1  kamil     CommandLine = Cmd.toString();
    417  1.1  kamil     Printf("CRASH_MIN: executing: %s\n", CommandLine.c_str());
    418  1.1  kamil     ExitCode = ExecuteCommand(Cmd);
    419  1.1  kamil     CopyFileToErr(LogFilePath);
    420  1.1  kamil     if (ExitCode == 0) {
    421  1.1  kamil       if (Flags.exact_artifact_path) {
    422  1.1  kamil         CurrentFilePath = Flags.exact_artifact_path;
    423  1.1  kamil         WriteToFile(U, CurrentFilePath);
    424  1.1  kamil       }
    425  1.1  kamil       Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
    426  1.1  kamil              CurrentFilePath.c_str(), U.size());
    427  1.1  kamil       break;
    428  1.1  kamil     }
    429  1.1  kamil     auto DedupToken2 = GetDedupTokenFromFile(LogFilePath);
    430  1.1  kamil     if (!DedupToken2.empty())
    431  1.1  kamil       Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str());
    432  1.1  kamil 
    433  1.1  kamil     if (DedupToken1 != DedupToken2) {
    434  1.1  kamil       if (Flags.exact_artifact_path) {
    435  1.1  kamil         CurrentFilePath = Flags.exact_artifact_path;
    436  1.1  kamil         WriteToFile(U, CurrentFilePath);
    437  1.1  kamil       }
    438  1.1  kamil       Printf("CRASH_MIN: mismatch in dedup tokens"
    439  1.1  kamil              " (looks like a different bug). Won't minimize further\n");
    440  1.1  kamil       break;
    441  1.1  kamil     }
    442  1.1  kamil 
    443  1.1  kamil     CurrentFilePath = ArtifactPath;
    444  1.1  kamil     Printf("*********************************\n");
    445  1.1  kamil   }
    446  1.1  kamil   RemoveFile(LogFilePath);
    447  1.1  kamil   return 0;
    448  1.1  kamil }
    449  1.1  kamil 
    450  1.1  kamil int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
    451  1.1  kamil   assert(Inputs->size() == 1);
    452  1.1  kamil   std::string InputFilePath = Inputs->at(0);
    453  1.1  kamil   Unit U = FileToVector(InputFilePath);
    454  1.1  kamil   Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
    455  1.1  kamil   if (U.size() < 2) {
    456  1.1  kamil     Printf("INFO: The input is small enough, exiting\n");
    457  1.1  kamil     exit(0);
    458  1.1  kamil   }
    459  1.1  kamil   F->SetMaxInputLen(U.size());
    460  1.1  kamil   F->SetMaxMutationLen(U.size() - 1);
    461  1.1  kamil   F->MinimizeCrashLoop(U);
    462  1.1  kamil   Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
    463  1.1  kamil   exit(0);
    464  1.1  kamil   return 0;
    465  1.1  kamil }
    466  1.1  kamil 
    467  1.1  kamil int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict,
    468  1.1  kamil                       UnitVector& Corpus) {
    469  1.1  kamil   Printf("Started dictionary minimization (up to %d tests)\n",
    470  1.1  kamil          Dict.size() * Corpus.size() * 2);
    471  1.1  kamil 
    472  1.1  kamil   // Scores and usage count for each dictionary unit.
    473  1.1  kamil   Vector<int> Scores(Dict.size());
    474  1.1  kamil   Vector<int> Usages(Dict.size());
    475  1.1  kamil 
    476  1.1  kamil   Vector<size_t> InitialFeatures;
    477  1.1  kamil   Vector<size_t> ModifiedFeatures;
    478  1.1  kamil   for (auto &C : Corpus) {
    479  1.1  kamil     // Get coverage for the testcase without modifications.
    480  1.1  kamil     F->ExecuteCallback(C.data(), C.size());
    481  1.1  kamil     InitialFeatures.clear();
    482  1.1  kamil     TPC.CollectFeatures([&](size_t Feature) {
    483  1.1  kamil       InitialFeatures.push_back(Feature);
    484  1.1  kamil     });
    485  1.1  kamil 
    486  1.1  kamil     for (size_t i = 0; i < Dict.size(); ++i) {
    487  1.1  kamil       Vector<uint8_t> Data = C;
    488  1.1  kamil       auto StartPos = std::search(Data.begin(), Data.end(),
    489  1.1  kamil                                   Dict[i].begin(), Dict[i].end());
    490  1.1  kamil       // Skip dictionary unit, if the testcase does not contain it.
    491  1.1  kamil       if (StartPos == Data.end())
    492  1.1  kamil         continue;
    493  1.1  kamil 
    494  1.1  kamil       ++Usages[i];
    495  1.1  kamil       while (StartPos != Data.end()) {
    496  1.1  kamil         // Replace all occurrences of dictionary unit in the testcase.
    497  1.1  kamil         auto EndPos = StartPos + Dict[i].size();
    498  1.1  kamil         for (auto It = StartPos; It != EndPos; ++It)
    499  1.1  kamil           *It ^= 0xFF;
    500  1.1  kamil 
    501  1.1  kamil         StartPos = std::search(EndPos, Data.end(),
    502  1.1  kamil                                Dict[i].begin(), Dict[i].end());
    503  1.1  kamil       }
    504  1.1  kamil 
    505  1.1  kamil       // Get coverage for testcase with masked occurrences of dictionary unit.
    506  1.1  kamil       F->ExecuteCallback(Data.data(), Data.size());
    507  1.1  kamil       ModifiedFeatures.clear();
    508  1.1  kamil       TPC.CollectFeatures([&](size_t Feature) {
    509  1.1  kamil         ModifiedFeatures.push_back(Feature);
    510  1.1  kamil       });
    511  1.1  kamil 
    512  1.1  kamil       if (InitialFeatures == ModifiedFeatures)
    513  1.1  kamil         --Scores[i];
    514  1.1  kamil       else
    515  1.1  kamil         Scores[i] += 2;
    516  1.1  kamil     }
    517  1.1  kamil   }
    518  1.1  kamil 
    519  1.1  kamil   Printf("###### Useless dictionary elements. ######\n");
    520  1.1  kamil   for (size_t i = 0; i < Dict.size(); ++i) {
    521  1.1  kamil     // Dictionary units with positive score are treated as useful ones.
    522  1.1  kamil     if (Scores[i] > 0)
    523  1.1  kamil        continue;
    524  1.1  kamil 
    525  1.1  kamil     Printf("\"");
    526  1.1  kamil     PrintASCII(Dict[i].data(), Dict[i].size(), "\"");
    527  1.1  kamil     Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]);
    528  1.1  kamil   }
    529  1.1  kamil   Printf("###### End of useless dictionary elements. ######\n");
    530  1.1  kamil   return 0;
    531  1.1  kamil }
    532  1.1  kamil 
    533  1.1  kamil int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
    534  1.1  kamil   using namespace fuzzer;
    535  1.1  kamil   assert(argc && argv && "Argument pointers cannot be nullptr");
    536  1.1  kamil   std::string Argv0((*argv)[0]);
    537  1.1  kamil   EF = new ExternalFunctions();
    538  1.1  kamil   if (EF->LLVMFuzzerInitialize)
    539  1.1  kamil     EF->LLVMFuzzerInitialize(argc, argv);
    540  1.1  kamil   if (EF->__msan_scoped_disable_interceptor_checks)
    541  1.1  kamil     EF->__msan_scoped_disable_interceptor_checks();
    542  1.1  kamil   const Vector<std::string> Args(*argv, *argv + *argc);
    543  1.1  kamil   assert(!Args.empty());
    544  1.1  kamil   ProgName = new std::string(Args[0]);
    545  1.1  kamil   if (Argv0 != *ProgName) {
    546  1.1  kamil     Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
    547  1.1  kamil     exit(1);
    548  1.1  kamil   }
    549  1.1  kamil   ParseFlags(Args);
    550  1.1  kamil   if (Flags.help) {
    551  1.1  kamil     PrintHelp();
    552  1.1  kamil     return 0;
    553  1.1  kamil   }
    554  1.1  kamil 
    555  1.1  kamil   if (Flags.close_fd_mask & 2)
    556  1.1  kamil     DupAndCloseStderr();
    557  1.1  kamil   if (Flags.close_fd_mask & 1)
    558  1.1  kamil     CloseStdout();
    559  1.1  kamil 
    560  1.1  kamil   if (Flags.jobs > 0 && Flags.workers == 0) {
    561  1.1  kamil     Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
    562  1.1  kamil     if (Flags.workers > 1)
    563  1.1  kamil       Printf("Running %u workers\n", Flags.workers);
    564  1.1  kamil   }
    565  1.1  kamil 
    566  1.1  kamil   if (Flags.workers > 0 && Flags.jobs > 0)
    567  1.1  kamil     return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
    568  1.1  kamil 
    569  1.1  kamil   FuzzingOptions Options;
    570  1.1  kamil   Options.Verbosity = Flags.verbosity;
    571  1.1  kamil   Options.MaxLen = Flags.max_len;
    572  1.1  kamil   Options.LenControl = Flags.len_control;
    573  1.1  kamil   Options.UnitTimeoutSec = Flags.timeout;
    574  1.1  kamil   Options.ErrorExitCode = Flags.error_exitcode;
    575  1.1  kamil   Options.TimeoutExitCode = Flags.timeout_exitcode;
    576  1.1  kamil   Options.MaxTotalTimeSec = Flags.max_total_time;
    577  1.1  kamil   Options.DoCrossOver = Flags.cross_over;
    578  1.1  kamil   Options.MutateDepth = Flags.mutate_depth;
    579  1.1  kamil   Options.ReduceDepth = Flags.reduce_depth;
    580  1.1  kamil   Options.UseCounters = Flags.use_counters;
    581  1.1  kamil   Options.UseMemmem = Flags.use_memmem;
    582  1.1  kamil   Options.UseCmp = Flags.use_cmp;
    583  1.1  kamil   Options.UseValueProfile = Flags.use_value_profile;
    584  1.1  kamil   Options.Shrink = Flags.shrink;
    585  1.1  kamil   Options.ReduceInputs = Flags.reduce_inputs;
    586  1.1  kamil   Options.ShuffleAtStartUp = Flags.shuffle;
    587  1.1  kamil   Options.PreferSmall = Flags.prefer_small;
    588  1.1  kamil   Options.ReloadIntervalSec = Flags.reload;
    589  1.1  kamil   Options.OnlyASCII = Flags.only_ascii;
    590  1.1  kamil   Options.DetectLeaks = Flags.detect_leaks;
    591  1.1  kamil   Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval;
    592  1.1  kamil   Options.TraceMalloc = Flags.trace_malloc;
    593  1.1  kamil   Options.RssLimitMb = Flags.rss_limit_mb;
    594  1.1  kamil   Options.MallocLimitMb = Flags.malloc_limit_mb;
    595  1.1  kamil   if (!Options.MallocLimitMb)
    596  1.1  kamil     Options.MallocLimitMb = Options.RssLimitMb;
    597  1.1  kamil   if (Flags.runs >= 0)
    598  1.1  kamil     Options.MaxNumberOfRuns = Flags.runs;
    599  1.1  kamil   if (!Inputs->empty() && !Flags.minimize_crash_internal_step)
    600  1.1  kamil     Options.OutputCorpus = (*Inputs)[0];
    601  1.1  kamil   Options.ReportSlowUnits = Flags.report_slow_units;
    602  1.1  kamil   if (Flags.artifact_prefix)
    603  1.1  kamil     Options.ArtifactPrefix = Flags.artifact_prefix;
    604  1.1  kamil   if (Flags.exact_artifact_path)
    605  1.1  kamil     Options.ExactArtifactPath = Flags.exact_artifact_path;
    606  1.1  kamil   Vector<Unit> Dictionary;
    607  1.1  kamil   if (Flags.dict)
    608  1.1  kamil     if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
    609  1.1  kamil       return 1;
    610  1.1  kamil   if (Flags.verbosity > 0 && !Dictionary.empty())
    611  1.1  kamil     Printf("Dictionary: %zd entries\n", Dictionary.size());
    612  1.1  kamil   bool DoPlainRun = AllInputsAreFiles();
    613  1.1  kamil   Options.SaveArtifacts =
    614  1.1  kamil       !DoPlainRun || Flags.minimize_crash_internal_step;
    615  1.1  kamil   Options.PrintNewCovPcs = Flags.print_pcs;
    616  1.1  kamil   Options.PrintNewCovFuncs = Flags.print_funcs;
    617  1.1  kamil   Options.PrintFinalStats = Flags.print_final_stats;
    618  1.1  kamil   Options.PrintCorpusStats = Flags.print_corpus_stats;
    619  1.1  kamil   Options.PrintCoverage = Flags.print_coverage;
    620  1.1  kamil   Options.PrintUnstableStats = Flags.print_unstable_stats;
    621  1.1  kamil   if (Flags.handle_unstable == TracePC::MinUnstable ||
    622  1.1  kamil       Flags.handle_unstable == TracePC::ZeroUnstable)
    623  1.1  kamil     Options.HandleUnstable = Flags.handle_unstable;
    624  1.1  kamil   Options.DumpCoverage = Flags.dump_coverage;
    625  1.1  kamil   if (Flags.exit_on_src_pos)
    626  1.1  kamil     Options.ExitOnSrcPos = Flags.exit_on_src_pos;
    627  1.1  kamil   if (Flags.exit_on_item)
    628  1.1  kamil     Options.ExitOnItem = Flags.exit_on_item;
    629  1.1  kamil   if (Flags.focus_function)
    630  1.1  kamil     Options.FocusFunction = Flags.focus_function;
    631  1.1  kamil   if (Flags.data_flow_trace)
    632  1.1  kamil     Options.DataFlowTrace = Flags.data_flow_trace;
    633  1.1  kamil 
    634  1.1  kamil   unsigned Seed = Flags.seed;
    635  1.1  kamil   // Initialize Seed.
    636  1.1  kamil   if (Seed == 0)
    637  1.1  kamil     Seed =
    638  1.1  kamil         std::chrono::system_clock::now().time_since_epoch().count() + GetPid();
    639  1.1  kamil   if (Flags.verbosity)
    640  1.1  kamil     Printf("INFO: Seed: %u\n", Seed);
    641  1.1  kamil 
    642  1.1  kamil   Random Rand(Seed);
    643  1.1  kamil   auto *MD = new MutationDispatcher(Rand, Options);
    644  1.1  kamil   auto *Corpus = new InputCorpus(Options.OutputCorpus);
    645  1.1  kamil   auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
    646  1.1  kamil 
    647  1.1  kamil   for (auto &U: Dictionary)
    648  1.1  kamil     if (U.size() <= Word::GetMaxSize())
    649  1.1  kamil       MD->AddWordToManualDictionary(Word(U.data(), U.size()));
    650  1.1  kamil 
    651  1.1  kamil   StartRssThread(F, Flags.rss_limit_mb);
    652  1.1  kamil 
    653  1.1  kamil   Options.HandleAbrt = Flags.handle_abrt;
    654  1.1  kamil   Options.HandleBus = Flags.handle_bus;
    655  1.1  kamil   Options.HandleFpe = Flags.handle_fpe;
    656  1.1  kamil   Options.HandleIll = Flags.handle_ill;
    657  1.1  kamil   Options.HandleInt = Flags.handle_int;
    658  1.1  kamil   Options.HandleSegv = Flags.handle_segv;
    659  1.1  kamil   Options.HandleTerm = Flags.handle_term;
    660  1.1  kamil   Options.HandleXfsz = Flags.handle_xfsz;
    661  1.1  kamil   Options.HandleUsr1 = Flags.handle_usr1;
    662  1.1  kamil   Options.HandleUsr2 = Flags.handle_usr2;
    663  1.1  kamil   SetSignalHandler(Options);
    664  1.1  kamil 
    665  1.1  kamil   std::atexit(Fuzzer::StaticExitCallback);
    666  1.1  kamil 
    667  1.1  kamil   if (Flags.minimize_crash)
    668  1.1  kamil     return MinimizeCrashInput(Args, Options);
    669  1.1  kamil 
    670  1.1  kamil   if (Flags.minimize_crash_internal_step)
    671  1.1  kamil     return MinimizeCrashInputInternalStep(F, Corpus);
    672  1.1  kamil 
    673  1.1  kamil   if (Flags.cleanse_crash)
    674  1.1  kamil     return CleanseCrashInput(Args, Options);
    675  1.1  kamil 
    676  1.1  kamil #if 0  // deprecated, to be removed.
    677  1.1  kamil   if (auto Name = Flags.run_equivalence_server) {
    678  1.1  kamil     SMR.Destroy(Name);
    679  1.1  kamil     if (!SMR.Create(Name)) {
    680  1.1  kamil        Printf("ERROR: can't create shared memory region\n");
    681  1.1  kamil       return 1;
    682  1.1  kamil     }
    683  1.1  kamil     Printf("INFO: EQUIVALENCE SERVER UP\n");
    684  1.1  kamil     while (true) {
    685  1.1  kamil       SMR.WaitClient();
    686  1.1  kamil       size_t Size = SMR.ReadByteArraySize();
    687  1.1  kamil       SMR.WriteByteArray(nullptr, 0);
    688  1.1  kamil       const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size);
    689  1.1  kamil       F->ExecuteCallback(tmp.data(), tmp.size());
    690  1.1  kamil       SMR.PostServer();
    691  1.1  kamil     }
    692  1.1  kamil     return 0;
    693  1.1  kamil   }
    694  1.1  kamil 
    695  1.1  kamil   if (auto Name = Flags.use_equivalence_server) {
    696  1.1  kamil     if (!SMR.Open(Name)) {
    697  1.1  kamil       Printf("ERROR: can't open shared memory region\n");
    698  1.1  kamil       return 1;
    699  1.1  kamil     }
    700  1.1  kamil     Printf("INFO: EQUIVALENCE CLIENT UP\n");
    701  1.1  kamil   }
    702  1.1  kamil #endif
    703  1.1  kamil 
    704  1.1  kamil   if (DoPlainRun) {
    705  1.1  kamil     Options.SaveArtifacts = false;
    706  1.1  kamil     int Runs = std::max(1, Flags.runs);
    707  1.1  kamil     Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
    708  1.1  kamil            Inputs->size(), Runs);
    709  1.1  kamil     for (auto &Path : *Inputs) {
    710  1.1  kamil       auto StartTime = system_clock::now();
    711  1.1  kamil       Printf("Running: %s\n", Path.c_str());
    712  1.1  kamil       for (int Iter = 0; Iter < Runs; Iter++)
    713  1.1  kamil         RunOneTest(F, Path.c_str(), Options.MaxLen);
    714  1.1  kamil       auto StopTime = system_clock::now();
    715  1.1  kamil       auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
    716  1.1  kamil       Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS);
    717  1.1  kamil     }
    718  1.1  kamil     Printf("***\n"
    719  1.1  kamil            "*** NOTE: fuzzing was not performed, you have only\n"
    720  1.1  kamil            "***       executed the target code on a fixed set of inputs.\n"
    721  1.1  kamil            "***\n");
    722  1.1  kamil     F->PrintFinalStats();
    723  1.1  kamil     exit(0);
    724  1.1  kamil   }
    725  1.1  kamil 
    726  1.1  kamil   if (Flags.merge) {
    727  1.1  kamil     F->CrashResistantMerge(Args, *Inputs,
    728  1.1  kamil                            Flags.load_coverage_summary,
    729  1.1  kamil                            Flags.save_coverage_summary,
    730  1.1  kamil                            Flags.merge_control_file);
    731  1.1  kamil     exit(0);
    732  1.1  kamil   }
    733  1.1  kamil 
    734  1.1  kamil   if (Flags.merge_inner) {
    735  1.1  kamil     const size_t kDefaultMaxMergeLen = 1 << 20;
    736  1.1  kamil     if (Options.MaxLen == 0)
    737  1.1  kamil       F->SetMaxInputLen(kDefaultMaxMergeLen);
    738  1.1  kamil     assert(Flags.merge_control_file);
    739  1.1  kamil     F->CrashResistantMergeInternalStep(Flags.merge_control_file);
    740  1.1  kamil     exit(0);
    741  1.1  kamil   }
    742  1.1  kamil 
    743  1.1  kamil   if (Flags.analyze_dict) {
    744  1.1  kamil     size_t MaxLen = INT_MAX;  // Large max length.
    745  1.1  kamil     UnitVector InitialCorpus;
    746  1.1  kamil     for (auto &Inp : *Inputs) {
    747  1.1  kamil       Printf("Loading corpus dir: %s\n", Inp.c_str());
    748  1.1  kamil       ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
    749  1.1  kamil                              MaxLen, /*ExitOnError=*/false);
    750  1.1  kamil     }
    751  1.1  kamil 
    752  1.1  kamil     if (Dictionary.empty() || Inputs->empty()) {
    753  1.1  kamil       Printf("ERROR: can't analyze dict without dict and corpus provided\n");
    754  1.1  kamil       return 1;
    755  1.1  kamil     }
    756  1.1  kamil     if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
    757  1.1  kamil       Printf("Dictionary analysis failed\n");
    758  1.1  kamil       exit(1);
    759  1.1  kamil     }
    760  1.1  kamil     Printf("Dictionary analysis succeeded\n");
    761  1.1  kamil     exit(0);
    762  1.1  kamil   }
    763  1.1  kamil 
    764  1.1  kamil   F->Loop(*Inputs);
    765  1.1  kamil 
    766  1.1  kamil   if (Flags.verbosity)
    767  1.1  kamil     Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
    768  1.1  kamil            F->secondsSinceProcessStartUp());
    769  1.1  kamil   F->PrintFinalStats();
    770  1.1  kamil 
    771  1.1  kamil   exit(0);  // Don't let F destroy itself.
    772  1.1  kamil }
    773  1.1  kamil 
    774  1.1  kamil // Storage for global ExternalFunctions object.
    775  1.1  kamil ExternalFunctions *EF = nullptr;
    776  1.1  kamil 
    777  1.1  kamil }  // namespace fuzzer
    778