From a2ca2dcc461cccd539aed282b1f50d2925bc05d7 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 9 Nov 2017 20:30:19 +0000 Subject: [PATCH] [libFuzzer] handle SIGUSR1/SIGUSR2 and try to exit grafully on these signals llvm-svn: 317829 --- compiler-rt/lib/fuzzer/FuzzerDriver.cpp | 2 ++ compiler-rt/lib/fuzzer/FuzzerFlags.def | 2 ++ compiler-rt/lib/fuzzer/FuzzerInternal.h | 4 ++++ compiler-rt/lib/fuzzer/FuzzerLoop.cpp | 14 +++++++++++++ compiler-rt/lib/fuzzer/FuzzerMerge.cpp | 2 ++ compiler-rt/lib/fuzzer/FuzzerOptions.h | 2 ++ compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp | 8 +++++++ compiler-rt/test/fuzzer/SleepOneSecondTest.cpp | 13 ++++++++++++ compiler-rt/test/fuzzer/sigusr.test | 29 ++++++++++++++++++++++++++ 9 files changed, 76 insertions(+) create mode 100644 compiler-rt/test/fuzzer/SleepOneSecondTest.cpp create mode 100644 compiler-rt/test/fuzzer/sigusr.test diff --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp index abc3144..6480fbe 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp @@ -639,6 +639,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.HandleSegv = Flags.handle_segv; Options.HandleTerm = Flags.handle_term; Options.HandleXfsz = Flags.handle_xfsz; + Options.HandleUsr1 = Flags.handle_usr1; + Options.HandleUsr2 = Flags.handle_usr2; SetSignalHandler(Options); std::atexit(Fuzzer::StaticExitCallback); diff --git a/compiler-rt/lib/fuzzer/FuzzerFlags.def b/compiler-rt/lib/fuzzer/FuzzerFlags.def index 9b21157..d738a42 100644 --- a/compiler-rt/lib/fuzzer/FuzzerFlags.def +++ b/compiler-rt/lib/fuzzer/FuzzerFlags.def @@ -114,6 +114,8 @@ FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.") FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.") FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.") FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.") +FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.") +FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.") FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " "if 2, close stderr; if 3, close both. " "Be careful, this will also close e.g. asan's stderr/stdout.") diff --git a/compiler-rt/lib/fuzzer/FuzzerInternal.h b/compiler-rt/lib/fuzzer/FuzzerInternal.h index 3716244..cb26fe3 100644 --- a/compiler-rt/lib/fuzzer/FuzzerInternal.h +++ b/compiler-rt/lib/fuzzer/FuzzerInternal.h @@ -63,6 +63,7 @@ public: static void StaticExitCallback(); static void StaticInterruptCallback(); static void StaticFileSizeExceedCallback(); + static void StaticGracefulExitCallback(); void ExecuteCallback(const uint8_t *Data, size_t Size); bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false, @@ -94,6 +95,7 @@ private: void AlarmCallback(); void CrashCallback(); void ExitCallback(); + void MaybeExitGracefully(); void CrashOnOverwrittenData(); void InterruptCallback(); void MutateAndTestOne(); @@ -116,6 +118,8 @@ private: uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit. bool RunningCB = false; + bool GracefulExitRequested = false; + size_t TotalNumberOfRuns = 0; size_t NumberOfNewUnitsAdded = 0; diff --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp index f4771e1..97bc1c6 100644 --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -216,6 +216,12 @@ void Fuzzer::StaticInterruptCallback() { F->InterruptCallback(); } +void Fuzzer::StaticGracefulExitCallback() { + assert(F); + F->GracefulExitRequested = true; + Printf("INFO: signal received, trying to exit gracefully\n"); +} + void Fuzzer::StaticFileSizeExceedCallback() { Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); exit(1); @@ -246,6 +252,13 @@ void Fuzzer::ExitCallback() { _Exit(Options.ErrorExitCode); } +void Fuzzer::MaybeExitGracefully() { + if (!GracefulExitRequested) return; + Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid()); + PrintFinalStats(); + _Exit(0); +} + void Fuzzer::InterruptCallback() { Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); PrintFinalStats(); @@ -621,6 +634,7 @@ void Fuzzer::MutateAndTestOne() { for (int i = 0; i < Options.MutateDepth; i++) { if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) break; + MaybeExitGracefully(); size_t NewSize = 0; NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); assert(NewSize > 0 && "Mutator returned empty unit"); diff --git a/compiler-rt/lib/fuzzer/FuzzerMerge.cpp b/compiler-rt/lib/fuzzer/FuzzerMerge.cpp index 89b4821..59e34cf 100644 --- a/compiler-rt/lib/fuzzer/FuzzerMerge.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerMerge.cpp @@ -223,6 +223,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app); Set AllFeatures; for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) { + MaybeExitGracefully(); auto U = FileToVector(M.Files[i].Name); if (U.size() > MaxInputLen) { U.resize(MaxInputLen); @@ -334,6 +335,7 @@ void Fuzzer::CrashResistantMerge(const Vector &Args, CloneArgsWithoutX(Args, "merge")); bool Success = false; for (size_t Attempt = 1; Attempt <= NumAttempts; Attempt++) { + MaybeExitGracefully(); Printf("MERGE-OUTER: attempt %zd\n", Attempt); auto ExitCode = ExecuteCommand(BaseCmd.first + " -merge_control_file=" + CFPath + diff --git a/compiler-rt/lib/fuzzer/FuzzerOptions.h b/compiler-rt/lib/fuzzer/FuzzerOptions.h index 73953e1..0a1fb61 100644 --- a/compiler-rt/lib/fuzzer/FuzzerOptions.h +++ b/compiler-rt/lib/fuzzer/FuzzerOptions.h @@ -65,6 +65,8 @@ struct FuzzingOptions { bool HandleSegv = false; bool HandleTerm = false; bool HandleXfsz = false; + bool HandleUsr1 = false; + bool HandleUsr2 = false; }; } // namespace fuzzer diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp index 24c5ccc..934b7aa 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp @@ -40,6 +40,10 @@ static void InterruptHandler(int, siginfo_t *, void *) { Fuzzer::StaticInterruptCallback(); } +static void GracefulExitHandler(int, siginfo_t *, void *) { + Fuzzer::StaticGracefulExitCallback(); +} + static void FileSizeExceedHandler(int, siginfo_t *, void *) { Fuzzer::StaticFileSizeExceedCallback(); } @@ -98,6 +102,10 @@ void SetSignalHandler(const FuzzingOptions& Options) { SetSigaction(SIGFPE, CrashHandler); if (Options.HandleXfsz) SetSigaction(SIGXFSZ, FileSizeExceedHandler); + if (Options.HandleUsr1) + SetSigaction(SIGUSR1, GracefulExitHandler); + if (Options.HandleUsr2) + SetSigaction(SIGUSR2, GracefulExitHandler); } void SleepSeconds(int Seconds) { diff --git a/compiler-rt/test/fuzzer/SleepOneSecondTest.cpp b/compiler-rt/test/fuzzer/SleepOneSecondTest.cpp new file mode 100644 index 0000000..27de2f4 --- /dev/null +++ b/compiler-rt/test/fuzzer/SleepOneSecondTest.cpp @@ -0,0 +1,13 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer: it simply sleeps for 1 second. +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + return 0; +} + diff --git a/compiler-rt/test/fuzzer/sigusr.test b/compiler-rt/test/fuzzer/sigusr.test new file mode 100644 index 0000000..fce244f --- /dev/null +++ b/compiler-rt/test/fuzzer/sigusr.test @@ -0,0 +1,29 @@ +# Check that libFuzzer honors SIGUSR1/SIGUSR2 +RUN: rm -rf %t +RUN: mkdir -p %t +RUN: %cpp_compiler %S/SleepOneSecondTest.cpp -o %t/LFSIGUSR + +RUN: %t/LFSIGUSR 2> %t/log & export PID=$! +RUN: sleep 2 +RUN: kill -SIGUSR1 $PID +RUN: cat %t/log | FileCheck %s + +RUN: mkdir -p %t/C1 %t/C2 +RUN: echo a > %t/C2/a +RUN: echo b > %t/C2/b +RUN: echo c > %t/C2/c +RUN: echo d > %t/C2/d +RUN: echo e > %t/C2/e +RUN: echo f > %t/C2/f +RUN: echo g > %t/C2/g + +RUN: %t/LFSIGUSR -merge=1 -merge_control_file=%t/MCF %t/C1 %t/C2 2> %t/log & export PID=$! +RUN: sleep 3 +RUN: killall -SIGUSR2 %t/LFSIGUSR +RUN: cat %t/log | FileCheck %s +RUN: grep C2/g %t/MCF +RUN: grep STARTED %t/MCF +RUN: grep DONE %t/MCF + +CHECK: INFO: signal received, trying to exit gracefully +CHECK: INFO: libFuzzer: exiting as requested -- 2.7.4