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