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