1 //===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
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 /* This file allows to fuzz libFuzzer-style target functions
9  (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
10 
11 Usage:
12 ################################################################################
13 cat << EOF > test_fuzzer.cc
14 #include <stddef.h>
15 #include <stdint.h>
16 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
17   if (size > 0 && data[0] == 'H')
18     if (size > 1 && data[1] == 'I')
19        if (size > 2 && data[2] == '!')
20        __builtin_trap();
21   return 0;
22 }
23 EOF
24 # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
25 clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
26 # Build afl-llvm-rt.o.c from the AFL distribution.
27 clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
28 # Build this file, link it with afl-llvm-rt.o.o and the target code.
29 clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
30 # Run AFL:
31 rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
32 $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
33 ################################################################################
34 AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
35 specified. If the file does not exist, it is created. This is useful for getting
36 stack traces (when using ASAN for example) or original error messages on hard
37 to reproduce bugs. Note that any content written to stderr will be written to
38 this file instead of stderr's usual location.
39 
40 AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option.
41 If 1, close stdout at startup. If 2 close stderr; if 3 close both.
42 
43 */
44 #include <assert.h>
45 #include <errno.h>
46 #include <stdint.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 
52 #include <fstream>
53 #include <iostream>
54 #include <vector>
55 
56 // Platform detection. Copied from FuzzerInternal.h
57 #ifdef __linux__
58 #define LIBFUZZER_LINUX 1
59 #define LIBFUZZER_APPLE 0
60 #define LIBFUZZER_NETBSD 0
61 #define LIBFUZZER_FREEBSD 0
62 #define LIBFUZZER_OPENBSD 0
63 #elif __APPLE__
64 #define LIBFUZZER_LINUX 0
65 #define LIBFUZZER_APPLE 1
66 #define LIBFUZZER_NETBSD 0
67 #define LIBFUZZER_FREEBSD 0
68 #define LIBFUZZER_OPENBSD 0
69 #elif __NetBSD__
70 #define LIBFUZZER_LINUX 0
71 #define LIBFUZZER_APPLE 0
72 #define LIBFUZZER_NETBSD 1
73 #define LIBFUZZER_FREEBSD 0
74 #define LIBFUZZER_OPENBSD 0
75 #elif __FreeBSD__
76 #define LIBFUZZER_LINUX 0
77 #define LIBFUZZER_APPLE 0
78 #define LIBFUZZER_NETBSD 0
79 #define LIBFUZZER_FREEBSD 1
80 #define LIBFUZZER_OPENBSD 0
81 #elif __OpenBSD__
82 #define LIBFUZZER_LINUX 0
83 #define LIBFUZZER_APPLE 0
84 #define LIBFUZZER_NETBSD 0
85 #define LIBFUZZER_FREEBSD 0
86 #define LIBFUZZER_OPENBSD 1
87 #else
88 #error "Support for your platform has not been implemented"
89 #endif
90 
91 // libFuzzer interface is thin, so we don't include any libFuzzer headers.
92 extern "C" {
93 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
94 __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
95 }
96 
97 // Notify AFL about persistent mode.
98 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
99 extern "C" int __afl_persistent_loop(unsigned int);
100 static volatile char suppress_warning2 = AFL_PERSISTENT[0];
101 
102 // Notify AFL about deferred forkserver.
103 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
104 extern "C" void __afl_manual_init();
105 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
106 
107 // Input buffer.
108 static const size_t kMaxAflInputSize = 1 << 20;
109 static uint8_t AflInputBuf[kMaxAflInputSize];
110 
111 // Use this optionally defined function to output sanitizer messages even if
112 // user asks to close stderr.
113 __attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *);
114 
115 // Keep track of where stderr content is being written to, so that
116 // dup_and_close_stderr can use the correct one.
117 static FILE *output_file = stderr;
118 
119 // Experimental feature to use afl_driver without AFL's deferred mode.
120 // Needs to run before __afl_auto_init.
121 __attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
122   if (getenv("AFL_DRIVER_DONT_DEFER")) {
123     if (unsetenv("__AFL_DEFER_FORKSRV")) {
124       perror("Failed to unset __AFL_DEFER_FORKSRV");
125       abort();
126     }
127   }
128 }
129 
130 // If the user asks us to duplicate stderr, then do it.
131 static void maybe_duplicate_stderr() {
132   char *stderr_duplicate_filename =
133       getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
134 
135   if (!stderr_duplicate_filename)
136     return;
137 
138   FILE *stderr_duplicate_stream =
139       freopen(stderr_duplicate_filename, "a+", stderr);
140 
141   if (!stderr_duplicate_stream) {
142     fprintf(
143         stderr,
144         "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
145     abort();
146   }
147   output_file = stderr_duplicate_stream;
148 }
149 
150 // Most of these I/O functions were inspired by/copied from libFuzzer's code.
151 static void discard_output(int fd) {
152   FILE *temp = fopen("/dev/null", "w");
153   if (!temp)
154     abort();
155   dup2(fileno(temp), fd);
156   fclose(temp);
157 }
158 
159 static void close_stdout() { discard_output(STDOUT_FILENO); }
160 
161 // Prevent the targeted code from writing to "stderr" but allow sanitizers and
162 // this driver to do so.
163 static void dup_and_close_stderr() {
164   int output_fileno = fileno(output_file);
165   int output_fd = dup(output_fileno);
166   if (output_fd <= 0)
167     abort();
168   FILE *new_output_file = fdopen(output_fd, "w");
169   if (!new_output_file)
170     abort();
171   if (!__sanitizer_set_report_fd)
172     return;
173   __sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));
174   discard_output(output_fileno);
175 }
176 
177 static void Printf(const char *Fmt, ...) {
178   va_list ap;
179   va_start(ap, Fmt);
180   vfprintf(output_file, Fmt, ap);
181   va_end(ap);
182   fflush(output_file);
183 }
184 
185 // Close stdout and/or stderr if user asks for it.
186 static void maybe_close_fd_mask() {
187   char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
188   if (!fd_mask_str)
189     return;
190   int fd_mask = atoi(fd_mask_str);
191   if (fd_mask & 2)
192     dup_and_close_stderr();
193   if (fd_mask & 1)
194     close_stdout();
195 }
196 
197 // Define LLVMFuzzerMutate to avoid link failures for targets that use it
198 // with libFuzzer's LLVMFuzzerCustomMutator.
199 extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
200   assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
201   return 0;
202 }
203 
204 // Execute any files provided as parameters.
205 static int ExecuteFilesOnyByOne(int argc, char **argv) {
206   for (int i = 1; i < argc; i++) {
207     std::ifstream in(argv[i], std::ios::binary);
208     in.seekg(0, in.end);
209     size_t length = in.tellg();
210     in.seekg (0, in.beg);
211     std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
212     // Allocate exactly length bytes so that we reliably catch buffer overflows.
213     std::vector<char> bytes(length);
214     in.read(bytes.data(), bytes.size());
215     assert(in);
216     LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
217                            bytes.size());
218     std::cout << "Execution successful" << std::endl;
219   }
220   return 0;
221 }
222 
223 int main(int argc, char **argv) {
224   Printf(
225       "======================= INFO =========================\n"
226       "This binary is built for AFL-fuzz.\n"
227       "To run the target function on individual input(s) execute this:\n"
228       "  %s < INPUT_FILE\n"
229       "or\n"
230       "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
231       "To fuzz with afl-fuzz execute this:\n"
232       "  afl-fuzz [afl-flags] %s [-N]\n"
233       "afl-fuzz will run N iterations before "
234       "re-spawning the process (default: 1000)\n"
235       "======================================================\n",
236           argv[0], argv[0], argv[0]);
237 
238   maybe_duplicate_stderr();
239   maybe_close_fd_mask();
240   if (LLVMFuzzerInitialize)
241     LLVMFuzzerInitialize(&argc, &argv);
242   // Do any other expensive one-time initialization here.
243 
244   if (!getenv("AFL_DRIVER_DONT_DEFER"))
245     __afl_manual_init();
246 
247   int N = 1000;
248   if (argc == 2 && argv[1][0] == '-')
249       N = atoi(argv[1] + 1);
250   else if(argc == 2 && (N = atoi(argv[1])) > 0)
251       Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
252   else if (argc > 1)
253     return ExecuteFilesOnyByOne(argc, argv);
254 
255   assert(N > 0);
256 
257   // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
258   // on the first execution of LLVMFuzzerTestOneInput is ignored.
259   uint8_t dummy_input[1] = {0};
260   LLVMFuzzerTestOneInput(dummy_input, 1);
261 
262   int num_runs = 0;
263   while (__afl_persistent_loop(N)) {
264     ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
265     if (n_read > 0) {
266       // Copy AflInputBuf into a separate buffer to let asan find buffer
267       // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
268       uint8_t *copy = new uint8_t[n_read];
269       memcpy(copy, AflInputBuf, n_read);
270       num_runs++;
271       LLVMFuzzerTestOneInput(copy, n_read);
272       delete[] copy;
273     }
274   }
275   Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
276 }
277