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 // This is an undocumented exception code corresponding to a Visual C++ 64 // Exception. 65 // 66 // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 67 case 0xE06D7363: 68 if (HandlerOpt->HandleWinExcept) 69 Fuzzer::StaticCrashSignalCallback(); 70 break; 71 // TODO: Handle (Options.HandleXfsz) 72 } 73 return EXCEPTION_CONTINUE_SEARCH; 74 } 75 76 BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { 77 switch (dwCtrlType) { 78 case CTRL_C_EVENT: 79 if (HandlerOpt->HandleInt) 80 Fuzzer::StaticInterruptCallback(); 81 return TRUE; 82 case CTRL_BREAK_EVENT: 83 if (HandlerOpt->HandleTerm) 84 Fuzzer::StaticInterruptCallback(); 85 return TRUE; 86 } 87 return FALSE; 88 } 89 90 void CALLBACK AlarmHandler(PVOID, BOOLEAN) { 91 Fuzzer::StaticAlarmCallback(); 92 } 93 94 class TimerQ { 95 HANDLE TimerQueue; 96 public: 97 TimerQ() : TimerQueue(NULL) {} 98 ~TimerQ() { 99 if (TimerQueue) 100 DeleteTimerQueueEx(TimerQueue, NULL); 101 } 102 void SetTimer(int Seconds) { 103 if (!TimerQueue) { 104 TimerQueue = CreateTimerQueue(); 105 if (!TimerQueue) { 106 Printf("libFuzzer: CreateTimerQueue failed.\n"); 107 exit(1); 108 } 109 } 110 HANDLE Timer; 111 if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, 112 Seconds*1000, Seconds*1000, 0)) { 113 Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); 114 exit(1); 115 } 116 } 117 }; 118 119 static TimerQ Timer; 120 121 static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); } 122 123 void SetSignalHandler(const FuzzingOptions& Options) { 124 HandlerOpt = &Options; 125 126 if (Options.HandleAlrm && Options.UnitTimeoutSec > 0) 127 Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); 128 129 if (Options.HandleInt || Options.HandleTerm) 130 if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { 131 DWORD LastError = GetLastError(); 132 Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", 133 LastError); 134 exit(1); 135 } 136 137 if (Options.HandleSegv || Options.HandleBus || Options.HandleIll || 138 Options.HandleFpe || Options.HandleWinExcept) 139 SetUnhandledExceptionFilter(ExceptionHandler); 140 141 if (Options.HandleAbrt) 142 if (SIG_ERR == signal(SIGABRT, CrashHandler)) { 143 Printf("libFuzzer: signal failed with %d\n", errno); 144 exit(1); 145 } 146 } 147 148 void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); } 149 150 unsigned long GetPid() { return GetCurrentProcessId(); } 151 152 size_t GetPeakRSSMb() { 153 PROCESS_MEMORY_COUNTERS info; 154 if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info))) 155 return 0; 156 return info.PeakWorkingSetSize >> 20; 157 } 158 159 FILE *OpenProcessPipe(const char *Command, const char *Mode) { 160 return _popen(Command, Mode); 161 } 162 163 int CloseProcessPipe(FILE *F) { 164 return _pclose(F); 165 } 166 167 int ExecuteCommand(const Command &Cmd) { 168 std::string CmdLine = Cmd.toString(); 169 return system(CmdLine.c_str()); 170 } 171 172 bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) { 173 FILE *Pipe = _popen(Cmd.toString().c_str(), "r"); 174 if (!Pipe) 175 return false; 176 177 if (CmdOutput) { 178 char TmpBuffer[128]; 179 while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe)) 180 CmdOutput->append(TmpBuffer); 181 } 182 return _pclose(Pipe) == 0; 183 } 184 185 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 186 size_t PattLen) { 187 // TODO: make this implementation more efficient. 188 const char *Cdata = (const char *)Data; 189 const char *Cpatt = (const char *)Patt; 190 191 if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen) 192 return NULL; 193 194 if (PattLen == 1) 195 return memchr(Data, *Cpatt, DataLen); 196 197 const char *End = Cdata + DataLen - PattLen + 1; 198 199 for (const char *It = Cdata; It < End; ++It) 200 if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0) 201 return It; 202 203 return NULL; 204 } 205 206 std::string DisassembleCmd(const std::string &FileName) { 207 std::vector<std::string> command_vector; 208 command_vector.push_back("dumpbin /summary > nul"); 209 if (ExecuteCommand(Command(command_vector)) == 0) 210 return "dumpbin /disasm " + FileName; 211 Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); 212 exit(1); 213 } 214 215 std::string SearchRegexCmd(const std::string &Regex) { 216 return "findstr /r \"" + Regex + "\""; 217 } 218 219 void DiscardOutput(int Fd) { 220 FILE* Temp = fopen("nul", "w"); 221 if (!Temp) 222 return; 223 _dup2(_fileno(Temp), Fd); 224 fclose(Temp); 225 } 226 227 size_t PageSize() { 228 static size_t PageSizeCached = []() -> size_t { 229 SYSTEM_INFO si; 230 GetSystemInfo(&si); 231 return si.dwPageSize; 232 }(); 233 return PageSizeCached; 234 } 235 236 void SetThreadName(std::thread &thread, const std::string &name) { 237 // TODO ? 238 // to UTF-8 then SetThreadDescription ? 239 } 240 241 } // namespace fuzzer 242 243 #endif // LIBFUZZER_WINDOWS 244