110ab2aceSGeorge Karpenkov //===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // Misc utils implementation for Windows.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
10226866e1SDokyung Song #include "FuzzerPlatform.h"
1110ab2aceSGeorge Karpenkov #if LIBFUZZER_WINDOWS
1204304d12SMatt Morehouse #include "FuzzerCommand.h"
1310ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1410ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
1510ab2aceSGeorge Karpenkov #include <cassert>
1610ab2aceSGeorge Karpenkov #include <chrono>
1710ab2aceSGeorge Karpenkov #include <cstring>
1810ab2aceSGeorge Karpenkov #include <errno.h>
19e5b603a4SMarco Vanotti #include <io.h>
2010ab2aceSGeorge Karpenkov #include <iomanip>
2110ab2aceSGeorge Karpenkov #include <signal.h>
2210ab2aceSGeorge Karpenkov #include <stdio.h>
2310ab2aceSGeorge Karpenkov #include <sys/types.h>
2410ab2aceSGeorge Karpenkov #include <windows.h>
2510ab2aceSGeorge Karpenkov
2610ab2aceSGeorge Karpenkov // This must be included after windows.h.
27e199a2d4SMartin Storsjo #include <psapi.h>
2810ab2aceSGeorge Karpenkov
2910ab2aceSGeorge Karpenkov namespace fuzzer {
3010ab2aceSGeorge Karpenkov
3110ab2aceSGeorge Karpenkov static const FuzzingOptions* HandlerOpt = nullptr;
3210ab2aceSGeorge Karpenkov
ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)3310ab2aceSGeorge Karpenkov static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
3410ab2aceSGeorge Karpenkov switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
3510ab2aceSGeorge Karpenkov case EXCEPTION_ACCESS_VIOLATION:
3610ab2aceSGeorge Karpenkov case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
3710ab2aceSGeorge Karpenkov case EXCEPTION_STACK_OVERFLOW:
3810ab2aceSGeorge Karpenkov if (HandlerOpt->HandleSegv)
3910ab2aceSGeorge Karpenkov Fuzzer::StaticCrashSignalCallback();
4010ab2aceSGeorge Karpenkov break;
4110ab2aceSGeorge Karpenkov case EXCEPTION_DATATYPE_MISALIGNMENT:
4210ab2aceSGeorge Karpenkov case EXCEPTION_IN_PAGE_ERROR:
4310ab2aceSGeorge Karpenkov if (HandlerOpt->HandleBus)
4410ab2aceSGeorge Karpenkov Fuzzer::StaticCrashSignalCallback();
4510ab2aceSGeorge Karpenkov break;
4610ab2aceSGeorge Karpenkov case EXCEPTION_ILLEGAL_INSTRUCTION:
4710ab2aceSGeorge Karpenkov case EXCEPTION_PRIV_INSTRUCTION:
4810ab2aceSGeorge Karpenkov if (HandlerOpt->HandleIll)
4910ab2aceSGeorge Karpenkov Fuzzer::StaticCrashSignalCallback();
5010ab2aceSGeorge Karpenkov break;
5110ab2aceSGeorge Karpenkov case EXCEPTION_FLT_DENORMAL_OPERAND:
5210ab2aceSGeorge Karpenkov case EXCEPTION_FLT_DIVIDE_BY_ZERO:
5310ab2aceSGeorge Karpenkov case EXCEPTION_FLT_INEXACT_RESULT:
5410ab2aceSGeorge Karpenkov case EXCEPTION_FLT_INVALID_OPERATION:
5510ab2aceSGeorge Karpenkov case EXCEPTION_FLT_OVERFLOW:
5610ab2aceSGeorge Karpenkov case EXCEPTION_FLT_STACK_CHECK:
5710ab2aceSGeorge Karpenkov case EXCEPTION_FLT_UNDERFLOW:
5810ab2aceSGeorge Karpenkov case EXCEPTION_INT_DIVIDE_BY_ZERO:
5910ab2aceSGeorge Karpenkov case EXCEPTION_INT_OVERFLOW:
6010ab2aceSGeorge Karpenkov if (HandlerOpt->HandleFpe)
6110ab2aceSGeorge Karpenkov Fuzzer::StaticCrashSignalCallback();
6210ab2aceSGeorge Karpenkov break;
63f897e82bSJoe Pletcher // This is an undocumented exception code corresponding to a Visual C++
64f897e82bSJoe Pletcher // Exception.
65f897e82bSJoe Pletcher //
66f897e82bSJoe Pletcher // See: https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
67f897e82bSJoe Pletcher case 0xE06D7363:
68f897e82bSJoe Pletcher if (HandlerOpt->HandleWinExcept)
69f897e82bSJoe Pletcher Fuzzer::StaticCrashSignalCallback();
70f897e82bSJoe Pletcher break;
71f897e82bSJoe Pletcher // TODO: Handle (Options.HandleXfsz)
7210ab2aceSGeorge Karpenkov }
7310ab2aceSGeorge Karpenkov return EXCEPTION_CONTINUE_SEARCH;
7410ab2aceSGeorge Karpenkov }
7510ab2aceSGeorge Karpenkov
CtrlHandler(DWORD dwCtrlType)7610ab2aceSGeorge Karpenkov BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
7710ab2aceSGeorge Karpenkov switch (dwCtrlType) {
7810ab2aceSGeorge Karpenkov case CTRL_C_EVENT:
7910ab2aceSGeorge Karpenkov if (HandlerOpt->HandleInt)
8010ab2aceSGeorge Karpenkov Fuzzer::StaticInterruptCallback();
8110ab2aceSGeorge Karpenkov return TRUE;
8210ab2aceSGeorge Karpenkov case CTRL_BREAK_EVENT:
8310ab2aceSGeorge Karpenkov if (HandlerOpt->HandleTerm)
8410ab2aceSGeorge Karpenkov Fuzzer::StaticInterruptCallback();
8510ab2aceSGeorge Karpenkov return TRUE;
8610ab2aceSGeorge Karpenkov }
8710ab2aceSGeorge Karpenkov return FALSE;
8810ab2aceSGeorge Karpenkov }
8910ab2aceSGeorge Karpenkov
AlarmHandler(PVOID,BOOLEAN)9010ab2aceSGeorge Karpenkov void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
9110ab2aceSGeorge Karpenkov Fuzzer::StaticAlarmCallback();
9210ab2aceSGeorge Karpenkov }
9310ab2aceSGeorge Karpenkov
9410ab2aceSGeorge Karpenkov class TimerQ {
9510ab2aceSGeorge Karpenkov HANDLE TimerQueue;
9610ab2aceSGeorge Karpenkov public:
TimerQ()977821f892SJonathan Metzman TimerQ() : TimerQueue(NULL) {}
~TimerQ()9810ab2aceSGeorge Karpenkov ~TimerQ() {
9910ab2aceSGeorge Karpenkov if (TimerQueue)
10010ab2aceSGeorge Karpenkov DeleteTimerQueueEx(TimerQueue, NULL);
1017821f892SJonathan Metzman }
SetTimer(int Seconds)10210ab2aceSGeorge Karpenkov void SetTimer(int Seconds) {
10310ab2aceSGeorge Karpenkov if (!TimerQueue) {
10410ab2aceSGeorge Karpenkov TimerQueue = CreateTimerQueue();
10510ab2aceSGeorge Karpenkov if (!TimerQueue) {
10610ab2aceSGeorge Karpenkov Printf("libFuzzer: CreateTimerQueue failed.\n");
10710ab2aceSGeorge Karpenkov exit(1);
10810ab2aceSGeorge Karpenkov }
10910ab2aceSGeorge Karpenkov }
11010ab2aceSGeorge Karpenkov HANDLE Timer;
11110ab2aceSGeorge Karpenkov if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
11210ab2aceSGeorge Karpenkov Seconds*1000, Seconds*1000, 0)) {
11310ab2aceSGeorge Karpenkov Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
11410ab2aceSGeorge Karpenkov exit(1);
11510ab2aceSGeorge Karpenkov }
1167821f892SJonathan Metzman }
11710ab2aceSGeorge Karpenkov };
11810ab2aceSGeorge Karpenkov
11910ab2aceSGeorge Karpenkov static TimerQ Timer;
12010ab2aceSGeorge Karpenkov
CrashHandler(int)12110ab2aceSGeorge Karpenkov static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
12210ab2aceSGeorge Karpenkov
SetSignalHandler(const FuzzingOptions & Options)12310ab2aceSGeorge Karpenkov void SetSignalHandler(const FuzzingOptions& Options) {
12410ab2aceSGeorge Karpenkov HandlerOpt = &Options;
12510ab2aceSGeorge Karpenkov
1269df7ee34SIlya Leoshkevich if (Options.HandleAlrm && Options.UnitTimeoutSec > 0)
12710ab2aceSGeorge Karpenkov Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
12810ab2aceSGeorge Karpenkov
12910ab2aceSGeorge Karpenkov if (Options.HandleInt || Options.HandleTerm)
13010ab2aceSGeorge Karpenkov if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
13110ab2aceSGeorge Karpenkov DWORD LastError = GetLastError();
13210ab2aceSGeorge Karpenkov Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
13310ab2aceSGeorge Karpenkov LastError);
13410ab2aceSGeorge Karpenkov exit(1);
13510ab2aceSGeorge Karpenkov }
13610ab2aceSGeorge Karpenkov
13710ab2aceSGeorge Karpenkov if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
138f897e82bSJoe Pletcher Options.HandleFpe || Options.HandleWinExcept)
13910ab2aceSGeorge Karpenkov SetUnhandledExceptionFilter(ExceptionHandler);
14010ab2aceSGeorge Karpenkov
14110ab2aceSGeorge Karpenkov if (Options.HandleAbrt)
14210ab2aceSGeorge Karpenkov if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
14310ab2aceSGeorge Karpenkov Printf("libFuzzer: signal failed with %d\n", errno);
14410ab2aceSGeorge Karpenkov exit(1);
14510ab2aceSGeorge Karpenkov }
14610ab2aceSGeorge Karpenkov }
14710ab2aceSGeorge Karpenkov
SleepSeconds(int Seconds)14810ab2aceSGeorge Karpenkov void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
14910ab2aceSGeorge Karpenkov
GetPid()15010ab2aceSGeorge Karpenkov unsigned long GetPid() { return GetCurrentProcessId(); }
15110ab2aceSGeorge Karpenkov
GetPeakRSSMb()15210ab2aceSGeorge Karpenkov size_t GetPeakRSSMb() {
15310ab2aceSGeorge Karpenkov PROCESS_MEMORY_COUNTERS info;
15410ab2aceSGeorge Karpenkov if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
15510ab2aceSGeorge Karpenkov return 0;
15610ab2aceSGeorge Karpenkov return info.PeakWorkingSetSize >> 20;
15710ab2aceSGeorge Karpenkov }
15810ab2aceSGeorge Karpenkov
OpenProcessPipe(const char * Command,const char * Mode)15910ab2aceSGeorge Karpenkov FILE *OpenProcessPipe(const char *Command, const char *Mode) {
16010ab2aceSGeorge Karpenkov return _popen(Command, Mode);
16110ab2aceSGeorge Karpenkov }
16210ab2aceSGeorge Karpenkov
CloseProcessPipe(FILE * F)16385515c7fSYuanfang Chen int CloseProcessPipe(FILE *F) {
16485515c7fSYuanfang Chen return _pclose(F);
16585515c7fSYuanfang Chen }
16685515c7fSYuanfang Chen
ExecuteCommand(const Command & Cmd)16704304d12SMatt Morehouse int ExecuteCommand(const Command &Cmd) {
16804304d12SMatt Morehouse std::string CmdLine = Cmd.toString();
16904304d12SMatt Morehouse return system(CmdLine.c_str());
17010ab2aceSGeorge Karpenkov }
17110ab2aceSGeorge Karpenkov
ExecuteCommand(const Command & Cmd,std::string * CmdOutput)1724caeb62eSYuanfang Chen bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
1734caeb62eSYuanfang Chen FILE *Pipe = _popen(Cmd.toString().c_str(), "r");
1744caeb62eSYuanfang Chen if (!Pipe)
1754caeb62eSYuanfang Chen return false;
1764caeb62eSYuanfang Chen
1774caeb62eSYuanfang Chen if (CmdOutput) {
1784caeb62eSYuanfang Chen char TmpBuffer[128];
1794caeb62eSYuanfang Chen while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
1804caeb62eSYuanfang Chen CmdOutput->append(TmpBuffer);
1814caeb62eSYuanfang Chen }
1824caeb62eSYuanfang Chen return _pclose(Pipe) == 0;
1834caeb62eSYuanfang Chen }
1844caeb62eSYuanfang Chen
SearchMemory(const void * Data,size_t DataLen,const void * Patt,size_t PattLen)185c5d72517SMarco Vanotti const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
186c5d72517SMarco Vanotti size_t PattLen) {
187c5d72517SMarco Vanotti // TODO: make this implementation more efficient.
188c5d72517SMarco Vanotti const char *Cdata = (const char *)Data;
189c5d72517SMarco Vanotti const char *Cpatt = (const char *)Patt;
190c5d72517SMarco Vanotti
191c5d72517SMarco Vanotti if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
192c5d72517SMarco Vanotti return NULL;
193c5d72517SMarco Vanotti
194c5d72517SMarco Vanotti if (PattLen == 1)
195c5d72517SMarco Vanotti return memchr(Data, *Cpatt, DataLen);
196c5d72517SMarco Vanotti
197c5d72517SMarco Vanotti const char *End = Cdata + DataLen - PattLen + 1;
198c5d72517SMarco Vanotti
199c5d72517SMarco Vanotti for (const char *It = Cdata; It < End; ++It)
200c5d72517SMarco Vanotti if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
201c5d72517SMarco Vanotti return It;
202c5d72517SMarco Vanotti
203c5d72517SMarco Vanotti return NULL;
204c5d72517SMarco Vanotti }
205c5d72517SMarco Vanotti
DisassembleCmd(const std::string & FileName)20610ab2aceSGeorge Karpenkov std::string DisassembleCmd(const std::string &FileName) {
207*7c921753SKostya Serebryany std::vector<std::string> command_vector;
2087e042bb1SMatt Morehouse command_vector.push_back("dumpbin /summary > nul");
2097e042bb1SMatt Morehouse if (ExecuteCommand(Command(command_vector)) == 0)
21010ab2aceSGeorge Karpenkov return "dumpbin /disasm " + FileName;
21110ab2aceSGeorge Karpenkov Printf("libFuzzer: couldn't find tool to disassemble (dumpbin)\n");
21210ab2aceSGeorge Karpenkov exit(1);
21310ab2aceSGeorge Karpenkov }
21410ab2aceSGeorge Karpenkov
SearchRegexCmd(const std::string & Regex)21510ab2aceSGeorge Karpenkov std::string SearchRegexCmd(const std::string &Regex) {
21610ab2aceSGeorge Karpenkov return "findstr /r \"" + Regex + "\"";
21710ab2aceSGeorge Karpenkov }
21810ab2aceSGeorge Karpenkov
DiscardOutput(int Fd)219e5b603a4SMarco Vanotti void DiscardOutput(int Fd) {
220e5b603a4SMarco Vanotti FILE* Temp = fopen("nul", "w");
221e5b603a4SMarco Vanotti if (!Temp)
222e5b603a4SMarco Vanotti return;
223e5b603a4SMarco Vanotti _dup2(_fileno(Temp), Fd);
224e5b603a4SMarco Vanotti fclose(Temp);
225e5b603a4SMarco Vanotti }
226e5b603a4SMarco Vanotti
22710ab2aceSGeorge Karpenkov } // namespace fuzzer
22810ab2aceSGeorge Karpenkov
22910ab2aceSGeorge Karpenkov #endif // LIBFUZZER_WINDOWS
230