1 //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===// 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 for Windows. 9 //===----------------------------------------------------------------------===// 10 #include "FuzzerPlatform.h" 11 #if LIBFUZZER_WINDOWS 12 #include "FuzzerCommand.h" 13 #include "FuzzerIO.h" 14 #include "FuzzerInternal.h" 15 #include <cassert> 16 #include <chrono> 17 #include <cstring> 18 #include <errno.h> 19 #include <io.h> 20 #include <iomanip> 21 #include <signal.h> 22 #include <stdio.h> 23 #include <sys/types.h> 24 #include <windows.h> 25 26 // This must be included after windows.h. 27 #include <psapi.h> 28 29 namespace fuzzer { 30 31 static const FuzzingOptions* HandlerOpt = nullptr; 32 33 static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { 34 switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { 35 case EXCEPTION_ACCESS_VIOLATION: 36 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 37 case EXCEPTION_STACK_OVERFLOW: 38 if (HandlerOpt->HandleSegv) 39 Fuzzer::StaticCrashSignalCallback(); 40 break; 41 case EXCEPTION_DATATYPE_MISALIGNMENT: 42 case EXCEPTION_IN_PAGE_ERROR: 43 if (HandlerOpt->HandleBus) 44 Fuzzer::StaticCrashSignalCallback(); 45 break; 46 case EXCEPTION_ILLEGAL_INSTRUCTION: 47 case EXCEPTION_PRIV_INSTRUCTION: 48 if (HandlerOpt->HandleIll) 49 Fuzzer::StaticCrashSignalCallback(); 50 break; 51 case EXCEPTION_FLT_DENORMAL_OPERAND: 52 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 53 case EXCEPTION_FLT_INEXACT_RESULT: 54 case EXCEPTION_FLT_INVALID_OPERATION: 55 case EXCEPTION_FLT_OVERFLOW: 56 case EXCEPTION_FLT_STACK_CHECK: 57 case EXCEPTION_FLT_UNDERFLOW: 58 case EXCEPTION_INT_DIVIDE_BY_ZERO: 59 case EXCEPTION_INT_OVERFLOW: 60 if (HandlerOpt->HandleFpe) 61 Fuzzer::StaticCrashSignalCallback(); 62 break; 63 // TODO: handle (Options.HandleXfsz) 64 } 65 return EXCEPTION_CONTINUE_SEARCH; 66 } 67 68 BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { 69 switch (dwCtrlType) { 70 case CTRL_C_EVENT: 71 if (HandlerOpt->HandleInt) 72 Fuzzer::StaticInterruptCallback(); 73 return TRUE; 74 case CTRL_BREAK_EVENT: 75 if (HandlerOpt->HandleTerm) 76 Fuzzer::StaticInterruptCallback(); 77 return TRUE; 78 } 79 return FALSE; 80 } 81 82 void CALLBACK AlarmHandler(PVOID, BOOLEAN) { 83 Fuzzer::StaticAlarmCallback(); 84 } 85 86 class TimerQ { 87 HANDLE TimerQueue; 88 public: 89 TimerQ() : TimerQueue(NULL) {} 90 ~TimerQ() { 91 if (TimerQueue) 92 DeleteTimerQueueEx(TimerQueue, NULL); 93 } 94 void SetTimer(int Seconds) { 95 if (!TimerQueue) { 96 TimerQueue = CreateTimerQueue(); 97 if (!TimerQueue) { 98 Printf("libFuzzer: CreateTimerQueue failed.\n"); 99 exit(1); 100 } 101 } 102 HANDLE Timer; 103 if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, 104 Seconds*1000, Seconds*1000, 0)) { 105 Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); 106 exit(1); 107 } 108 } 109 }; 110 111 static TimerQ Timer; 112 113 static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); } 114 115 void SetSignalHandler(const FuzzingOptions& Options) { 116 HandlerOpt = &Options; 117 118 if (Options.UnitTimeoutSec > 0) 119 Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); 120 121 if (Options.HandleInt || Options.HandleTerm) 122 if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { 123 DWORD LastError = GetLastError(); 124 Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", 125 LastError); 126 exit(1); 127 } 128 129 if (Options.HandleSegv || Options.HandleBus || Options.HandleIll || 130 Options.HandleFpe) 131 SetUnhandledExceptionFilter(ExceptionHandler); 132 133 if (Options.HandleAbrt) 134 if (SIG_ERR == signal(SIGABRT, CrashHandler)) { 135 Printf("libFuzzer: signal failed with %d\n", errno); 136 exit(1); 137 } 138 } 139 140 void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); } 141 142 unsigned long GetPid() { return GetCurrentProcessId(); } 143 144 size_t GetPeakRSSMb() { 145 PROCESS_MEMORY_COUNTERS info; 146 if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info))) 147 return 0; 148 return info.PeakWorkingSetSize >> 20; 149 } 150 151 FILE *OpenProcessPipe(const char *Command, const char *Mode) { 152 return _popen(Command, Mode); 153 } 154 155 int CloseProcessPipe(FILE *F) { 156 return _pclose(F); 157 } 158 159 int ExecuteCommand(const Command &Cmd) { 160 std::string CmdLine = Cmd.toString(); 161 return system(CmdLine.c_str()); 162 } 163 164 bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) { 165 FILE *Pipe = _popen(Cmd.toString().c_str(), "r"); 166 if (!Pipe) 167 return false; 168 169 if (CmdOutput) { 170 char TmpBuffer[128]; 171 while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe)) 172 CmdOutput->append(TmpBuffer); 173 } 174 return _pclose(Pipe) == 0; 175 } 176 177 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 178 size_t PattLen) { 179 // TODO: make this implementation more efficient. 180 const char *Cdata = (const char *)Data; 181 const char *Cpatt = (const char *)Patt; 182 183 if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen) 184 return NULL; 185 186 if (PattLen == 1) 187 return memchr(Data, *Cpatt, DataLen); 188 189 const char *End = Cdata + DataLen - PattLen + 1; 190 191 for (const char *It = Cdata; It < End; ++It) 192 if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0) 193 return It; 194 195 return NULL; 196 } 197 198 std::string DisassembleCmd(const std::string &FileName) { 199 Vector<std::string> command_vector; 200 command_vector.push_back("dumpbin /summary > nul"); 201 if (ExecuteCommand(Command(command_vector)) == 0) 202 return "dumpbin /disasm " + FileName; 203 Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); 204 exit(1); 205 } 206 207 std::string SearchRegexCmd(const std::string &Regex) { 208 return "findstr /r \"" + Regex + "\""; 209 } 210 211 void DiscardOutput(int Fd) { 212 FILE* Temp = fopen("nul", "w"); 213 if (!Temp) 214 return; 215 _dup2(_fileno(Temp), Fd); 216 fclose(Temp); 217 } 218 219 } // namespace fuzzer 220 221 #endif // LIBFUZZER_WINDOWS 222