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