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