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