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 environment variable
35 *appends* stderr to the file specified. If the file does not exist, it is
36 created. This is useful for getting stack traces (when using ASAN for example)
37 or original error messages on hard to reproduce bugs.
38 
39 */
40 #include <assert.h>
41 #include <errno.h>
42 #include <stdint.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 
48 #include <fstream>
49 #include <iostream>
50 #include <vector>
51 
52 // Platform detection. Copied from FuzzerInternal.h
53 #ifdef __linux__
54 #define LIBFUZZER_LINUX 1
55 #define LIBFUZZER_APPLE 0
56 #define LIBFUZZER_NETBSD 0
57 #define LIBFUZZER_FREEBSD 0
58 #define LIBFUZZER_OPENBSD 0
59 #elif __APPLE__
60 #define LIBFUZZER_LINUX 0
61 #define LIBFUZZER_APPLE 1
62 #define LIBFUZZER_NETBSD 0
63 #define LIBFUZZER_FREEBSD 0
64 #define LIBFUZZER_OPENBSD 0
65 #elif __NetBSD__
66 #define LIBFUZZER_LINUX 0
67 #define LIBFUZZER_APPLE 0
68 #define LIBFUZZER_NETBSD 1
69 #define LIBFUZZER_FREEBSD 0
70 #define LIBFUZZER_OPENBSD 0
71 #elif __FreeBSD__
72 #define LIBFUZZER_LINUX 0
73 #define LIBFUZZER_APPLE 0
74 #define LIBFUZZER_NETBSD 0
75 #define LIBFUZZER_FREEBSD 1
76 #define LIBFUZZER_OPENBSD 0
77 #elif __OpenBSD__
78 #define LIBFUZZER_LINUX 0
79 #define LIBFUZZER_APPLE 0
80 #define LIBFUZZER_NETBSD 0
81 #define LIBFUZZER_FREEBSD 0
82 #define LIBFUZZER_OPENBSD 1
83 #else
84 #error "Support for your platform has not been implemented"
85 #endif
86 
87 // libFuzzer interface is thin, so we don't include any libFuzzer headers.
88 extern "C" {
89 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
90 __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
91 }
92 
93 // Notify AFL about persistent mode.
94 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
95 extern "C" int __afl_persistent_loop(unsigned int);
96 static volatile char suppress_warning2 = AFL_PERSISTENT[0];
97 
98 // Notify AFL about deferred forkserver.
99 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
100 extern "C" void  __afl_manual_init();
101 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
102 
103 // Input buffer.
104 static const size_t kMaxAflInputSize = 1 << 20;
105 static uint8_t AflInputBuf[kMaxAflInputSize];
106 
107 // Experimental feature to use afl_driver without AFL's deferred mode.
108 // Needs to run before __afl_auto_init.
109 __attribute__((constructor(0))) void __decide_deferred_forkserver(void) {
110   if (getenv("AFL_DRIVER_DONT_DEFER")) {
111     if (unsetenv("__AFL_DEFER_FORKSRV")) {
112       perror("Failed to unset __AFL_DEFER_FORKSRV");
113       abort();
114     }
115   }
116 }
117 
118 // If the user asks us to duplicate stderr, then do it.
119 static void maybe_duplicate_stderr() {
120   char* stderr_duplicate_filename =
121       getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
122 
123   if (!stderr_duplicate_filename)
124     return;
125 
126   FILE* stderr_duplicate_stream =
127       freopen(stderr_duplicate_filename, "a+", stderr);
128 
129   if (!stderr_duplicate_stream) {
130     fprintf(
131         stderr,
132         "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
133     abort();
134   }
135 }
136 
137 // Define LLVMFuzzerMutate to avoid link failures for targets that use it
138 // with libFuzzer's LLVMFuzzerCustomMutator.
139 extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
140   assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
141   return 0;
142 }
143 
144 // Execute any files provided as parameters.
145 int ExecuteFilesOnyByOne(int argc, char **argv) {
146   for (int i = 1; i < argc; i++) {
147     std::ifstream in(argv[i], std::ios::binary);
148     in.seekg(0, in.end);
149     size_t length = in.tellg();
150     in.seekg (0, in.beg);
151     std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
152     // Allocate exactly length bytes so that we reliably catch buffer overflows.
153     std::vector<char> bytes(length);
154     in.read(bytes.data(), bytes.size());
155     assert(in);
156     LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
157                            bytes.size());
158     std::cout << "Execution successful" << std::endl;
159   }
160   return 0;
161 }
162 
163 int main(int argc, char **argv) {
164   fprintf(stderr,
165       "======================= INFO =========================\n"
166       "This binary is built for AFL-fuzz.\n"
167       "To run the target function on individual input(s) execute this:\n"
168       "  %s < INPUT_FILE\n"
169       "or\n"
170       "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
171       "To fuzz with afl-fuzz execute this:\n"
172       "  afl-fuzz [afl-flags] %s [-N]\n"
173       "afl-fuzz will run N iterations before "
174       "re-spawning the process (default: 1000)\n"
175       "======================================================\n",
176           argv[0], argv[0], argv[0]);
177   if (LLVMFuzzerInitialize)
178     LLVMFuzzerInitialize(&argc, &argv);
179   // Do any other expensive one-time initialization here.
180 
181   maybe_duplicate_stderr();
182 
183   if (!getenv("AFL_DRIVER_DONT_DEFER"))
184     __afl_manual_init();
185 
186   int N = 1000;
187   if (argc == 2 && argv[1][0] == '-')
188       N = atoi(argv[1] + 1);
189   else if(argc == 2 && (N = atoi(argv[1])) > 0)
190       fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
191               argv[0], N);
192   else if (argc > 1)
193     return ExecuteFilesOnyByOne(argc, argv);
194 
195   assert(N > 0);
196 
197   // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
198   // on the first execution of LLVMFuzzerTestOneInput is ignored.
199   uint8_t dummy_input[1] = {0};
200   LLVMFuzzerTestOneInput(dummy_input, 1);
201 
202   int num_runs = 0;
203   while (__afl_persistent_loop(N)) {
204     ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
205     if (n_read > 0) {
206       // Copy AflInputBuf into a separate buffer to let asan find buffer
207       // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
208       uint8_t *copy = new uint8_t[n_read];
209       memcpy(copy, AflInputBuf, n_read);
210       num_runs++;
211       LLVMFuzzerTestOneInput(copy, n_read);
212       delete[] copy;
213     }
214   }
215   fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
216 }
217