xref: /freebsd/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp (revision e1e636193db45630c7881246d25902e57c43d24e)
1 //===- FuzzerUtilPosix.cpp - Misc utils for Posix. ------------------------===//
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 using Posix API.
9 //===----------------------------------------------------------------------===//
10 #include "FuzzerPlatform.h"
11 #if LIBFUZZER_POSIX
12 #include "FuzzerIO.h"
13 #include "FuzzerInternal.h"
14 #include "FuzzerTracePC.h"
15 #include <cassert>
16 #include <chrono>
17 #include <cstring>
18 #include <errno.h>
19 #include <iomanip>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <sys/mman.h>
23 #include <sys/resource.h>
24 #include <sys/syscall.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <thread>
28 #include <unistd.h>
29 
30 namespace fuzzer {
31 
32 static void AlarmHandler(int, siginfo_t *, void *) {
33   Fuzzer::StaticAlarmCallback();
34 }
35 
36 static void (*upstream_segv_handler)(int, siginfo_t *, void *);
37 
38 static void SegvHandler(int sig, siginfo_t *si, void *ucontext) {
39   assert(si->si_signo == SIGSEGV);
40   if (upstream_segv_handler)
41     return upstream_segv_handler(sig, si, ucontext);
42   Fuzzer::StaticCrashSignalCallback();
43 }
44 
45 static void CrashHandler(int, siginfo_t *, void *) {
46   Fuzzer::StaticCrashSignalCallback();
47 }
48 
49 static void InterruptHandler(int, siginfo_t *, void *) {
50   Fuzzer::StaticInterruptCallback();
51 }
52 
53 static void GracefulExitHandler(int, siginfo_t *, void *) {
54   Fuzzer::StaticGracefulExitCallback();
55 }
56 
57 static void FileSizeExceedHandler(int, siginfo_t *, void *) {
58   Fuzzer::StaticFileSizeExceedCallback();
59 }
60 
61 static void SetSigaction(int signum,
62                          void (*callback)(int, siginfo_t *, void *)) {
63   struct sigaction sigact = {};
64   if (sigaction(signum, nullptr, &sigact)) {
65     Printf("libFuzzer: sigaction failed with %d\n", errno);
66     exit(1);
67   }
68   if (sigact.sa_flags & SA_SIGINFO) {
69     if (sigact.sa_sigaction) {
70       if (signum != SIGSEGV)
71         return;
72       upstream_segv_handler = sigact.sa_sigaction;
73     }
74   } else {
75     if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN &&
76         sigact.sa_handler != SIG_ERR)
77       return;
78   }
79 
80   struct sigaction new_sigact = {};
81   // Address sanitizer needs SA_ONSTACK (causing the signal handler to run on a
82   // dedicated stack) in order to be able to detect stack overflows; keep the
83   // flag if it's set.
84   new_sigact.sa_flags = SA_SIGINFO | (sigact.sa_flags & SA_ONSTACK);
85   new_sigact.sa_sigaction = callback;
86   if (sigaction(signum, &new_sigact, nullptr)) {
87     Printf("libFuzzer: sigaction failed with %d\n", errno);
88     exit(1);
89   }
90 }
91 
92 // Return true on success, false otherwise.
93 bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
94   FILE *Pipe = popen(Cmd.toString().c_str(), "r");
95   if (!Pipe)
96     return false;
97 
98   if (CmdOutput) {
99     char TmpBuffer[128];
100     while (fgets(TmpBuffer, sizeof(TmpBuffer), Pipe))
101       CmdOutput->append(TmpBuffer);
102   }
103   return pclose(Pipe) == 0;
104 }
105 
106 void SetTimer(int Seconds) {
107   struct itimerval T {
108     {Seconds, 0}, { Seconds, 0 }
109   };
110   if (setitimer(ITIMER_REAL, &T, nullptr)) {
111     Printf("libFuzzer: setitimer failed with %d\n", errno);
112     exit(1);
113   }
114   SetSigaction(SIGALRM, AlarmHandler);
115 }
116 
117 void SetSignalHandler(const FuzzingOptions& Options) {
118   // setitimer is not implemented in emscripten.
119   if (Options.HandleAlrm && Options.UnitTimeoutSec > 0 && !LIBFUZZER_EMSCRIPTEN)
120     SetTimer(Options.UnitTimeoutSec / 2 + 1);
121   if (Options.HandleInt)
122     SetSigaction(SIGINT, InterruptHandler);
123   if (Options.HandleTerm)
124     SetSigaction(SIGTERM, InterruptHandler);
125   if (Options.HandleSegv)
126     SetSigaction(SIGSEGV, SegvHandler);
127   if (Options.HandleBus)
128     SetSigaction(SIGBUS, CrashHandler);
129   if (Options.HandleAbrt)
130     SetSigaction(SIGABRT, CrashHandler);
131   if (Options.HandleIll)
132     SetSigaction(SIGILL, CrashHandler);
133   if (Options.HandleFpe)
134     SetSigaction(SIGFPE, CrashHandler);
135   if (Options.HandleXfsz)
136     SetSigaction(SIGXFSZ, FileSizeExceedHandler);
137   if (Options.HandleUsr1)
138     SetSigaction(SIGUSR1, GracefulExitHandler);
139   if (Options.HandleUsr2)
140     SetSigaction(SIGUSR2, GracefulExitHandler);
141 }
142 
143 void SleepSeconds(int Seconds) {
144   sleep(Seconds); // Use C API to avoid coverage from instrumented libc++.
145 }
146 
147 unsigned long GetPid() { return (unsigned long)getpid(); }
148 
149 size_t GetPeakRSSMb() {
150   struct rusage usage;
151   if (getrusage(RUSAGE_SELF, &usage))
152     return 0;
153   if (LIBFUZZER_LINUX || LIBFUZZER_FREEBSD || LIBFUZZER_NETBSD ||
154       LIBFUZZER_EMSCRIPTEN) {
155     // ru_maxrss is in KiB
156     return usage.ru_maxrss >> 10;
157   } else if (LIBFUZZER_APPLE) {
158     // ru_maxrss is in bytes
159     return usage.ru_maxrss >> 20;
160   }
161   assert(0 && "GetPeakRSSMb() is not implemented for your platform");
162   return 0;
163 }
164 
165 FILE *OpenProcessPipe(const char *Command, const char *Mode) {
166   return popen(Command, Mode);
167 }
168 
169 int CloseProcessPipe(FILE *F) {
170   return pclose(F);
171 }
172 
173 const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
174                          size_t PattLen) {
175   return memmem(Data, DataLen, Patt, PattLen);
176 }
177 
178 std::string DisassembleCmd(const std::string &FileName) {
179   return "objdump -d " + FileName;
180 }
181 
182 std::string SearchRegexCmd(const std::string &Regex) {
183   return "grep '" + Regex + "'";
184 }
185 
186 size_t PageSize() {
187   static size_t PageSizeCached = sysconf(_SC_PAGESIZE);
188   return PageSizeCached;
189 }
190 
191 }  // namespace fuzzer
192 
193 #endif // LIBFUZZER_POSIX
194