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("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.
122static 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.
142static 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
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(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
168static 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.
177static 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.
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(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
214int 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