1 //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // Misc utils implementation for Windows.
10 //===----------------------------------------------------------------------===//
11 #include "FuzzerDefs.h"
12 #if LIBFUZZER_WINDOWS
13 #include "FuzzerCommand.h"
14 #include "FuzzerIO.h"
15 #include "FuzzerInternal.h"
16 #include <cassert>
17 #include <chrono>
18 #include <cstring>
19 #include <errno.h>
20 #include <iomanip>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <windows.h>
25 
26 // This must be included after windows.h.
27 #include <psapi.h>
28 
29 namespace fuzzer {
30 
31 static const FuzzingOptions* HandlerOpt = nullptr;
32 
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)33 static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
34   switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
35     case EXCEPTION_ACCESS_VIOLATION:
36     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
37     case EXCEPTION_STACK_OVERFLOW:
38       if (HandlerOpt->HandleSegv)
39         Fuzzer::StaticCrashSignalCallback();
40       break;
41     case EXCEPTION_DATATYPE_MISALIGNMENT:
42     case EXCEPTION_IN_PAGE_ERROR:
43       if (HandlerOpt->HandleBus)
44         Fuzzer::StaticCrashSignalCallback();
45       break;
46     case EXCEPTION_ILLEGAL_INSTRUCTION:
47     case EXCEPTION_PRIV_INSTRUCTION:
48       if (HandlerOpt->HandleIll)
49         Fuzzer::StaticCrashSignalCallback();
50       break;
51     case EXCEPTION_FLT_DENORMAL_OPERAND:
52     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
53     case EXCEPTION_FLT_INEXACT_RESULT:
54     case EXCEPTION_FLT_INVALID_OPERATION:
55     case EXCEPTION_FLT_OVERFLOW:
56     case EXCEPTION_FLT_STACK_CHECK:
57     case EXCEPTION_FLT_UNDERFLOW:
58     case EXCEPTION_INT_DIVIDE_BY_ZERO:
59     case EXCEPTION_INT_OVERFLOW:
60       if (HandlerOpt->HandleFpe)
61         Fuzzer::StaticCrashSignalCallback();
62       break;
63     // TODO: handle (Options.HandleXfsz)
64   }
65   return EXCEPTION_CONTINUE_SEARCH;
66 }
67 
CtrlHandler(DWORD dwCtrlType)68 BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
69   switch (dwCtrlType) {
70     case CTRL_C_EVENT:
71       if (HandlerOpt->HandleInt)
72         Fuzzer::StaticInterruptCallback();
73       return TRUE;
74     case CTRL_BREAK_EVENT:
75       if (HandlerOpt->HandleTerm)
76         Fuzzer::StaticInterruptCallback();
77       return TRUE;
78   }
79   return FALSE;
80 }
81 
AlarmHandler(PVOID,BOOLEAN)82 void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
83   Fuzzer::StaticAlarmCallback();
84 }
85 
86 class TimerQ {
87   HANDLE TimerQueue;
88  public:
TimerQ()89   TimerQ() : TimerQueue(NULL) {};
~TimerQ()90   ~TimerQ() {
91     if (TimerQueue)
92       DeleteTimerQueueEx(TimerQueue, NULL);
93   };
SetTimer(int Seconds)94   void SetTimer(int Seconds) {
95     if (!TimerQueue) {
96       TimerQueue = CreateTimerQueue();
97       if (!TimerQueue) {
98         Printf("libFuzzer: CreateTimerQueue failed.\n");
99         exit(1);
100       }
101     }
102     HANDLE Timer;
103     if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
104         Seconds*1000, Seconds*1000, 0)) {
105       Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
106       exit(1);
107     }
108   };
109 };
110 
111 static TimerQ Timer;
112 
CrashHandler(int)113 static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
114 
SetSignalHandler(const FuzzingOptions & Options)115 void SetSignalHandler(const FuzzingOptions& Options) {
116   HandlerOpt = &Options;
117 
118   if (Options.UnitTimeoutSec > 0)
119     Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
120 
121   if (Options.HandleInt || Options.HandleTerm)
122     if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
123       DWORD LastError = GetLastError();
124       Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
125         LastError);
126       exit(1);
127     }
128 
129   if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
130       Options.HandleFpe)
131     SetUnhandledExceptionFilter(ExceptionHandler);
132 
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 
SleepSeconds(int Seconds)140 void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
141 
GetPid()142 unsigned long GetPid() { return GetCurrentProcessId(); }
143 
GetPeakRSSMb()144 size_t GetPeakRSSMb() {
145   PROCESS_MEMORY_COUNTERS info;
146   if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
147     return 0;
148   return info.PeakWorkingSetSize >> 20;
149 }
150 
OpenProcessPipe(const char * Command,const char * Mode)151 FILE *OpenProcessPipe(const char *Command, const char *Mode) {
152   return _popen(Command, Mode);
153 }
154 
ExecuteCommand(const Command & Cmd)155 int ExecuteCommand(const Command &Cmd) {
156   std::string CmdLine = Cmd.toString();
157   return system(CmdLine.c_str());
158 }
159 
SearchMemory(const void * Data,size_t DataLen,const void * Patt,size_t PattLen)160 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
161                          size_t PattLen) {
162   // TODO: make this implementation more efficient.
163   const char *Cdata = (const char *)Data;
164   const char *Cpatt = (const char *)Patt;
165 
166   if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
167     return NULL;
168 
169   if (PattLen == 1)
170     return memchr(Data, *Cpatt, DataLen);
171 
172   const char *End = Cdata + DataLen - PattLen + 1;
173 
174   for (const char *It = Cdata; It < End; ++It)
175     if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
176       return It;
177 
178   return NULL;
179 }
180 
DisassembleCmd(const std::string & FileName)181 std::string DisassembleCmd(const std::string &FileName) {
182   Vector<std::string> command_vector;
183   command_vector.push_back("dumpbin /summary > nul");
184   if (ExecuteCommand(Command(command_vector)) == 0)
185     return "dumpbin /disasm " + FileName;
186   Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
187   exit(1);
188 }
189 
SearchRegexCmd(const std::string & Regex)190 std::string SearchRegexCmd(const std::string &Regex) {
191   return "findstr /r \"" + Regex + "\"";
192 }
193 
194 } // namespace fuzzer
195 
196 #endif // LIBFUZZER_WINDOWS
197