1//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// FuzzerDriver and flag parsing. 10//===----------------------------------------------------------------------===// 11 12#include "FuzzerCorpus.h" 13#include "FuzzerInterface.h" 14#include "FuzzerInternal.h" 15#include "FuzzerIO.h" 16#include "FuzzerMutate.h" 17#include "FuzzerRandom.h" 18#include "FuzzerTracePC.h" 19#include <algorithm> 20#include <atomic> 21#include <chrono> 22#include <cstring> 23#include <mutex> 24#include <string> 25#include <thread> 26 27// This function should be present in the libFuzzer so that the client 28// binary can test for its existence. 29extern "C" __attribute__((used)) void __libfuzzer_is_present() {} 30 31namespace fuzzer { 32 33// Program arguments. 34struct FlagDescription { 35 const char *Name; 36 const char *Description; 37 int Default; 38 int *IntFlag; 39 const char **StrFlag; 40 unsigned int *UIntFlag; 41}; 42 43struct { 44#define FUZZER_DEPRECATED_FLAG(Name) 45#define FUZZER_FLAG_INT(Name, Default, Description) int Name; 46#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; 47#define FUZZER_FLAG_STRING(Name, Description) const char *Name; 48#include "FuzzerFlags.def" 49#undef FUZZER_DEPRECATED_FLAG 50#undef FUZZER_FLAG_INT 51#undef FUZZER_FLAG_UNSIGNED 52#undef FUZZER_FLAG_STRING 53} Flags; 54 55static const FlagDescription FlagDescriptions [] { 56#define FUZZER_DEPRECATED_FLAG(Name) \ 57 {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, 58#define FUZZER_FLAG_INT(Name, Default, Description) \ 59 {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, 60#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ 61 {#Name, Description, static_cast<int>(Default), \ 62 nullptr, nullptr, &Flags.Name}, 63#define FUZZER_FLAG_STRING(Name, Description) \ 64 {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, 65#include "FuzzerFlags.def" 66#undef FUZZER_DEPRECATED_FLAG 67#undef FUZZER_FLAG_INT 68#undef FUZZER_FLAG_UNSIGNED 69#undef FUZZER_FLAG_STRING 70}; 71 72static const size_t kNumFlags = 73 sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); 74 75static std::vector<std::string> *Inputs; 76static std::string *ProgName; 77 78static void PrintHelp() { 79 Printf("Usage:\n"); 80 auto Prog = ProgName->c_str(); 81 Printf("\nTo run fuzzing pass 0 or more directories.\n"); 82 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog); 83 84 Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n"); 85 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog); 86 87 Printf("\nFlags: (strictly in form -flag=value)\n"); 88 size_t MaxFlagLen = 0; 89 for (size_t F = 0; F < kNumFlags; F++) 90 MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen); 91 92 for (size_t F = 0; F < kNumFlags; F++) { 93 const auto &D = FlagDescriptions[F]; 94 if (strstr(D.Description, "internal flag") == D.Description) continue; 95 Printf(" %s", D.Name); 96 for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) 97 Printf(" "); 98 Printf("\t"); 99 Printf("%d\t%s\n", D.Default, D.Description); 100 } 101 Printf("\nFlags starting with '--' will be ignored and " 102 "will be passed verbatim to subprocesses.\n"); 103} 104 105static const char *FlagValue(const char *Param, const char *Name) { 106 size_t Len = strlen(Name); 107 if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 && 108 Param[Len + 1] == '=') 109 return &Param[Len + 2]; 110 return nullptr; 111} 112 113// Avoid calling stol as it triggers a bug in clang/glibc build. 114static long MyStol(const char *Str) { 115 long Res = 0; 116 long Sign = 1; 117 if (*Str == '-') { 118 Str++; 119 Sign = -1; 120 } 121 for (size_t i = 0; Str[i]; i++) { 122 char Ch = Str[i]; 123 if (Ch < '0' || Ch > '9') 124 return Res; 125 Res = Res * 10 + (Ch - '0'); 126 } 127 return Res * Sign; 128} 129 130static bool ParseOneFlag(const char *Param) { 131 if (Param[0] != '-') return false; 132 if (Param[1] == '-') { 133 static bool PrintedWarning = false; 134 if (!PrintedWarning) { 135 PrintedWarning = true; 136 Printf("INFO: libFuzzer ignores flags that start with '--'\n"); 137 } 138 for (size_t F = 0; F < kNumFlags; F++) 139 if (FlagValue(Param + 1, FlagDescriptions[F].Name)) 140 Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1); 141 return true; 142 } 143 for (size_t F = 0; F < kNumFlags; F++) { 144 const char *Name = FlagDescriptions[F].Name; 145 const char *Str = FlagValue(Param, Name); 146 if (Str) { 147 if (FlagDescriptions[F].IntFlag) { 148 int Val = MyStol(Str); 149 *FlagDescriptions[F].IntFlag = Val; 150 if (Flags.verbosity >= 2) 151 Printf("Flag: %s %d\n", Name, Val); 152 return true; 153 } else if (FlagDescriptions[F].UIntFlag) { 154 unsigned int Val = std::stoul(Str); 155 *FlagDescriptions[F].UIntFlag = Val; 156 if (Flags.verbosity >= 2) 157 Printf("Flag: %s %u\n", Name, Val); 158 return true; 159 } else if (FlagDescriptions[F].StrFlag) { 160 *FlagDescriptions[F].StrFlag = Str; 161 if (Flags.verbosity >= 2) 162 Printf("Flag: %s %s\n", Name, Str); 163 return true; 164 } else { // Deprecated flag. 165 Printf("Flag: %s: deprecated, don't use\n", Name); 166 return true; 167 } 168 } 169 } 170 Printf("\n\nWARNING: unrecognized flag '%s'; " 171 "use -help=1 to list all flags\n\n", Param); 172 return true; 173} 174 175// We don't use any library to minimize dependencies. 176static void ParseFlags(const std::vector<std::string> &Args) { 177 for (size_t F = 0; F < kNumFlags; F++) { 178 if (FlagDescriptions[F].IntFlag) 179 *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default; 180 if (FlagDescriptions[F].UIntFlag) 181 *FlagDescriptions[F].UIntFlag = 182 static_cast<unsigned int>(FlagDescriptions[F].Default); 183 if (FlagDescriptions[F].StrFlag) 184 *FlagDescriptions[F].StrFlag = nullptr; 185 } 186 Inputs = new std::vector<std::string>; 187 for (size_t A = 1; A < Args.size(); A++) { 188 if (ParseOneFlag(Args[A].c_str())) continue; 189 Inputs->push_back(Args[A]); 190 } 191} 192 193static std::mutex Mu; 194 195static void PulseThread() { 196 while (true) { 197 SleepSeconds(600); 198 std::lock_guard<std::mutex> Lock(Mu); 199 Printf("pulse...\n"); 200 } 201} 202 203static void WorkerThread(const std::string &Cmd, std::atomic<unsigned> *Counter, 204 unsigned NumJobs, std::atomic<bool> *HasErrors) { 205 while (true) { 206 unsigned C = (*Counter)++; 207 if (C >= NumJobs) break; 208 std::string Log = "fuzz-" + std::to_string(C) + ".log"; 209 std::string ToRun = Cmd + " > " + Log + " 2>&1\n"; 210 if (Flags.verbosity) 211 Printf("%s", ToRun.c_str()); 212 int ExitCode = ExecuteCommand(ToRun); 213 if (ExitCode != 0) 214 *HasErrors = true; 215 std::lock_guard<std::mutex> Lock(Mu); 216 Printf("================== Job %u exited with exit code %d ============\n", 217 C, ExitCode); 218 fuzzer::CopyFileToErr(Log); 219 } 220} 221 222std::string CloneArgsWithoutX(const std::vector<std::string> &Args, 223 const char *X1, const char *X2) { 224 std::string Cmd; 225 for (auto &S : Args) { 226 if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2)) 227 continue; 228 Cmd += S + " "; 229 } 230 return Cmd; 231} 232 233static int RunInMultipleProcesses(const std::vector<std::string> &Args, 234 unsigned NumWorkers, unsigned NumJobs) { 235 std::atomic<unsigned> Counter(0); 236 std::atomic<bool> HasErrors(false); 237 std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers"); 238 std::vector<std::thread> V; 239 std::thread Pulse(PulseThread); 240 Pulse.detach(); 241 for (unsigned i = 0; i < NumWorkers; i++) 242 V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors)); 243 for (auto &T : V) 244 T.join(); 245 return HasErrors ? 1 : 0; 246} 247 248static void RssThread(Fuzzer *F, size_t RssLimitMb) { 249 while (true) { 250 SleepSeconds(1); 251 size_t Peak = GetPeakRSSMb(); 252 if (Peak > RssLimitMb) 253 F->RssLimitCallback(); 254 } 255} 256 257static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { 258 if (!RssLimitMb) return; 259 std::thread T(RssThread, F, RssLimitMb); 260 T.detach(); 261} 262 263int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { 264 Unit U = FileToVector(InputFilePath); 265 if (MaxLen && MaxLen < U.size()) 266 U.resize(MaxLen); 267 F->RunOne(U.data(), U.size()); 268 F->TryDetectingAMemoryLeak(U.data(), U.size(), true); 269 return 0; 270} 271 272static bool AllInputsAreFiles() { 273 if (Inputs->empty()) return false; 274 for (auto &Path : *Inputs) 275 if (!IsFile(Path)) 276 return false; 277 return true; 278} 279 280int MinimizeCrashInput(const std::vector<std::string> &Args) { 281 if (Inputs->size() != 1) { 282 Printf("ERROR: -minimize_crash should be given one input file\n"); 283 exit(1); 284 } 285 std::string InputFilePath = Inputs->at(0); 286 std::string BaseCmd = 287 CloneArgsWithoutX(Args, "minimize_crash", "exact_artifact_path"); 288 auto InputPos = BaseCmd.find(" " + InputFilePath + " "); 289 assert(InputPos != std::string::npos); 290 BaseCmd.erase(InputPos, InputFilePath.size() + 1); 291 if (Flags.runs <= 0 && Flags.max_total_time == 0) { 292 Printf("INFO: you need to specify -runs=N or " 293 "-max_total_time=N with -minimize_crash=1\n" 294 "INFO: defaulting to -max_total_time=600\n"); 295 BaseCmd += " -max_total_time=600"; 296 } 297 // BaseCmd += " > /dev/null 2>&1 "; 298 299 std::string CurrentFilePath = InputFilePath; 300 while (true) { 301 Unit U = FileToVector(CurrentFilePath); 302 if (U.size() < 2) { 303 Printf("CRASH_MIN: '%s' is small enough\n", CurrentFilePath.c_str()); 304 return 0; 305 } 306 Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n", 307 CurrentFilePath.c_str(), U.size()); 308 309 auto Cmd = BaseCmd + " " + CurrentFilePath; 310 311 Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); 312 int ExitCode = ExecuteCommand(Cmd); 313 if (ExitCode == 0) { 314 Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str()); 315 exit(1); 316 } 317 Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize " 318 "it further\n", 319 CurrentFilePath.c_str(), U.size()); 320 321 std::string ArtifactPath = "minimized-from-" + Hash(U); 322 Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" + 323 ArtifactPath; 324 Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); 325 ExitCode = ExecuteCommand(Cmd); 326 if (ExitCode == 0) { 327 if (Flags.exact_artifact_path) { 328 CurrentFilePath = Flags.exact_artifact_path; 329 WriteToFile(U, CurrentFilePath); 330 } 331 Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n", 332 CurrentFilePath.c_str(), U.size()); 333 return 0; 334 } 335 CurrentFilePath = ArtifactPath; 336 Printf("\n\n\n\n\n\n*********************************\n"); 337 } 338 return 0; 339} 340 341int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { 342 assert(Inputs->size() == 1); 343 std::string InputFilePath = Inputs->at(0); 344 Unit U = FileToVector(InputFilePath); 345 assert(U.size() > 2); 346 Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size()); 347 Corpus->AddToCorpus(U, 0); 348 F->SetMaxInputLen(U.size()); 349 F->SetMaxMutationLen(U.size() - 1); 350 F->MinimizeCrashLoop(U); 351 Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n"); 352 exit(0); 353 return 0; 354} 355 356int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { 357 using namespace fuzzer; 358 assert(argc && argv && "Argument pointers cannot be nullptr"); 359 EF = new ExternalFunctions(); 360 if (EF->LLVMFuzzerInitialize) 361 EF->LLVMFuzzerInitialize(argc, argv); 362 const std::vector<std::string> Args(*argv, *argv + *argc); 363 assert(!Args.empty()); 364 ProgName = new std::string(Args[0]); 365 ParseFlags(Args); 366 if (Flags.help) { 367 PrintHelp(); 368 return 0; 369 } 370 371 if (Flags.minimize_crash) 372 return MinimizeCrashInput(Args); 373 374 if (Flags.close_fd_mask & 2) 375 DupAndCloseStderr(); 376 if (Flags.close_fd_mask & 1) 377 CloseStdout(); 378 379 if (Flags.jobs > 0 && Flags.workers == 0) { 380 Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); 381 if (Flags.workers > 1) 382 Printf("Running %u workers\n", Flags.workers); 383 } 384 385 if (Flags.workers > 0 && Flags.jobs > 0) 386 return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); 387 388 const size_t kMaxSaneLen = 1 << 20; 389 const size_t kMinDefaultLen = 64; 390 FuzzingOptions Options; 391 Options.Verbosity = Flags.verbosity; 392 Options.MaxLen = Flags.max_len; 393 Options.UnitTimeoutSec = Flags.timeout; 394 Options.ErrorExitCode = Flags.error_exitcode; 395 Options.TimeoutExitCode = Flags.timeout_exitcode; 396 Options.MaxTotalTimeSec = Flags.max_total_time; 397 Options.DoCrossOver = Flags.cross_over; 398 Options.MutateDepth = Flags.mutate_depth; 399 Options.UseCounters = Flags.use_counters; 400 Options.UseIndirCalls = Flags.use_indir_calls; 401 Options.UseMemcmp = Flags.use_memcmp; 402 Options.UseMemmem = Flags.use_memmem; 403 Options.UseCmp = Flags.use_cmp; 404 Options.UseValueProfile = Flags.use_value_profile; 405 Options.Shrink = Flags.shrink; 406 Options.ShuffleAtStartUp = Flags.shuffle; 407 Options.PreferSmall = Flags.prefer_small; 408 Options.ReloadIntervalSec = Flags.reload; 409 Options.OnlyASCII = Flags.only_ascii; 410 Options.OutputCSV = Flags.output_csv; 411 Options.DetectLeaks = Flags.detect_leaks; 412 Options.TraceMalloc = Flags.trace_malloc; 413 Options.RssLimitMb = Flags.rss_limit_mb; 414 if (Flags.runs >= 0) 415 Options.MaxNumberOfRuns = Flags.runs; 416 if (!Inputs->empty() && !Flags.minimize_crash_internal_step) 417 Options.OutputCorpus = (*Inputs)[0]; 418 Options.ReportSlowUnits = Flags.report_slow_units; 419 if (Flags.artifact_prefix) 420 Options.ArtifactPrefix = Flags.artifact_prefix; 421 if (Flags.exact_artifact_path) 422 Options.ExactArtifactPath = Flags.exact_artifact_path; 423 std::vector<Unit> Dictionary; 424 if (Flags.dict) 425 if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) 426 return 1; 427 if (Flags.verbosity > 0 && !Dictionary.empty()) 428 Printf("Dictionary: %zd entries\n", Dictionary.size()); 429 bool DoPlainRun = AllInputsAreFiles(); 430 Options.SaveArtifacts = 431 !DoPlainRun || Flags.minimize_crash_internal_step; 432 Options.PrintNewCovPcs = Flags.print_pcs; 433 Options.PrintFinalStats = Flags.print_final_stats; 434 Options.PrintCorpusStats = Flags.print_corpus_stats; 435 Options.PrintCoverage = Flags.print_coverage; 436 Options.DumpCoverage = Flags.dump_coverage; 437 if (Flags.exit_on_src_pos) 438 Options.ExitOnSrcPos = Flags.exit_on_src_pos; 439 if (Flags.exit_on_item) 440 Options.ExitOnItem = Flags.exit_on_item; 441 442 unsigned Seed = Flags.seed; 443 // Initialize Seed. 444 if (Seed == 0) 445 Seed = (std::chrono::system_clock::now().time_since_epoch().count() << 10) + 446 GetPid(); 447 if (Flags.verbosity) 448 Printf("INFO: Seed: %u\n", Seed); 449 450 Random Rand(Seed); 451 auto *MD = new MutationDispatcher(Rand, Options); 452 auto *Corpus = new InputCorpus(Options.OutputCorpus); 453 auto *F = new Fuzzer(Callback, *Corpus, *MD, Options); 454 455 for (auto &U: Dictionary) 456 if (U.size() <= Word::GetMaxSize()) 457 MD->AddWordToManualDictionary(Word(U.data(), U.size())); 458 459 StartRssThread(F, Flags.rss_limit_mb); 460 461 Options.HandleAbrt = Flags.handle_abrt; 462 Options.HandleBus = Flags.handle_bus; 463 Options.HandleFpe = Flags.handle_fpe; 464 Options.HandleIll = Flags.handle_ill; 465 Options.HandleInt = Flags.handle_int; 466 Options.HandleSegv = Flags.handle_segv; 467 Options.HandleTerm = Flags.handle_term; 468 SetSignalHandler(Options); 469 470 if (Flags.minimize_crash_internal_step) 471 return MinimizeCrashInputInternalStep(F, Corpus); 472 473 if (DoPlainRun) { 474 Options.SaveArtifacts = false; 475 int Runs = std::max(1, Flags.runs); 476 Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(), 477 Inputs->size(), Runs); 478 for (auto &Path : *Inputs) { 479 auto StartTime = system_clock::now(); 480 Printf("Running: %s\n", Path.c_str()); 481 for (int Iter = 0; Iter < Runs; Iter++) 482 RunOneTest(F, Path.c_str(), Options.MaxLen); 483 auto StopTime = system_clock::now(); 484 auto MS = duration_cast<milliseconds>(StopTime - StartTime).count(); 485 Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); 486 } 487 Printf("***\n" 488 "*** NOTE: fuzzing was not performed, you have only\n" 489 "*** executed the target code on a fixed set of inputs.\n" 490 "***\n"); 491 F->PrintFinalStats(); 492 exit(0); 493 } 494 495 if (Flags.merge) { 496 if (Options.MaxLen == 0) 497 F->SetMaxInputLen(kMaxSaneLen); 498 if (TPC.UsingTracePcGuard()) { 499 if (Flags.merge_control_file) 500 F->CrashResistantMergeInternalStep(Flags.merge_control_file); 501 else 502 F->CrashResistantMerge(Args, *Inputs); 503 } else { 504 F->Merge(*Inputs); 505 } 506 exit(0); 507 } 508 509 size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; 510 511 UnitVector InitialCorpus; 512 for (auto &Inp : *Inputs) { 513 Printf("Loading corpus dir: %s\n", Inp.c_str()); 514 ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, 515 TemporaryMaxLen, /*ExitOnError=*/false); 516 } 517 518 if (Options.MaxLen == 0) { 519 size_t MaxLen = 0; 520 for (auto &U : InitialCorpus) 521 MaxLen = std::max(U.size(), MaxLen); 522 F->SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen)); 523 } 524 525 if (InitialCorpus.empty()) { 526 InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input. 527 if (Options.Verbosity) 528 Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); 529 } 530 F->ShuffleAndMinimize(&InitialCorpus); 531 InitialCorpus.clear(); // Don't need this memory any more. 532 F->Loop(); 533 534 if (Flags.verbosity) 535 Printf("Done %d runs in %zd second(s)\n", F->getTotalNumberOfRuns(), 536 F->secondsSinceProcessStartUp()); 537 F->PrintFinalStats(); 538 539 exit(0); // Don't let F destroy itself. 540} 541 542// Storage for global ExternalFunctions object. 543ExternalFunctions *EF = nullptr; 544 545} // namespace fuzzer 546