1 //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===// 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 // Fuzzer's main loop. 10 //===----------------------------------------------------------------------===// 11 12 #include "FuzzerInternal.h" 13 #include <algorithm> 14 15 #if defined(__has_include) 16 # if __has_include(<sanitizer/coverage_interface.h>) 17 # include <sanitizer/coverage_interface.h> 18 # endif 19 #endif 20 21 extern "C" { 22 // Re-declare some of the sanitizer functions as "weak" so that 23 // libFuzzer can be linked w/o the sanitizers and sanitizer-coverage 24 // (in which case it will complain at start-up time). 25 __attribute__((weak)) void __sanitizer_print_stack_trace(); 26 __attribute__((weak)) void __sanitizer_reset_coverage(); 27 __attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs(); 28 __attribute__((weak)) size_t __sanitizer_get_total_unique_coverage(); 29 __attribute__((weak)) 30 void __sanitizer_set_death_callback(void (*callback)(void)); 31 __attribute__((weak)) size_t __sanitizer_get_number_of_counters(); 32 __attribute__((weak)) 33 uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); 34 } 35 36 namespace fuzzer { 37 static const size_t kMaxUnitSizeToPrint = 256; 38 39 static void MissingWeakApiFunction(const char *FnName) { 40 Printf("ERROR: %s is not defined. Exiting.\n" 41 "Did you use -fsanitize-coverage=... to build your code?\n", FnName); 42 exit(1); 43 } 44 45 #define CHECK_WEAK_API_FUNCTION(fn) \ 46 do { \ 47 if (!fn) \ 48 MissingWeakApiFunction(#fn); \ 49 } while (false) 50 51 // Only one Fuzzer per process. 52 static Fuzzer *F; 53 54 Fuzzer::Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options) 55 : USF(USF), Options(Options) { 56 SetDeathCallback(); 57 InitializeTraceState(); 58 assert(!F); 59 F = this; 60 } 61 62 void Fuzzer::SetDeathCallback() { 63 CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback); 64 __sanitizer_set_death_callback(StaticDeathCallback); 65 } 66 67 void Fuzzer::PrintUnitInASCII(const Unit &U, const char *PrintAfter) { 68 PrintASCII(U, PrintAfter); 69 } 70 71 void Fuzzer::StaticDeathCallback() { 72 assert(F); 73 F->DeathCallback(); 74 } 75 76 void Fuzzer::DeathCallback() { 77 Printf("DEATH:\n"); 78 if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { 79 Print(CurrentUnit, "\n"); 80 PrintUnitInASCII(CurrentUnit, "\n"); 81 } 82 WriteUnitToFileWithPrefix(CurrentUnit, "crash-"); 83 } 84 85 void Fuzzer::StaticAlarmCallback() { 86 assert(F); 87 F->AlarmCallback(); 88 } 89 90 void Fuzzer::AlarmCallback() { 91 assert(Options.UnitTimeoutSec > 0); 92 size_t Seconds = 93 duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); 94 if (Seconds == 0) return; 95 if (Options.Verbosity >= 2) 96 Printf("AlarmCallback %zd\n", Seconds); 97 if (Seconds >= (size_t)Options.UnitTimeoutSec) { 98 Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); 99 Printf(" and the timeout value is %d (use -timeout=N to change)\n", 100 Options.UnitTimeoutSec); 101 if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { 102 Print(CurrentUnit, "\n"); 103 PrintUnitInASCII(CurrentUnit, "\n"); 104 } 105 WriteUnitToFileWithPrefix(CurrentUnit, "timeout-"); 106 Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), 107 Seconds); 108 if (__sanitizer_print_stack_trace) 109 __sanitizer_print_stack_trace(); 110 Printf("SUMMARY: libFuzzer: timeout\n"); 111 exit(1); 112 } 113 } 114 115 void Fuzzer::PrintStats(const char *Where, const char *End) { 116 size_t Seconds = secondsSinceProcessStartUp(); 117 size_t ExecPerSec = (Seconds ? TotalNumberOfRuns / Seconds : 0); 118 119 if (Options.OutputCSV) { 120 static bool csvHeaderPrinted = false; 121 if (!csvHeaderPrinted) { 122 csvHeaderPrinted = true; 123 Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n"); 124 } 125 Printf("%zd,%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns, 126 LastRecordedBlockCoverage, TotalBits(), 127 LastRecordedCallerCalleeCoverage, Corpus.size(), ExecPerSec, 128 TotalNumberOfExecutedTraceBasedMutations, Where); 129 } 130 131 if (!Options.Verbosity) 132 return; 133 Printf("#%zd\t%s", TotalNumberOfRuns, Where); 134 if (LastRecordedBlockCoverage) 135 Printf(" cov: %zd", LastRecordedBlockCoverage); 136 if (auto TB = TotalBits()) 137 Printf(" bits: %zd", TB); 138 if (LastRecordedCallerCalleeCoverage) 139 Printf(" indir: %zd", LastRecordedCallerCalleeCoverage); 140 Printf(" units: %zd exec/s: %zd", Corpus.size(), ExecPerSec); 141 if (TotalNumberOfExecutedTraceBasedMutations) 142 Printf(" tbm: %zd", TotalNumberOfExecutedTraceBasedMutations); 143 Printf("%s", End); 144 } 145 146 void Fuzzer::RereadOutputCorpus() { 147 if (Options.OutputCorpus.empty()) return; 148 std::vector<Unit> AdditionalCorpus; 149 ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, 150 &EpochOfLastReadOfOutputCorpus); 151 if (Corpus.empty()) { 152 Corpus = AdditionalCorpus; 153 return; 154 } 155 if (!Options.Reload) return; 156 if (Options.Verbosity >= 2) 157 Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); 158 for (auto &X : AdditionalCorpus) { 159 if (X.size() > (size_t)Options.MaxLen) 160 X.resize(Options.MaxLen); 161 if (UnitHashesAddedToCorpus.insert(Hash(X)).second) { 162 CurrentUnit.clear(); 163 CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end()); 164 if (RunOne(CurrentUnit)) { 165 Corpus.push_back(X); 166 PrintStats("RELOAD"); 167 } 168 } 169 } 170 } 171 172 void Fuzzer::ShuffleAndMinimize() { 173 bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 || 174 (Options.PreferSmallDuringInitialShuffle == -1 && 175 USF.GetRand().RandBool())); 176 if (Options.Verbosity) 177 Printf("PreferSmall: %d\n", PreferSmall); 178 PrintStats("READ "); 179 std::vector<Unit> NewCorpus; 180 if (Options.ShuffleAtStartUp) { 181 std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand()); 182 if (PreferSmall) 183 std::stable_sort( 184 Corpus.begin(), Corpus.end(), 185 [](const Unit &A, const Unit &B) { return A.size() < B.size(); }); 186 } 187 Unit &U = CurrentUnit; 188 for (const auto &C : Corpus) { 189 for (size_t First = 0; First < 1; First++) { 190 U.clear(); 191 size_t Last = std::min(First + Options.MaxLen, C.size()); 192 U.insert(U.begin(), C.begin() + First, C.begin() + Last); 193 if (Options.OnlyASCII) 194 ToASCII(U); 195 if (RunOne(U)) { 196 NewCorpus.push_back(U); 197 if (Options.Verbosity >= 2) 198 Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size()); 199 } 200 } 201 } 202 Corpus = NewCorpus; 203 for (auto &X : Corpus) 204 UnitHashesAddedToCorpus.insert(Hash(X)); 205 PrintStats("INITED"); 206 } 207 208 bool Fuzzer::RunOne(const Unit &U) { 209 UnitStartTime = system_clock::now(); 210 TotalNumberOfRuns++; 211 212 PrepareCoverageBeforeRun(); 213 ExecuteCallback(U); 214 bool Res = CheckCoverageAfterRun(); 215 216 auto UnitStopTime = system_clock::now(); 217 auto TimeOfUnit = 218 duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); 219 if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && 220 secondsSinceProcessStartUp() >= 2) 221 PrintStats("pulse "); 222 if (TimeOfUnit > TimeOfLongestUnitInSeconds && 223 TimeOfUnit >= Options.ReportSlowUnits) { 224 TimeOfLongestUnitInSeconds = TimeOfUnit; 225 Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); 226 WriteUnitToFileWithPrefix(U, "slow-unit-"); 227 } 228 return Res; 229 } 230 231 void Fuzzer::RunOneAndUpdateCorpus(Unit &U) { 232 if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 233 return; 234 if (Options.OnlyASCII) 235 ToASCII(U); 236 if (RunOne(U)) 237 ReportNewCoverage(U); 238 } 239 240 void Fuzzer::ExecuteCallback(const Unit &U) { 241 const uint8_t *Data = U.data(); 242 uint8_t EmptyData; 243 if (!Data) 244 Data = &EmptyData; 245 int Res = USF.TargetFunction(Data, U.size()); 246 (void)Res; 247 assert(Res == 0); 248 } 249 250 size_t Fuzzer::RecordBlockCoverage() { 251 CHECK_WEAK_API_FUNCTION(__sanitizer_get_total_unique_coverage); 252 return LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); 253 } 254 255 size_t Fuzzer::RecordCallerCalleeCoverage() { 256 if (!Options.UseIndirCalls) 257 return 0; 258 if (!__sanitizer_get_total_unique_caller_callee_pairs) 259 return 0; 260 return LastRecordedCallerCalleeCoverage = 261 __sanitizer_get_total_unique_caller_callee_pairs(); 262 } 263 264 void Fuzzer::PrepareCoverageBeforeRun() { 265 if (Options.UseCounters) { 266 size_t NumCounters = __sanitizer_get_number_of_counters(); 267 CounterBitmap.resize(NumCounters); 268 __sanitizer_update_counter_bitset_and_clear_counters(0); 269 } 270 RecordBlockCoverage(); 271 RecordCallerCalleeCoverage(); 272 } 273 274 bool Fuzzer::CheckCoverageAfterRun() { 275 size_t OldCoverage = LastRecordedBlockCoverage; 276 size_t NewCoverage = RecordBlockCoverage(); 277 size_t OldCallerCalleeCoverage = LastRecordedCallerCalleeCoverage; 278 size_t NewCallerCalleeCoverage = RecordCallerCalleeCoverage(); 279 size_t NumNewBits = 0; 280 if (Options.UseCounters) 281 NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters( 282 CounterBitmap.data()); 283 return NewCoverage > OldCoverage || 284 NewCallerCalleeCoverage > OldCallerCalleeCoverage || NumNewBits; 285 } 286 287 void Fuzzer::WriteToOutputCorpus(const Unit &U) { 288 if (Options.OutputCorpus.empty()) return; 289 std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); 290 WriteToFile(U, Path); 291 if (Options.Verbosity >= 2) 292 Printf("Written to %s\n", Path.c_str()); 293 assert(!Options.OnlyASCII || IsASCII(U)); 294 } 295 296 void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { 297 if (!Options.SaveArtifacts) 298 return; 299 std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); 300 if (!Options.ExactArtifactPath.empty()) 301 Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. 302 WriteToFile(U, Path); 303 Printf("artifact_prefix='%s'; Test unit written to %s\n", 304 Options.ArtifactPrefix.c_str(), Path.c_str()); 305 if (U.size() <= kMaxUnitSizeToPrint) 306 Printf("Base64: %s\n", Base64(U).c_str()); 307 } 308 309 void Fuzzer::SaveCorpus() { 310 if (Options.OutputCorpus.empty()) return; 311 for (const auto &U : Corpus) 312 WriteToFile(U, DirPlusFile(Options.OutputCorpus, Hash(U))); 313 if (Options.Verbosity) 314 Printf("Written corpus of %zd files to %s\n", Corpus.size(), 315 Options.OutputCorpus.c_str()); 316 } 317 318 void Fuzzer::PrintStatusForNewUnit(const Unit &U) { 319 if (!Options.PrintNEW) 320 return; 321 PrintStats("NEW ", ""); 322 if (Options.Verbosity) { 323 Printf(" L: %zd ", U.size()); 324 USF.PrintMutationSequence(); 325 Printf("\n"); 326 } 327 } 328 329 void Fuzzer::ReportNewCoverage(const Unit &U) { 330 Corpus.push_back(U); 331 UnitHashesAddedToCorpus.insert(Hash(U)); 332 PrintStatusForNewUnit(U); 333 WriteToOutputCorpus(U); 334 if (Options.ExitOnFirst) 335 exit(0); 336 } 337 338 void Fuzzer::Merge(const std::vector<std::string> &Corpora) { 339 if (Corpora.size() <= 1) { 340 Printf("Merge requires two or more corpus dirs\n"); 341 return; 342 } 343 auto InitialCorpusDir = Corpora[0]; 344 ReadDir(InitialCorpusDir, nullptr); 345 Printf("Merge: running the initial corpus '%s' of %d units\n", 346 InitialCorpusDir.c_str(), Corpus.size()); 347 for (auto &U : Corpus) 348 RunOne(U); 349 350 std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end()); 351 352 size_t NumTried = 0; 353 size_t NumMerged = 0; 354 for (auto &C : ExtraCorpora) { 355 Corpus.clear(); 356 ReadDir(C, nullptr); 357 Printf("Merge: merging the extra corpus '%s' of %zd units\n", C.c_str(), 358 Corpus.size()); 359 for (auto &U : Corpus) { 360 NumTried++; 361 if (RunOne(U)) { 362 WriteToOutputCorpus(U); 363 NumMerged++; 364 } 365 } 366 } 367 Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried); 368 } 369 370 void Fuzzer::MutateAndTestOne() { 371 auto &U = CurrentUnit; 372 USF.StartMutationSequence(); 373 374 U = ChooseUnitToMutate(); 375 376 for (int i = 0; i < Options.MutateDepth; i++) { 377 StartTraceRecording(); 378 size_t Size = U.size(); 379 U.resize(Options.MaxLen); 380 size_t NewSize = USF.Mutate(U.data(), Size, U.size()); 381 assert(NewSize > 0 && "Mutator returned empty unit"); 382 assert(NewSize <= (size_t)Options.MaxLen && 383 "Mutator return overisized unit"); 384 U.resize(NewSize); 385 RunOneAndUpdateCorpus(U); 386 size_t NumTraceBasedMutations = StopTraceRecording(); 387 size_t TBMWidth = 388 std::min((size_t)Options.TBMWidth, NumTraceBasedMutations); 389 size_t TBMDepth = 390 std::min((size_t)Options.TBMDepth, NumTraceBasedMutations); 391 Unit BackUp = U; 392 for (size_t w = 0; w < TBMWidth; w++) { 393 U = BackUp; 394 for (size_t d = 0; d < TBMDepth; d++) { 395 TotalNumberOfExecutedTraceBasedMutations++; 396 ApplyTraceBasedMutation(USF.GetRand()(NumTraceBasedMutations), &U); 397 RunOneAndUpdateCorpus(U); 398 } 399 } 400 } 401 } 402 403 // Returns an index of random unit from the corpus to mutate. 404 // Hypothesis: units added to the corpus last are more likely to be interesting. 405 // This function gives more wieght to the more recent units. 406 size_t Fuzzer::ChooseUnitIdxToMutate() { 407 size_t N = Corpus.size(); 408 size_t Total = (N + 1) * N / 2; 409 size_t R = USF.GetRand()(Total); 410 size_t IdxBeg = 0, IdxEnd = N; 411 // Binary search. 412 while (IdxEnd - IdxBeg >= 2) { 413 size_t Idx = IdxBeg + (IdxEnd - IdxBeg) / 2; 414 if (R > (Idx + 1) * Idx / 2) 415 IdxBeg = Idx; 416 else 417 IdxEnd = Idx; 418 } 419 assert(IdxBeg < N); 420 return IdxBeg; 421 } 422 423 // Experimental search heuristic: drilling. 424 // - Read, shuffle, execute and minimize the corpus. 425 // - Choose one random unit. 426 // - Reset the coverage. 427 // - Start fuzzing as if the chosen unit was the only element of the corpus. 428 // - When done, reset the coverage again. 429 // - Merge the newly created corpus into the original one. 430 void Fuzzer::Drill() { 431 // The corpus is already read, shuffled, and minimized. 432 assert(!Corpus.empty()); 433 Options.PrintNEW = false; // Don't print NEW status lines when drilling. 434 435 Unit U = ChooseUnitToMutate(); 436 437 CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage); 438 __sanitizer_reset_coverage(); 439 440 std::vector<Unit> SavedCorpus; 441 SavedCorpus.swap(Corpus); 442 Corpus.push_back(U); 443 assert(Corpus.size() == 1); 444 RunOne(U); 445 PrintStats("DRILL "); 446 std::string SavedOutputCorpusPath; // Don't write new units while drilling. 447 SavedOutputCorpusPath.swap(Options.OutputCorpus); 448 Loop(); 449 450 __sanitizer_reset_coverage(); 451 452 PrintStats("REINIT"); 453 SavedOutputCorpusPath.swap(Options.OutputCorpus); 454 for (auto &U : SavedCorpus) 455 RunOne(U); 456 PrintStats("MERGE "); 457 Options.PrintNEW = true; 458 size_t NumMerged = 0; 459 for (auto &U : Corpus) { 460 if (RunOne(U)) { 461 PrintStatusForNewUnit(U); 462 NumMerged++; 463 WriteToOutputCorpus(U); 464 } 465 } 466 PrintStats("MERGED"); 467 if (NumMerged && Options.Verbosity) 468 Printf("Drilling discovered %zd new units\n", NumMerged); 469 } 470 471 void Fuzzer::Loop() { 472 system_clock::time_point LastCorpusReload = system_clock::now(); 473 if (Options.DoCrossOver) 474 USF.SetCorpus(&Corpus); 475 while (true) { 476 SyncCorpus(); 477 auto Now = system_clock::now(); 478 if (duration_cast<seconds>(Now - LastCorpusReload).count()) { 479 RereadOutputCorpus(); 480 LastCorpusReload = Now; 481 } 482 if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 483 break; 484 if (Options.MaxTotalTimeSec > 0 && 485 secondsSinceProcessStartUp() > 486 static_cast<size_t>(Options.MaxTotalTimeSec)) 487 break; 488 // Perform several mutations and runs. 489 MutateAndTestOne(); 490 } 491 492 PrintStats("DONE ", "\n"); 493 } 494 495 void Fuzzer::SyncCorpus() { 496 if (Options.SyncCommand.empty() || Options.OutputCorpus.empty()) return; 497 auto Now = system_clock::now(); 498 if (duration_cast<seconds>(Now - LastExternalSync).count() < 499 Options.SyncTimeout) 500 return; 501 LastExternalSync = Now; 502 ExecuteCommand(Options.SyncCommand + " " + Options.OutputCorpus); 503 } 504 505 } // namespace fuzzer 506