10b57cec5SDimitry Andric //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // Misc utils implementation for Windows. 90b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 105ffd83dbSDimitry Andric #include "FuzzerPlatform.h" 110b57cec5SDimitry Andric #if LIBFUZZER_WINDOWS 120b57cec5SDimitry Andric #include "FuzzerCommand.h" 130b57cec5SDimitry Andric #include "FuzzerIO.h" 140b57cec5SDimitry Andric #include "FuzzerInternal.h" 150b57cec5SDimitry Andric #include <cassert> 160b57cec5SDimitry Andric #include <chrono> 170b57cec5SDimitry Andric #include <cstring> 180b57cec5SDimitry Andric #include <errno.h> 19480093f4SDimitry Andric #include <io.h> 200b57cec5SDimitry Andric #include <iomanip> 210b57cec5SDimitry Andric #include <signal.h> 220b57cec5SDimitry Andric #include <stdio.h> 230b57cec5SDimitry Andric #include <sys/types.h> 240b57cec5SDimitry Andric #include <windows.h> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric // This must be included after windows.h. 270b57cec5SDimitry Andric #include <psapi.h> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric namespace fuzzer { 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric static const FuzzingOptions* HandlerOpt = nullptr; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { 340b57cec5SDimitry Andric switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { 350b57cec5SDimitry Andric case EXCEPTION_ACCESS_VIOLATION: 360b57cec5SDimitry Andric case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 370b57cec5SDimitry Andric case EXCEPTION_STACK_OVERFLOW: 380b57cec5SDimitry Andric if (HandlerOpt->HandleSegv) 390b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 400b57cec5SDimitry Andric break; 410b57cec5SDimitry Andric case EXCEPTION_DATATYPE_MISALIGNMENT: 420b57cec5SDimitry Andric case EXCEPTION_IN_PAGE_ERROR: 430b57cec5SDimitry Andric if (HandlerOpt->HandleBus) 440b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 450b57cec5SDimitry Andric break; 460b57cec5SDimitry Andric case EXCEPTION_ILLEGAL_INSTRUCTION: 470b57cec5SDimitry Andric case EXCEPTION_PRIV_INSTRUCTION: 480b57cec5SDimitry Andric if (HandlerOpt->HandleIll) 490b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 500b57cec5SDimitry Andric break; 510b57cec5SDimitry Andric case EXCEPTION_FLT_DENORMAL_OPERAND: 520b57cec5SDimitry Andric case EXCEPTION_FLT_DIVIDE_BY_ZERO: 530b57cec5SDimitry Andric case EXCEPTION_FLT_INEXACT_RESULT: 540b57cec5SDimitry Andric case EXCEPTION_FLT_INVALID_OPERATION: 550b57cec5SDimitry Andric case EXCEPTION_FLT_OVERFLOW: 560b57cec5SDimitry Andric case EXCEPTION_FLT_STACK_CHECK: 570b57cec5SDimitry Andric case EXCEPTION_FLT_UNDERFLOW: 580b57cec5SDimitry Andric case EXCEPTION_INT_DIVIDE_BY_ZERO: 590b57cec5SDimitry Andric case EXCEPTION_INT_OVERFLOW: 600b57cec5SDimitry Andric if (HandlerOpt->HandleFpe) 610b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 620b57cec5SDimitry Andric break; 63*e8d8bef9SDimitry Andric // This is an undocumented exception code corresponding to a Visual C++ 64*e8d8bef9SDimitry Andric // Exception. 65*e8d8bef9SDimitry Andric // 66*e8d8bef9SDimitry Andric // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 67*e8d8bef9SDimitry Andric case 0xE06D7363: 68*e8d8bef9SDimitry Andric if (HandlerOpt->HandleWinExcept) 69*e8d8bef9SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 70*e8d8bef9SDimitry Andric break; 71*e8d8bef9SDimitry Andric // TODO: Handle (Options.HandleXfsz) 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric return EXCEPTION_CONTINUE_SEARCH; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { 770b57cec5SDimitry Andric switch (dwCtrlType) { 780b57cec5SDimitry Andric case CTRL_C_EVENT: 790b57cec5SDimitry Andric if (HandlerOpt->HandleInt) 800b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback(); 810b57cec5SDimitry Andric return TRUE; 820b57cec5SDimitry Andric case CTRL_BREAK_EVENT: 830b57cec5SDimitry Andric if (HandlerOpt->HandleTerm) 840b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback(); 850b57cec5SDimitry Andric return TRUE; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric return FALSE; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) { 910b57cec5SDimitry Andric Fuzzer::StaticAlarmCallback(); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric class TimerQ { 950b57cec5SDimitry Andric HANDLE TimerQueue; 960b57cec5SDimitry Andric public: 970b57cec5SDimitry Andric TimerQ() : TimerQueue(NULL) {} 980b57cec5SDimitry Andric ~TimerQ() { 990b57cec5SDimitry Andric if (TimerQueue) 1000b57cec5SDimitry Andric DeleteTimerQueueEx(TimerQueue, NULL); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric void SetTimer(int Seconds) { 1030b57cec5SDimitry Andric if (!TimerQueue) { 1040b57cec5SDimitry Andric TimerQueue = CreateTimerQueue(); 1050b57cec5SDimitry Andric if (!TimerQueue) { 1060b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueue failed.\n"); 1070b57cec5SDimitry Andric exit(1); 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric HANDLE Timer; 1110b57cec5SDimitry Andric if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, 1120b57cec5SDimitry Andric Seconds*1000, Seconds*1000, 0)) { 1130b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); 1140b57cec5SDimitry Andric exit(1); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric }; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric static TimerQ Timer; 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) { 1240b57cec5SDimitry Andric HandlerOpt = &Options; 1250b57cec5SDimitry Andric 126*e8d8bef9SDimitry Andric if (Options.HandleAlrm && Options.UnitTimeoutSec > 0) 1270b57cec5SDimitry Andric Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric if (Options.HandleInt || Options.HandleTerm) 1300b57cec5SDimitry Andric if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { 1310b57cec5SDimitry Andric DWORD LastError = GetLastError(); 1320b57cec5SDimitry Andric Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", 1330b57cec5SDimitry Andric LastError); 1340b57cec5SDimitry Andric exit(1); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric if (Options.HandleSegv || Options.HandleBus || Options.HandleIll || 138*e8d8bef9SDimitry Andric Options.HandleFpe || Options.HandleWinExcept) 1390b57cec5SDimitry Andric SetUnhandledExceptionFilter(ExceptionHandler); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric if (Options.HandleAbrt) 1420b57cec5SDimitry Andric if (SIG_ERR == signal(SIGABRT, CrashHandler)) { 1430b57cec5SDimitry Andric Printf("libFuzzer: signal failed with %d\n", errno); 1440b57cec5SDimitry Andric exit(1); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric size_t GetPeakRSSMb() { 1530b57cec5SDimitry Andric PROCESS_MEMORY_COUNTERS info; 1540b57cec5SDimitry Andric if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info))) 1550b57cec5SDimitry Andric return 0; 1560b57cec5SDimitry Andric return info.PeakWorkingSetSize >> 20; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) { 1600b57cec5SDimitry Andric return _popen(Command, Mode); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1635ffd83dbSDimitry Andric int CloseProcessPipe(FILE *F) { 1645ffd83dbSDimitry Andric return _pclose(F); 1655ffd83dbSDimitry Andric } 1665ffd83dbSDimitry Andric 1670b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) { 1680b57cec5SDimitry Andric std::string CmdLine = Cmd.toString(); 1690b57cec5SDimitry Andric return system(CmdLine.c_str()); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1725ffd83dbSDimitry Andric bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) { 1735ffd83dbSDimitry Andric FILE *Pipe = _popen(Cmd.toString().c_str(), "r"); 1745ffd83dbSDimitry Andric if (!Pipe) 1755ffd83dbSDimitry Andric return false; 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric if (CmdOutput) { 1785ffd83dbSDimitry Andric char TmpBuffer[128]; 1795ffd83dbSDimitry Andric while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe)) 1805ffd83dbSDimitry Andric CmdOutput->append(TmpBuffer); 1815ffd83dbSDimitry Andric } 1825ffd83dbSDimitry Andric return _pclose(Pipe) == 0; 1835ffd83dbSDimitry Andric } 1845ffd83dbSDimitry Andric 1850b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 1860b57cec5SDimitry Andric size_t PattLen) { 1870b57cec5SDimitry Andric // TODO: make this implementation more efficient. 1880b57cec5SDimitry Andric const char *Cdata = (const char *)Data; 1890b57cec5SDimitry Andric const char *Cpatt = (const char *)Patt; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen) 1920b57cec5SDimitry Andric return NULL; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric if (PattLen == 1) 1950b57cec5SDimitry Andric return memchr(Data, *Cpatt, DataLen); 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric const char *End = Cdata + DataLen - PattLen + 1; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric for (const char *It = Cdata; It < End; ++It) 2000b57cec5SDimitry Andric if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0) 2010b57cec5SDimitry Andric return It; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric return NULL; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) { 2070b57cec5SDimitry Andric Vector<std::string> command_vector; 2080b57cec5SDimitry Andric command_vector.push_back("dumpbin /summary > nul"); 2090b57cec5SDimitry Andric if (ExecuteCommand(Command(command_vector)) == 0) 2100b57cec5SDimitry Andric return "dumpbin /disasm " + FileName; 2110b57cec5SDimitry Andric Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); 2120b57cec5SDimitry Andric exit(1); 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) { 2160b57cec5SDimitry Andric return "findstr /r \"" + Regex + "\""; 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 219480093f4SDimitry Andric void DiscardOutput(int Fd) { 220480093f4SDimitry Andric FILE* Temp = fopen("nul", "w"); 221480093f4SDimitry Andric if (!Temp) 222480093f4SDimitry Andric return; 223480093f4SDimitry Andric _dup2(_fileno(Temp), Fd); 224480093f4SDimitry Andric fclose(Temp); 225480093f4SDimitry Andric } 226480093f4SDimitry Andric 2270b57cec5SDimitry Andric } // namespace fuzzer 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS 230