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> 240fca6ea1SDimitry Andric // clang-format off 250b57cec5SDimitry Andric #include <windows.h> 260fca6ea1SDimitry Andric // These must be included after windows.h. 270fca6ea1SDimitry Andric // archicture need to be set before including 280fca6ea1SDimitry Andric // libloaderapi 290fca6ea1SDimitry Andric #include <libloaderapi.h> 300fca6ea1SDimitry Andric #include <stringapiset.h> 310b57cec5SDimitry Andric #include <psapi.h> 320fca6ea1SDimitry Andric // clang-format on 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric namespace fuzzer { 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric static const FuzzingOptions* HandlerOpt = nullptr; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { 390b57cec5SDimitry Andric switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { 400b57cec5SDimitry Andric case EXCEPTION_ACCESS_VIOLATION: 410b57cec5SDimitry Andric case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 420b57cec5SDimitry Andric case EXCEPTION_STACK_OVERFLOW: 430b57cec5SDimitry Andric if (HandlerOpt->HandleSegv) 440b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 450b57cec5SDimitry Andric break; 460b57cec5SDimitry Andric case EXCEPTION_DATATYPE_MISALIGNMENT: 470b57cec5SDimitry Andric case EXCEPTION_IN_PAGE_ERROR: 480b57cec5SDimitry Andric if (HandlerOpt->HandleBus) 490b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 500b57cec5SDimitry Andric break; 510b57cec5SDimitry Andric case EXCEPTION_ILLEGAL_INSTRUCTION: 520b57cec5SDimitry Andric case EXCEPTION_PRIV_INSTRUCTION: 530b57cec5SDimitry Andric if (HandlerOpt->HandleIll) 540b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 550b57cec5SDimitry Andric break; 560b57cec5SDimitry Andric case EXCEPTION_FLT_DENORMAL_OPERAND: 570b57cec5SDimitry Andric case EXCEPTION_FLT_DIVIDE_BY_ZERO: 580b57cec5SDimitry Andric case EXCEPTION_FLT_INEXACT_RESULT: 590b57cec5SDimitry Andric case EXCEPTION_FLT_INVALID_OPERATION: 600b57cec5SDimitry Andric case EXCEPTION_FLT_OVERFLOW: 610b57cec5SDimitry Andric case EXCEPTION_FLT_STACK_CHECK: 620b57cec5SDimitry Andric case EXCEPTION_FLT_UNDERFLOW: 630b57cec5SDimitry Andric case EXCEPTION_INT_DIVIDE_BY_ZERO: 640b57cec5SDimitry Andric case EXCEPTION_INT_OVERFLOW: 650b57cec5SDimitry Andric if (HandlerOpt->HandleFpe) 660b57cec5SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 670b57cec5SDimitry Andric break; 68e8d8bef9SDimitry Andric // This is an undocumented exception code corresponding to a Visual C++ 69e8d8bef9SDimitry Andric // Exception. 70e8d8bef9SDimitry Andric // 71e8d8bef9SDimitry Andric // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273 72e8d8bef9SDimitry Andric case 0xE06D7363: 73e8d8bef9SDimitry Andric if (HandlerOpt->HandleWinExcept) 74e8d8bef9SDimitry Andric Fuzzer::StaticCrashSignalCallback(); 75e8d8bef9SDimitry Andric break; 76e8d8bef9SDimitry Andric // TODO: Handle (Options.HandleXfsz) 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric return EXCEPTION_CONTINUE_SEARCH; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric BOOL WINAPI CtrlHandler(DWORD dwCtrlType) { 820b57cec5SDimitry Andric switch (dwCtrlType) { 830b57cec5SDimitry Andric case CTRL_C_EVENT: 840b57cec5SDimitry Andric if (HandlerOpt->HandleInt) 850b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback(); 860b57cec5SDimitry Andric return TRUE; 870b57cec5SDimitry Andric case CTRL_BREAK_EVENT: 880b57cec5SDimitry Andric if (HandlerOpt->HandleTerm) 890b57cec5SDimitry Andric Fuzzer::StaticInterruptCallback(); 900b57cec5SDimitry Andric return TRUE; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric return FALSE; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric void CALLBACK AlarmHandler(PVOID, BOOLEAN) { 960b57cec5SDimitry Andric Fuzzer::StaticAlarmCallback(); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric class TimerQ { 1000b57cec5SDimitry Andric HANDLE TimerQueue; 1010b57cec5SDimitry Andric public: 1020b57cec5SDimitry Andric TimerQ() : TimerQueue(NULL) {} 1030b57cec5SDimitry Andric ~TimerQ() { 1040b57cec5SDimitry Andric if (TimerQueue) 1050b57cec5SDimitry Andric DeleteTimerQueueEx(TimerQueue, NULL); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric void SetTimer(int Seconds) { 1080b57cec5SDimitry Andric if (!TimerQueue) { 1090b57cec5SDimitry Andric TimerQueue = CreateTimerQueue(); 1100b57cec5SDimitry Andric if (!TimerQueue) { 1110b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueue failed.\n"); 1120b57cec5SDimitry Andric exit(1); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric HANDLE Timer; 1160b57cec5SDimitry Andric if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL, 1170b57cec5SDimitry Andric Seconds*1000, Seconds*1000, 0)) { 1180b57cec5SDimitry Andric Printf("libFuzzer: CreateTimerQueueTimer failed.\n"); 1190b57cec5SDimitry Andric exit(1); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric }; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric static TimerQ Timer; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric void SetSignalHandler(const FuzzingOptions& Options) { 1290b57cec5SDimitry Andric HandlerOpt = &Options; 1300b57cec5SDimitry Andric 131e8d8bef9SDimitry Andric if (Options.HandleAlrm && Options.UnitTimeoutSec > 0) 1320b57cec5SDimitry Andric Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric if (Options.HandleInt || Options.HandleTerm) 1350b57cec5SDimitry Andric if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { 1360b57cec5SDimitry Andric DWORD LastError = GetLastError(); 1370b57cec5SDimitry Andric Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n", 1380b57cec5SDimitry Andric LastError); 1390b57cec5SDimitry Andric exit(1); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric if (Options.HandleSegv || Options.HandleBus || Options.HandleIll || 143e8d8bef9SDimitry Andric Options.HandleFpe || Options.HandleWinExcept) 1440b57cec5SDimitry Andric SetUnhandledExceptionFilter(ExceptionHandler); 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric if (Options.HandleAbrt) 1470b57cec5SDimitry Andric if (SIG_ERR == signal(SIGABRT, CrashHandler)) { 1480b57cec5SDimitry Andric Printf("libFuzzer: signal failed with %d\n", errno); 1490b57cec5SDimitry Andric exit(1); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric unsigned long GetPid() { return GetCurrentProcessId(); } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric size_t GetPeakRSSMb() { 1580b57cec5SDimitry Andric PROCESS_MEMORY_COUNTERS info; 1590b57cec5SDimitry Andric if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info))) 1600b57cec5SDimitry Andric return 0; 1610b57cec5SDimitry Andric return info.PeakWorkingSetSize >> 20; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric FILE *OpenProcessPipe(const char *Command, const char *Mode) { 1650b57cec5SDimitry Andric return _popen(Command, Mode); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1685ffd83dbSDimitry Andric int CloseProcessPipe(FILE *F) { 1695ffd83dbSDimitry Andric return _pclose(F); 1705ffd83dbSDimitry Andric } 1715ffd83dbSDimitry Andric 1720b57cec5SDimitry Andric int ExecuteCommand(const Command &Cmd) { 1730b57cec5SDimitry Andric std::string CmdLine = Cmd.toString(); 1740b57cec5SDimitry Andric return system(CmdLine.c_str()); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1775ffd83dbSDimitry Andric bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) { 1785ffd83dbSDimitry Andric FILE *Pipe = _popen(Cmd.toString().c_str(), "r"); 1795ffd83dbSDimitry Andric if (!Pipe) 1805ffd83dbSDimitry Andric return false; 1815ffd83dbSDimitry Andric 1825ffd83dbSDimitry Andric if (CmdOutput) { 1835ffd83dbSDimitry Andric char TmpBuffer[128]; 1845ffd83dbSDimitry Andric while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe)) 1855ffd83dbSDimitry Andric CmdOutput->append(TmpBuffer); 1865ffd83dbSDimitry Andric } 1875ffd83dbSDimitry Andric return _pclose(Pipe) == 0; 1885ffd83dbSDimitry Andric } 1895ffd83dbSDimitry Andric 1900b57cec5SDimitry Andric const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, 1910b57cec5SDimitry Andric size_t PattLen) { 1920b57cec5SDimitry Andric // TODO: make this implementation more efficient. 1930b57cec5SDimitry Andric const char *Cdata = (const char *)Data; 1940b57cec5SDimitry Andric const char *Cpatt = (const char *)Patt; 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen) 1970b57cec5SDimitry Andric return NULL; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric if (PattLen == 1) 2000b57cec5SDimitry Andric return memchr(Data, *Cpatt, DataLen); 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric const char *End = Cdata + DataLen - PattLen + 1; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric for (const char *It = Cdata; It < End; ++It) 2050b57cec5SDimitry Andric if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0) 2060b57cec5SDimitry Andric return It; 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric return NULL; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric std::string DisassembleCmd(const std::string &FileName) { 212349cc55cSDimitry Andric std::vector<std::string> command_vector; 2130b57cec5SDimitry Andric command_vector.push_back("dumpbin /summary > nul"); 2140b57cec5SDimitry Andric if (ExecuteCommand(Command(command_vector)) == 0) 2150b57cec5SDimitry Andric return "dumpbin /disasm " + FileName; 2160b57cec5SDimitry Andric Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n"); 2170b57cec5SDimitry Andric exit(1); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric std::string SearchRegexCmd(const std::string &Regex) { 2210b57cec5SDimitry Andric return "findstr /r \"" + Regex + "\""; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 224480093f4SDimitry Andric void DiscardOutput(int Fd) { 225480093f4SDimitry Andric FILE* Temp = fopen("nul", "w"); 226480093f4SDimitry Andric if (!Temp) 227480093f4SDimitry Andric return; 228480093f4SDimitry Andric _dup2(_fileno(Temp), Fd); 229480093f4SDimitry Andric fclose(Temp); 230480093f4SDimitry Andric } 231480093f4SDimitry Andric 23206c3fb27SDimitry Andric size_t PageSize() { 23306c3fb27SDimitry Andric static size_t PageSizeCached = []() -> size_t { 23406c3fb27SDimitry Andric SYSTEM_INFO si; 23506c3fb27SDimitry Andric GetSystemInfo(&si); 23606c3fb27SDimitry Andric return si.dwPageSize; 23706c3fb27SDimitry Andric }(); 23806c3fb27SDimitry Andric return PageSizeCached; 23906c3fb27SDimitry Andric } 24006c3fb27SDimitry Andric 2415f757f3fSDimitry Andric void SetThreadName(std::thread &thread, const std::string &name) { 242*415efcecSDimitry Andric #ifndef __MINGW32__ 243*415efcecSDimitry Andric // Not setting the thread name in MinGW environments. MinGW C++ standard 244*415efcecSDimitry Andric // libraries can either use native Windows threads or pthreads, so we 245*415efcecSDimitry Andric // don't know with certainty what kind of thread handle we're getting 246*415efcecSDimitry Andric // from thread.native_handle() here. 2470fca6ea1SDimitry Andric typedef HRESULT(WINAPI * proc)(HANDLE, PCWSTR); 2480fca6ea1SDimitry Andric HMODULE kbase = GetModuleHandleA("KernelBase.dll"); 2490fca6ea1SDimitry Andric proc ThreadNameProc = 2500fca6ea1SDimitry Andric reinterpret_cast<proc>(GetProcAddress(kbase, "SetThreadDescription")); 2510fca6ea1SDimitry Andric if (ThreadNameProc) { 2520fca6ea1SDimitry Andric std::wstring buf; 2530fca6ea1SDimitry Andric auto sz = MultiByteToWideChar(CP_UTF8, 0, name.data(), -1, nullptr, 0); 2540fca6ea1SDimitry Andric if (sz > 0) { 2550fca6ea1SDimitry Andric buf.resize(sz); 2560fca6ea1SDimitry Andric if (MultiByteToWideChar(CP_UTF8, 0, name.data(), -1, &buf[0], sz) > 0) { 2570fca6ea1SDimitry Andric (void)ThreadNameProc(thread.native_handle(), buf.c_str()); 2580fca6ea1SDimitry Andric } 2590fca6ea1SDimitry Andric } 2600fca6ea1SDimitry Andric } 2615deeebd8SDimitry Andric #endif 2625f757f3fSDimitry Andric } 2635f757f3fSDimitry Andric 2640b57cec5SDimitry Andric } // namespace fuzzer 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric #endif // LIBFUZZER_WINDOWS 267