1 //===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
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 /* This file allows to fuzz libFuzzer-style target functions
10  (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
11 
12 Usage:
13 ################################################################################
14 cat << EOF > test_fuzzer.cc
15 #include <stddef.h>
16 #include <stdint.h>
17 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
18   if (size > 0 && data[0] == 'H')
19     if (size > 1 && data[1] == 'I')
20        if (size > 2 && data[2] == '!')
21        __builtin_trap();
22   return 0;
23 }
24 EOF
25 # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
26 clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
27 # Build afl-llvm-rt.o.c from the AFL distribution.
28 clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
29 # Build this file, link it with afl-llvm-rt.o.o and the target code.
30 clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
31 # Run AFL:
32 rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
33 $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
34 ################################################################################
35 Environment Variables:
36 There are a few environment variables that can be set to use features that
37 afl-fuzz doesn't have.
38 
39 AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
40 specified. If the file does not exist, it is created. This is useful for getting
41 stack traces (when using ASAN for example) or original error messages on hard to
42 reproduce bugs.
43 
44 AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
45 statistics to the file specified. Currently these are peak_rss_mb
46 (the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
47 the file does not exist it is created. If the file does exist then
48 afl_driver assumes it was restarted by afl-fuzz and will try to read old
49 statistics from the file. If that fails then the process will quit.
50 
51 */
52 #include <assert.h>
53 #include <errno.h>
54 #include <signal.h>
55 #include <stdint.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <sys/resource.h>
60 #include <sys/time.h>
61 #include <unistd.h>
62 
63 #include <fstream>
64 #include <iostream>
65 #include <vector>
66 
67 // Platform detection. Copied from FuzzerInternal.h
68 #ifdef __linux__
69 #define LIBFUZZER_LINUX 1
70 #define LIBFUZZER_APPLE 0
71 #define LIBFUZZER_NETBSD 0
72 #define LIBFUZZER_FREEBSD 0
73 #elif __APPLE__
74 #define LIBFUZZER_LINUX 0
75 #define LIBFUZZER_APPLE 1
76 #define LIBFUZZER_NETBSD 0
77 #define LIBFUZZER_FREEBSD 0
78 #elif __NetBSD__
79 #define LIBFUZZER_LINUX 0
80 #define LIBFUZZER_APPLE 0
81 #define LIBFUZZER_NETBSD 1
82 #define LIBFUZZER_FREEBSD 0
83 #elif __FreeBSD__
84 #define LIBFUZZER_LINUX 0
85 #define LIBFUZZER_APPLE 0
86 #define LIBFUZZER_NETBSD 0
87 #define LIBFUZZER_FREEBSD 1
88 #else
89 #error "Support for your platform has not been implemented"
90 #endif
91 
92 // Used to avoid repeating error checking boilerplate. If cond is false, a
93 // fatal error has occured in the program. In this event print error_message
94 // to stderr and abort(). Otherwise do nothing. Note that setting
95 // AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
96 // to the file as well, if the error occurs after the duplication is performed.
97 #define CHECK_ERROR(cond, error_message)                                       \
98   if (!(cond)) {                                                               \
99     fprintf(stderr, "%s\n", (error_message));                                  \
100     abort();                                                                   \
101   }
102 
103 // libFuzzer interface is thin, so we don't include any libFuzzer headers.
104 extern "C" {
105 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
106 __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
107 }
108 
109 // Notify AFL about persistent mode.
110 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
111 extern "C" int __afl_persistent_loop(unsigned int);
112 static volatile char suppress_warning2 = AFL_PERSISTENT[0];
113 
114 // Notify AFL about deferred forkserver.
115 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
116 extern "C" void  __afl_manual_init();
117 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
118 
119 // Input buffer.
120 static const size_t kMaxAflInputSize = 1 << 20;
121 static uint8_t AflInputBuf[kMaxAflInputSize];
122 
123 // Variables we need for writing to the extra stats file.
124 static FILE *extra_stats_file = NULL;
125 static uint32_t previous_peak_rss = 0;
126 static time_t slowest_unit_time_secs = 0;
127 static const int kNumExtraStats = 2;
128 static const char *kExtraStatsFormatString = "peak_rss_mb            : %u\n"
129                                              "slowest_unit_time_sec  : %u\n";
130 
131 // Copied from FuzzerUtil.cpp.
132 size_t GetPeakRSSMb() {
133   struct rusage usage;
134   if (getrusage(RUSAGE_SELF, &usage))
135     return 0;
136   if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD) {
137     // ru_maxrss is in KiB
138     return usage.ru_maxrss >> 10;
139   } else if (LIBFUZZER_APPLE) {
140     // ru_maxrss is in bytes
141     return usage.ru_maxrss >> 20;
142   }
143   assert(0 && "GetPeakRSSMb() is not implemented for your platform");
144   return 0;
145 }
146 
147 // Based on SetSigaction in FuzzerUtil.cpp
148 static void SetSigaction(int signum,
149                          void (*callback)(int, siginfo_t *, void *)) {
150   struct sigaction sigact;
151   memset(&sigact, 0, sizeof(sigact));
152   sigact.sa_sigaction = callback;
153   if (sigaction(signum, &sigact, 0)) {
154     fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
155     exit(1);
156   }
157 }
158 
159 // Write extra stats to the file specified by the user. If none is specified
160 // this function will never be called.
161 static void write_extra_stats() {
162   uint32_t peak_rss = GetPeakRSSMb();
163 
164   if (peak_rss < previous_peak_rss)
165     peak_rss = previous_peak_rss;
166 
167   int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
168                               peak_rss, slowest_unit_time_secs);
169 
170   CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
171 
172   CHECK_ERROR(fclose(extra_stats_file) == 0,
173               "Failed to close extra_stats_file");
174 }
175 
176 // Call write_extra_stats before we exit.
177 static void crash_handler(int, siginfo_t *, void *) {
178   // Make sure we don't try calling write_extra_stats again if we crashed while
179   // trying to call it.
180   static bool first_crash = true;
181   CHECK_ERROR(first_crash,
182               "Crashed in crash signal handler. This is a bug in the fuzzer.");
183 
184   first_crash = false;
185   write_extra_stats();
186 }
187 
188 // If the user has specified an extra_stats_file through the environment
189 // variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
190 // to write stats to it on exit. If no file is specified, do nothing. Otherwise
191 // install signal and exit handlers to write to the file when the process exits.
192 // Then if the file doesn't exist create it and set extra stats to 0. But if it
193 // does exist then read the initial values of the extra stats from the file
194 // and check that the file is writable.
195 static void maybe_initialize_extra_stats() {
196   // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
197   char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
198   if (!extra_stats_filename)
199     return;
200 
201   // Open the file and find the previous peak_rss_mb value.
202   // This is necessary because the fuzzing process is restarted after N
203   // iterations are completed. So we may need to get this value from a previous
204   // process to be accurate.
205   extra_stats_file = fopen(extra_stats_filename, "r");
206 
207   // If extra_stats_file already exists: read old stats from it.
208   if (extra_stats_file) {
209     int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
210                          &previous_peak_rss, &slowest_unit_time_secs);
211 
212     // Make sure we have read a real extra stats file and that we have used it
213     // to set slowest_unit_time_secs and previous_peak_rss.
214     CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
215 
216     CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
217 
218     // Now open the file for writing.
219     extra_stats_file = fopen(extra_stats_filename, "w");
220     CHECK_ERROR(extra_stats_file,
221                 "Failed to open extra stats file for writing");
222   } else {
223     // Looks like this is the first time in a fuzzing job this is being called.
224     extra_stats_file = fopen(extra_stats_filename, "w+");
225     CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
226   }
227 
228   // Make sure that crash_handler gets called on any kind of fatal error.
229   int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE,  SIGINT,
230                          SIGTERM};
231 
232   const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
233 
234   for (size_t idx = 0; idx < num_signals; idx++)
235     SetSigaction(crash_signals[idx], crash_handler);
236 
237   // Make sure it gets called on other kinds of exits.
238   atexit(write_extra_stats);
239 }
240 
241 // If the user asks us to duplicate stderr, then do it.
242 static void maybe_duplicate_stderr() {
243   char* stderr_duplicate_filename =
244       getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
245 
246   if (!stderr_duplicate_filename)
247     return;
248 
249   FILE* stderr_duplicate_stream =
250       freopen(stderr_duplicate_filename, "a+", stderr);
251 
252   if (!stderr_duplicate_stream) {
253     fprintf(
254         stderr,
255         "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
256     abort();
257   }
258 }
259 
260 // Define LLVMFuzzerMutate to avoid link failures for targets that use it
261 // with libFuzzer's LLVMFuzzerCustomMutator.
262 extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
263   assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
264   return 0;
265 }
266 
267 // Execute any files provided as parameters.
268 int ExecuteFilesOnyByOne(int argc, char **argv) {
269   for (int i = 1; i < argc; i++) {
270     std::ifstream in(argv[i]);
271     in.seekg(0, in.end);
272     size_t length = in.tellg();
273     in.seekg (0, in.beg);
274     std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
275     // Allocate exactly length bytes so that we reliably catch buffer overflows.
276     std::vector<char> bytes(length);
277     in.read(bytes.data(), bytes.size());
278     assert(in);
279     LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
280                            bytes.size());
281     std::cout << "Execution successfull" << std::endl;
282   }
283   return 0;
284 }
285 
286 int main(int argc, char **argv) {
287   fprintf(stderr,
288       "======================= INFO =========================\n"
289       "This binary is built for AFL-fuzz.\n"
290       "To run the target function on individual input(s) execute this:\n"
291       "  %s < INPUT_FILE\n"
292       "or\n"
293       "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
294       "To fuzz with afl-fuzz execute this:\n"
295       "  afl-fuzz [afl-flags] %s [-N]\n"
296       "afl-fuzz will run N iterations before "
297       "re-spawning the process (default: 1000)\n"
298       "======================================================\n",
299           argv[0], argv[0], argv[0]);
300   if (LLVMFuzzerInitialize)
301     LLVMFuzzerInitialize(&argc, &argv);
302   // Do any other expensive one-time initialization here.
303 
304   maybe_duplicate_stderr();
305   maybe_initialize_extra_stats();
306 
307   __afl_manual_init();
308 
309   int N = 1000;
310   if (argc == 2 && argv[1][0] == '-')
311       N = atoi(argv[1] + 1);
312   else if(argc == 2 && (N = atoi(argv[1])) > 0)
313       fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
314               argv[0], N);
315   else if (argc > 1)
316     return ExecuteFilesOnyByOne(argc, argv);
317 
318   assert(N > 0);
319 
320   // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
321   // on the first execution of LLVMFuzzerTestOneInput is ignored.
322   uint8_t dummy_input[1] = {0};
323   LLVMFuzzerTestOneInput(dummy_input, 1);
324 
325   time_t unit_time_secs;
326   int num_runs = 0;
327   while (__afl_persistent_loop(N)) {
328     ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
329     if (n_read > 0) {
330       // Copy AflInputBuf into a separate buffer to let asan find buffer
331       // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
332       uint8_t *copy = new uint8_t[n_read];
333       memcpy(copy, AflInputBuf, n_read);
334 
335       struct timeval unit_start_time;
336       CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
337                   "Calling gettimeofday failed");
338 
339       num_runs++;
340       LLVMFuzzerTestOneInput(copy, n_read);
341 
342       struct timeval unit_stop_time;
343       CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
344                   "Calling gettimeofday failed");
345 
346       // Update slowest_unit_time_secs if we see a new max.
347       unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
348       if (slowest_unit_time_secs < unit_time_secs)
349         slowest_unit_time_secs = unit_time_secs;
350 
351       delete[] copy;
352     }
353   }
354   fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
355 }
356