1 //===- FuzzerUtilPosix.cpp - Misc utils for Posix. ------------------------===// 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 // Misc utils implementation using Posix API. 9 //===----------------------------------------------------------------------===// 10 #include "FuzzerPlatform.h" 11 #if LIBFUZZER_POSIX 12 #include "FuzzerIO.h" 13 #include "FuzzerInternal.h" 14 #include "FuzzerTracePC.h" 15 #include <cassert> 16 #include <chrono> 17 #include <cstring> 18 #include <errno.h> 19 #include <iomanip> 20 #include <signal.h> 21 #include <stdio.h> 22 #include <sys/mman.h> 23 #include <sys/resource.h> 24 #include <sys/syscall.h> 25 #include <sys/time.h> 26 #include <sys/types.h> 27 #include <thread> 28 #include <unistd.h> 29 30 namespace fuzzer { 31 32 static void AlarmHandler(int, siginfo_t *, void *) { 33 Fuzzer::StaticAlarmCallback(); 34 } 35 36 static void (*upstream_segv_handler)(int, siginfo_t *, void *); 37 38 static void SegvHandler(int sig, siginfo_t *si, void *ucontext) { 39 assert(si->si_signo == SIGSEGV); 40 if (upstream_segv_handler) 41 return upstream_segv_handler(sig, si, ucontext); 42 Fuzzer::StaticCrashSignalCallback(); 43 } 44 45 static void CrashHandler(int, siginfo_t *, void *) { 46 Fuzzer::StaticCrashSignalCallback(); 47 } 48 49 static void InterruptHandler(int, siginfo_t *, void *) { 50 Fuzzer::StaticInterruptCallback(); 51 } 52 53 static void GracefulExitHandler(int, siginfo_t *, void *) { 54 Fuzzer::StaticGracefulExitCallback(); 55 } 56 57 static void FileSizeExceedHandler(int, siginfo_t *, void *) { 58 Fuzzer::StaticFileSizeExceedCallback(); 59 } 60 61 static void SetSigaction(int signum, 62 void (*callback)(int, siginfo_t *, void *)) { 63 struct sigaction sigact = {}; 64 if (sigaction(signum, nullptr, &sigact)) { 65 Printf("libFuzzer: sigaction failed with %d\n", errno); 66 exit(1); 67 } 68 if (sigact.sa_flags & SA_SIGINFO) { 69 if (sigact.sa_sigaction) { 70 if (signum != SIGSEGV) 71 return; 72 upstream_segv_handler = sigact.sa_sigaction; 73 } 74 } else { 75 if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN && 76 sigact.sa_handler != SIG_ERR) 77 return; 78 } 79 80 struct sigaction new_sigact = {}; 81 // Address sanitizer needs SA_ONSTACK (causing the signal handler to run on a 82 // dedicated stack) in order to be able to detect stack overflows; keep the 83 // flag if it's set. 84 new_sigact.sa_flags = SA_SIGINFO | (sigact.sa_flags & SA_ONSTACK); 85 new_sigact.sa_sigaction = callback; 86 if (sigaction(signum, &new_sigact, nullptr)) { 87 Printf("libFuzzer: sigaction failed with %d\n", errno); 88 exit(1); 89 } 90 } 91 92 // Return true on success, false otherwise. 93 bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) { 94 FILE *Pipe = popen(Cmd.toString().c_str(), "r"); 95 if (!Pipe) 96 return false; 97 98 if (CmdOutput) { 99 char TmpBuffer[128]; 100 while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe)) 101 CmdOutput->append(TmpBuffer); 102 } 103 return pclose(Pipe) == 0; 104 } 105 106 void SetTimer(int Seconds) { 107 struct itimerval T { 108 {Seconds, 0}, { Seconds, 0 } 109 }; 110 if (setitimer(ITIMER_REAL, &T, nullptr)) { 111 Printf("libFuzzer: setitimer failed with %d\n", errno); 112 exit(1); 113 } 114 SetSigaction(SIGALRM, AlarmHandler); 115 } 116 117 void SetSignalHandler(const FuzzingOptions& Options) { 118 // setitimer is not implemented in emscripten. 119 if (Options.HandleAlrm && Options.UnitTimeoutSec > 0 && !LIBFUZZER_EMSCRIPTEN) 120 SetTimer(Options.UnitTimeoutSec / 2 + 1); 121 if (Options.HandleInt) 122 SetSigaction(SIGINT, InterruptHandler); 123 if (Options.HandleTerm) 124 SetSigaction(SIGTERM, InterruptHandler); 125 if (Options.HandleSegv) 126 SetSigaction(SIGSEGV, SegvHandler); 127 if (Options.HandleBus) 128 SetSigaction(SIGBUS, CrashHandler); 129 if (Options.HandleAbrt) 130 SetSigaction(SIGABRT, CrashHandler); 131 if (Options.HandleIll) 132 SetSigaction(SIGILL, CrashHandler); 133 if (Options.HandleFpe) 134 SetSigaction(SIGFPE, CrashHandler); 135 if (Options.HandleXfsz) 136 SetSigaction(SIGXFSZ, FileSizeExceedHandler); 137 if (Options.HandleUsr1) 138 SetSigaction(SIGUSR1, GracefulExitHandler); 139 if (Options.HandleUsr2) 140 SetSigaction(SIGUSR2, GracefulExitHandler); 141 } 142 143 void SleepSeconds(int Seconds) { 144 sleep(Seconds); // Use C API to avoid coverage from instrumented libc++. 145 } 146 147 unsigned long GetPid() { return (unsigned long)getpid(); } 148 149 size_t GetPeakRSSMb() { 150 struct rusage usage; 151 if (getrusage(RUSAGE_SELF, &usage)) 152 return 0; 153 if (LIBFUZZER_LINUX || LIBFUZZER_FREEBSD || LIBFUZZER_NETBSD || 154 LIBFUZZER_EMSCRIPTEN) { 155 // ru_maxrss is in KiB 156 return usage.ru_maxrss >> 10; 157 } else if (LIBFUZZER_APPLE) { 158 // ru_maxrss is in bytes 159 return usage.ru_maxrss >> 20; 160 } 161 assert(0 && "GetPeakRSSMb() is not implemented for your platform"); 162 return 0; 163 } 164 165 FILE *OpenProcessPipe(const char *Command, const char *Mode) { 166 return popen(Command, Mode); 167 } 168 169 int CloseProcessPipe(FILE *F) { 170 return pclose(F); 171 } 172 173 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 174 size_t PattLen) { 175 return memmem(Data, DataLen, Patt, PattLen); 176 } 177 178 std::string DisassembleCmd(const std::string &FileName) { 179 return "objdump -d " + FileName; 180 } 181 182 std::string SearchRegexCmd(const std::string &Regex) { 183 return "grep '" + Regex + "'"; 184 } 185 186 } // namespace fuzzer 187 188 #endif // LIBFUZZER_POSIX 189