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