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