FuzzerUtilWindows.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 "FuzzerPlatform.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 <io.h>
  20. #include <iomanip>
  21. #include <signal.h>
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. // clang-format off
  25. #include <windows.h>
  26. // These must be included after windows.h.
  27. // archicture need to be set before including
  28. // libloaderapi
  29. #include <libloaderapi.h>
  30. #include <stringapiset.h>
  31. #include <psapi.h>
  32. // clang-format on
  33. namespace fuzzer {
  34. static const FuzzingOptions* HandlerOpt = nullptr;
  35. static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
  36. switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
  37. case EXCEPTION_ACCESS_VIOLATION:
  38. case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  39. case EXCEPTION_STACK_OVERFLOW:
  40. if (HandlerOpt->HandleSegv)
  41. Fuzzer::StaticCrashSignalCallback();
  42. break;
  43. case EXCEPTION_DATATYPE_MISALIGNMENT:
  44. case EXCEPTION_IN_PAGE_ERROR:
  45. if (HandlerOpt->HandleBus)
  46. Fuzzer::StaticCrashSignalCallback();
  47. break;
  48. case EXCEPTION_ILLEGAL_INSTRUCTION:
  49. case EXCEPTION_PRIV_INSTRUCTION:
  50. if (HandlerOpt->HandleIll)
  51. Fuzzer::StaticCrashSignalCallback();
  52. break;
  53. case EXCEPTION_FLT_DENORMAL_OPERAND:
  54. case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  55. case EXCEPTION_FLT_INEXACT_RESULT:
  56. case EXCEPTION_FLT_INVALID_OPERATION:
  57. case EXCEPTION_FLT_OVERFLOW:
  58. case EXCEPTION_FLT_STACK_CHECK:
  59. case EXCEPTION_FLT_UNDERFLOW:
  60. case EXCEPTION_INT_DIVIDE_BY_ZERO:
  61. case EXCEPTION_INT_OVERFLOW:
  62. if (HandlerOpt->HandleFpe)
  63. Fuzzer::StaticCrashSignalCallback();
  64. break;
  65. // This is an undocumented exception code corresponding to a Visual C++
  66. // Exception.
  67. //
  68. // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
  69. case 0xE06D7363:
  70. if (HandlerOpt->HandleWinExcept)
  71. Fuzzer::StaticCrashSignalCallback();
  72. break;
  73. // TODO: Handle (Options.HandleXfsz)
  74. }
  75. return EXCEPTION_CONTINUE_SEARCH;
  76. }
  77. BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
  78. switch (dwCtrlType) {
  79. case CTRL_C_EVENT:
  80. if (HandlerOpt->HandleInt)
  81. Fuzzer::StaticInterruptCallback();
  82. return TRUE;
  83. case CTRL_BREAK_EVENT:
  84. if (HandlerOpt->HandleTerm)
  85. Fuzzer::StaticInterruptCallback();
  86. return TRUE;
  87. }
  88. return FALSE;
  89. }
  90. void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
  91. Fuzzer::StaticAlarmCallback();
  92. }
  93. class TimerQ {
  94. HANDLE TimerQueue;
  95. public:
  96. TimerQ() : TimerQueue(NULL) {}
  97. ~TimerQ() {
  98. if (TimerQueue)
  99. DeleteTimerQueueEx(TimerQueue, NULL);
  100. }
  101. void SetTimer(int Seconds) {
  102. if (!TimerQueue) {
  103. TimerQueue = CreateTimerQueue();
  104. if (!TimerQueue) {
  105. Printf("libFuzzer: CreateTimerQueue failed.\n");
  106. exit(1);
  107. }
  108. }
  109. HANDLE Timer;
  110. if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
  111. Seconds*1000, Seconds*1000, 0)) {
  112. Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
  113. exit(1);
  114. }
  115. }
  116. };
  117. static TimerQ Timer;
  118. static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
  119. void SetSignalHandler(const FuzzingOptions& Options) {
  120. HandlerOpt = &Options;
  121. if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
  122. Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
  123. if (Options.HandleInt || Options.HandleTerm)
  124. if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
  125. DWORD LastError = GetLastError();
  126. Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
  127. LastError);
  128. exit(1);
  129. }
  130. if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
  131. Options.HandleFpe || Options.HandleWinExcept)
  132. SetUnhandledExceptionFilter(ExceptionHandler);
  133. if (Options.HandleAbrt)
  134. if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
  135. Printf("libFuzzer: signal failed with %d\n", errno);
  136. exit(1);
  137. }
  138. }
  139. void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
  140. unsigned long GetPid() { return GetCurrentProcessId(); }
  141. size_t GetPeakRSSMb() {
  142. PROCESS_MEMORY_COUNTERS info;
  143. if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
  144. return 0;
  145. return info.PeakWorkingSetSize >> 20;
  146. }
  147. FILE *OpenProcessPipe(const char *Command, const char *Mode) {
  148. return _popen(Command, Mode);
  149. }
  150. int CloseProcessPipe(FILE *F) {
  151. return _pclose(F);
  152. }
  153. int ExecuteCommand(const Command &Cmd) {
  154. std::string CmdLine = Cmd.toString();
  155. return system(CmdLine.c_str());
  156. }
  157. bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
  158. FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
  159. if (!Pipe)
  160. return false;
  161. if (CmdOutput) {
  162. char TmpBuffer[128];
  163. while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
  164. CmdOutput->append(TmpBuffer);
  165. }
  166. return _pclose(Pipe) == 0;
  167. }
  168. const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
  169. size_t PattLen) {
  170. // TODO: make this implementation more efficient.
  171. const char *Cdata = (const char *)Data;
  172. const char *Cpatt = (const char *)Patt;
  173. if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
  174. return NULL;
  175. if (PattLen == 1)
  176. return memchr(Data, *Cpatt, DataLen);
  177. const char *End = Cdata + DataLen - PattLen + 1;
  178. for (const char *It = Cdata; It < End; ++It)
  179. if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
  180. return It;
  181. return NULL;
  182. }
  183. std::string DisassembleCmd(const std::string &FileName) {
  184. std::vector<std::string> command_vector;
  185. command_vector.push_back("dumpbin /summary > nul");
  186. if (ExecuteCommand(Command(command_vector)) == 0)
  187. return "dumpbin /disasm " + FileName;
  188. Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
  189. exit(1);
  190. }
  191. std::string SearchRegexCmd(const std::string &Regex) {
  192. return "findstr /r \"" + Regex + "\"";
  193. }
  194. void DiscardOutput(int Fd) {
  195. FILE* Temp = fopen("nul", "w");
  196. if (!Temp)
  197. return;
  198. _dup2(_fileno(Temp), Fd);
  199. fclose(Temp);
  200. }
  201. size_t PageSize() {
  202. static size_t PageSizeCached = []() -> size_t {
  203. SYSTEM_INFO si;
  204. GetSystemInfo(&si);
  205. return si.dwPageSize;
  206. }();
  207. return PageSizeCached;
  208. }
  209. void SetThreadName(std::thread &thread, const std::string &name) {
  210. #ifndef __MINGW32__
  211. // Not setting the thread name in MinGW environments. MinGW C++ standard
  212. // libraries can either use native Windows threads or pthreads, so we
  213. // don't know with certainty what kind of thread handle we're getting
  214. // from thread.native_handle() here.
  215. typedef HRESULT(WINAPI * proc)(HANDLE, PCWSTR);
  216. HMODULE kbase = GetModuleHandleA("KernelBase.dll");
  217. proc ThreadNameProc =
  218. reinterpret_cast<proc>(GetProcAddress(kbase, "SetThreadDescription"));
  219. if (ThreadNameProc) {
  220. std::wstring buf;
  221. auto sz = MultiByteToWideChar(CP_UTF8, 0, name.data(), -1, nullptr, 0);
  222. if (sz > 0) {
  223. buf.resize(sz);
  224. if (MultiByteToWideChar(CP_UTF8, 0, name.data(), -1, &buf[0], sz) > 0) {
  225. (void)ThreadNameProc(thread.native_handle(), buf.c_str());
  226. }
  227. }
  228. }
  229. #endif
  230. }
  231. } // namespace fuzzer
  232. #endif // LIBFUZZER_WINDOWS