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