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
11Usage:
12################################################################################
13cat << EOF > test_fuzzer.cc
14#include <stddef.h>
15#include <stdint.h>
16extern "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}
23EOF
24# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
25clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
26# Build afl-llvm-rt.o.c from the AFL distribution.
27clang -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.
29clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
30# Run AFL:
31rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
32$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
33################################################################################
34AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
35specified. If the file does not exist, it is created. This is useful for getting
36stack traces (when using ASAN for example) or original error messages on hard
37to reproduce bugs. Note that any content written to stderr will be written to
38this file instead of stderr's usual location.
39
40AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option.
41If 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.
83extern "C" {
84int 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.
89static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
90extern "C" int __afl_persistent_loop(unsigned int);
91static volatile char suppress_warning2 = AFL_PERSISTENT[0];
92
93// Notify AFL about deferred forkserver.
94static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
95extern "C" void __afl_manual_init();
96static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
97
98// Input buffer.
99static const size_t kMaxAflInputSize = 1 << 20;
100static uint8_t AflInputBuf[kMaxAflInputSize];
101
102// Use this optionally defined function to output sanitizer messages even if
103// user asks to close stderr.
104extern "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.
108static 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.
112__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
113 if (getenv(name: "AFL_DRIVER_DONT_DEFER")) {
114 if (unsetenv(name: "__AFL_DEFER_FORKSRV")) {
115 perror(s: "Failed to unset __AFL_DEFER_FORKSRV");
116 abort();
117 }
118 }
119}
120
121// If the user asks us to duplicate stderr, then do it.
122static void maybe_duplicate_stderr() {
123 char *stderr_duplicate_filename =
124 getenv(name: "AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
125
126 if (!stderr_duplicate_filename)
127 return;
128
129 FILE *stderr_duplicate_stream =
130 freopen(filename: stderr_duplicate_filename, modes: "a+", stderr);
131
132 if (!stderr_duplicate_stream) {
133 fprintf(
134 stderr,
135 format: "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.
142static void discard_output(int fd) {
143 FILE *temp = fopen(filename: "/dev/null", modes: "w");
144 if (!temp)
145 abort();
146 dup2(fd: fileno(stream: temp), fd2: fd);
147 fclose(stream: temp);
148}
149
150static 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.
154static void dup_and_close_stderr() {
155 int output_fileno = fileno(stream: output_file);
156 int output_fd = dup(fd: output_fileno);
157 if (output_fd <= 0)
158 abort();
159 FILE *new_output_file = fdopen(fd: output_fd, modes: "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(fd: output_fileno);
166}
167
168static void Printf(const char *Fmt, ...) {
169 va_list ap;
170 va_start(ap, Fmt);
171 vfprintf(s: output_file, format: Fmt, arg: ap);
172 va_end(ap);
173 fflush(stream: output_file);
174}
175
176// Close stdout and/or stderr if user asks for it.
177static void maybe_close_fd_mask() {
178 char *fd_mask_str = getenv(name: "AFL_DRIVER_CLOSE_FD_MASK");
179 if (!fd_mask_str)
180 return;
181 int fd_mask = atoi(nptr: 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.
190extern "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.
196static 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(s: bytes.data(), n: bytes.size());
206 assert(in);
207 LLVMFuzzerTestOneInput(Data: reinterpret_cast<const uint8_t *>(bytes.data()),
208 Size: bytes.size());
209 std::cout << "Execution successful" << std::endl;
210 }
211 return 0;
212}
213
214int main(int argc, char **argv) {
215 Printf(
216 Fmt: "======================= 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: &argc, argv: &argv);
233 // Do any other expensive one-time initialization here.
234
235 if (!getenv(name: "AFL_DRIVER_DONT_DEFER"))
236 __afl_manual_init();
237
238 int N = 1000;
239 if (argc == 2 && argv[1][0] == '-')
240 N = atoi(nptr: argv[1] + 1);
241 else if(argc == 2 && (N = atoi(nptr: argv[1])) > 0)
242 Printf(Fmt: "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(Data: dummy_input, Size: 1);
252
253 int num_runs = 0;
254 while (__afl_persistent_loop(N)) {
255 ssize_t n_read = read(fd: 0, buf: AflInputBuf, nbytes: 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(dest: copy, src: AflInputBuf, n: n_read);
261 num_runs++;
262 LLVMFuzzerTestOneInput(Data: copy, Size: n_read);
263 delete[] copy;
264 }
265 }
266 Printf(Fmt: "%s: successfully executed %d input(s)\n", argv[0], num_runs);
267}
268

source code of compiler-rt/lib/fuzzer/afl/afl_driver.cpp