FuzzerUtilWindows.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. #include <windows.h>
  25. // This must be included after windows.h.
  26. #include <psapi.h>
  27. namespace fuzzer {
  28. static const FuzzingOptions* HandlerOpt = nullptr;
  29. static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
  30. switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
  31. case EXCEPTION_ACCESS_VIOLATION:
  32. case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
  33. case EXCEPTION_STACK_OVERFLOW:
  34. if (HandlerOpt->HandleSegv)
  35. Fuzzer::StaticCrashSignalCallback();
  36. break;
  37. case EXCEPTION_DATATYPE_MISALIGNMENT:
  38. case EXCEPTION_IN_PAGE_ERROR:
  39. if (HandlerOpt->HandleBus)
  40. Fuzzer::StaticCrashSignalCallback();
  41. break;
  42. case EXCEPTION_ILLEGAL_INSTRUCTION:
  43. case EXCEPTION_PRIV_INSTRUCTION:
  44. if (HandlerOpt->HandleIll)
  45. Fuzzer::StaticCrashSignalCallback();
  46. break;
  47. case EXCEPTION_FLT_DENORMAL_OPERAND:
  48. case EXCEPTION_FLT_DIVIDE_BY_ZERO:
  49. case EXCEPTION_FLT_INEXACT_RESULT:
  50. case EXCEPTION_FLT_INVALID_OPERATION:
  51. case EXCEPTION_FLT_OVERFLOW:
  52. case EXCEPTION_FLT_STACK_CHECK:
  53. case EXCEPTION_FLT_UNDERFLOW:
  54. case EXCEPTION_INT_DIVIDE_BY_ZERO:
  55. case EXCEPTION_INT_OVERFLOW:
  56. if (HandlerOpt->HandleFpe)
  57. Fuzzer::StaticCrashSignalCallback();
  58. break;
  59. // This is an undocumented exception code corresponding to a Visual C++
  60. // Exception.
  61. //
  62. // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
  63. case 0xE06D7363:
  64. if (HandlerOpt->HandleWinExcept)
  65. Fuzzer::StaticCrashSignalCallback();
  66. break;
  67. // TODO: Handle (Options.HandleXfsz)
  68. }
  69. return EXCEPTION_CONTINUE_SEARCH;
  70. }
  71. BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
  72. switch (dwCtrlType) {
  73. case CTRL_C_EVENT:
  74. if (HandlerOpt->HandleInt)
  75. Fuzzer::StaticInterruptCallback();
  76. return TRUE;
  77. case CTRL_BREAK_EVENT:
  78. if (HandlerOpt->HandleTerm)
  79. Fuzzer::StaticInterruptCallback();
  80. return TRUE;
  81. }
  82. return FALSE;
  83. }
  84. void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
  85. Fuzzer::StaticAlarmCallback();
  86. }
  87. class TimerQ {
  88. HANDLE TimerQueue;
  89. public:
  90. TimerQ() : TimerQueue(NULL) {}
  91. ~TimerQ() {
  92. if (TimerQueue)
  93. DeleteTimerQueueEx(TimerQueue, NULL);
  94. }
  95. void SetTimer(int Seconds) {
  96. if (!TimerQueue) {
  97. TimerQueue = CreateTimerQueue();
  98. if (!TimerQueue) {
  99. Printf("libFuzzer: CreateTimerQueue failed.\n");
  100. exit(1);
  101. }
  102. }
  103. HANDLE Timer;
  104. if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
  105. Seconds*1000, Seconds*1000, 0)) {
  106. Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
  107. exit(1);
  108. }
  109. }
  110. };
  111. static TimerQ Timer;
  112. static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
  113. void SetSignalHandler(const FuzzingOptions& Options) {
  114. HandlerOpt = &Options;
  115. if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
  116. Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
  117. if (Options.HandleInt || Options.HandleTerm)
  118. if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
  119. DWORD LastError = GetLastError();
  120. Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
  121. LastError);
  122. exit(1);
  123. }
  124. if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
  125. Options.HandleFpe || Options.HandleWinExcept)
  126. SetUnhandledExceptionFilter(ExceptionHandler);
  127. if (Options.HandleAbrt)
  128. if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
  129. Printf("libFuzzer: signal failed with %d\n", errno);
  130. exit(1);
  131. }
  132. }
  133. void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
  134. unsigned long GetPid() { return GetCurrentProcessId(); }
  135. size_t GetPeakRSSMb() {
  136. PROCESS_MEMORY_COUNTERS info;
  137. if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
  138. return 0;
  139. return info.PeakWorkingSetSize >> 20;
  140. }
  141. FILE *OpenProcessPipe(const char *Command, const char *Mode) {
  142. return _popen(Command, Mode);
  143. }
  144. int CloseProcessPipe(FILE *F) {
  145. return _pclose(F);
  146. }
  147. int ExecuteCommand(const Command &Cmd) {
  148. std::string CmdLine = Cmd.toString();
  149. return system(CmdLine.c_str());
  150. }
  151. bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
  152. FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
  153. if (!Pipe)
  154. return false;
  155. if (CmdOutput) {
  156. char TmpBuffer[128];
  157. while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
  158. CmdOutput->append(TmpBuffer);
  159. }
  160. return _pclose(Pipe) == 0;
  161. }
  162. const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
  163. size_t PattLen) {
  164. // TODO: make this implementation more efficient.
  165. const char *Cdata = (const char *)Data;
  166. const char *Cpatt = (const char *)Patt;
  167. if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
  168. return NULL;
  169. if (PattLen == 1)
  170. return memchr(Data, *Cpatt, DataLen);
  171. const char *End = Cdata + DataLen - PattLen + 1;
  172. for (const char *It = Cdata; It < End; ++It)
  173. if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
  174. return It;
  175. return NULL;
  176. }
  177. std::string DisassembleCmd(const std::string &FileName) {
  178. std::vector<std::string> command_vector;
  179. command_vector.push_back("dumpbin /summary > nul");
  180. if (ExecuteCommand(Command(command_vector)) == 0)
  181. return "dumpbin /disasm " + FileName;
  182. Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
  183. exit(1);
  184. }
  185. std::string SearchRegexCmd(const std::string &Regex) {
  186. return "findstr /r \"" + Regex + "\"";
  187. }
  188. void DiscardOutput(int Fd) {
  189. FILE* Temp = fopen("nul", "w");
  190. if (!Temp)
  191. return;
  192. _dup2(_fileno(Temp), Fd);
  193. fclose(Temp);
  194. }
  195. } // namespace fuzzer
  196. #endif // LIBFUZZER_WINDOWS