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