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