blob: f21dfc58fede4a64686f34115e276b61467be37a [file] [log] [blame]
George Karpenkov10ab2ac2017-08-21 23:25:50 +00001//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
George Karpenkov10ab2ac2017-08-21 23:25:50 +00006//===----------------------------------------------------------------------===//
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################################################################################
Jonathan Metzman139e2162019-04-18 18:49:11 +000034AFL_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.
George Karpenkov10ab2ac2017-08-21 23:25:50 +000042
43*/
44#include <assert.h>
45#include <errno.h>
George Karpenkov10ab2ac2017-08-21 23:25:50 +000046#include <stdint.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
George Karpenkov10ab2ac2017-08-21 23:25:50 +000050#include <unistd.h>
51
52#include <fstream>
53#include <iostream>
54#include <vector>
55
56// Platform detection. Copied from FuzzerInternal.h
57#ifdef __linux__
58#define LIBFUZZER_LINUX 1
59#define LIBFUZZER_APPLE 0
Kamil Rytarowski8da27222017-08-30 22:44:11 +000060#define LIBFUZZER_NETBSD 0
Kamil Rytarowskie81e9442018-01-12 17:15:05 +000061#define LIBFUZZER_FREEBSD 0
Vitaly Buka98020892018-04-09 22:38:26 +000062#define LIBFUZZER_OPENBSD 0
George Karpenkov10ab2ac2017-08-21 23:25:50 +000063#elif __APPLE__
64#define LIBFUZZER_LINUX 0
65#define LIBFUZZER_APPLE 1
Kamil Rytarowski8da27222017-08-30 22:44:11 +000066#define LIBFUZZER_NETBSD 0
Kamil Rytarowskie81e9442018-01-12 17:15:05 +000067#define LIBFUZZER_FREEBSD 0
Vitaly Buka98020892018-04-09 22:38:26 +000068#define LIBFUZZER_OPENBSD 0
Kamil Rytarowski8da27222017-08-30 22:44:11 +000069#elif __NetBSD__
70#define LIBFUZZER_LINUX 0
71#define LIBFUZZER_APPLE 0
72#define LIBFUZZER_NETBSD 1
Kamil Rytarowskie81e9442018-01-12 17:15:05 +000073#define LIBFUZZER_FREEBSD 0
Vitaly Buka98020892018-04-09 22:38:26 +000074#define LIBFUZZER_OPENBSD 0
Kamil Rytarowskie81e9442018-01-12 17:15:05 +000075#elif __FreeBSD__
76#define LIBFUZZER_LINUX 0
77#define LIBFUZZER_APPLE 0
78#define LIBFUZZER_NETBSD 0
79#define LIBFUZZER_FREEBSD 1
Vitaly Buka98020892018-04-09 22:38:26 +000080#define LIBFUZZER_OPENBSD 0
81#elif __OpenBSD__
82#define LIBFUZZER_LINUX 0
83#define LIBFUZZER_APPLE 0
84#define LIBFUZZER_NETBSD 0
85#define LIBFUZZER_FREEBSD 0
86#define LIBFUZZER_OPENBSD 1
George Karpenkov10ab2ac2017-08-21 23:25:50 +000087#else
88#error "Support for your platform has not been implemented"
89#endif
90
George Karpenkov10ab2ac2017-08-21 23:25:50 +000091// libFuzzer interface is thin, so we don't include any libFuzzer headers.
92extern "C" {
93int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
94__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
95}
96
97// Notify AFL about persistent mode.
98static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
99extern "C" int __afl_persistent_loop(unsigned int);
100static volatile char suppress_warning2 = AFL_PERSISTENT[0];
101
102// Notify AFL about deferred forkserver.
103static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
Jonathan Metzman139e2162019-04-18 18:49:11 +0000104extern "C" void __afl_manual_init();
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000105static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
106
107// Input buffer.
108static const size_t kMaxAflInputSize = 1 << 20;
109static uint8_t AflInputBuf[kMaxAflInputSize];
110
Jonathan Metzman139e2162019-04-18 18:49:11 +0000111// Use this optionally defined function to output sanitizer messages even if
112// user asks to close stderr.
113__attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *);
114
115// Keep track of where stderr content is being written to, so that
116// dup_and_close_stderr can use the correct one.
117static FILE *output_file = stderr;
118
Matt Morehousef66221c2018-04-23 21:36:21 +0000119// Experimental feature to use afl_driver without AFL's deferred mode.
120// Needs to run before __afl_auto_init.
Jonathan Metzman139e2162019-04-18 18:49:11 +0000121__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
Matt Morehousef66221c2018-04-23 21:36:21 +0000122 if (getenv("AFL_DRIVER_DONT_DEFER")) {
123 if (unsetenv("__AFL_DEFER_FORKSRV")) {
124 perror("Failed to unset __AFL_DEFER_FORKSRV");
125 abort();
126 }
127 }
128}
129
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000130// If the user asks us to duplicate stderr, then do it.
131static void maybe_duplicate_stderr() {
Jonathan Metzman139e2162019-04-18 18:49:11 +0000132 char *stderr_duplicate_filename =
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000133 getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
134
135 if (!stderr_duplicate_filename)
136 return;
137
Jonathan Metzman139e2162019-04-18 18:49:11 +0000138 FILE *stderr_duplicate_stream =
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000139 freopen(stderr_duplicate_filename, "a+", stderr);
140
141 if (!stderr_duplicate_stream) {
142 fprintf(
143 stderr,
144 "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
145 abort();
146 }
Jonathan Metzman139e2162019-04-18 18:49:11 +0000147 output_file = stderr_duplicate_stream;
148}
149
150// Most of these I/O functions were inspired by/copied from libFuzzer's code.
151static void discard_output(int fd) {
152 FILE *temp = fopen("/dev/null", "w");
153 if (!temp)
154 abort();
155 dup2(fileno(temp), fd);
156 fclose(temp);
157}
158
159static void close_stdout() { discard_output(STDOUT_FILENO); }
160
161// Prevent the targeted code from writing to "stderr" but allow sanitizers and
162// this driver to do so.
163static void dup_and_close_stderr() {
164 int output_fileno = fileno(output_file);
165 int output_fd = dup(output_fileno);
166 if (output_fd <= 0)
167 abort();
168 FILE *new_output_file = fdopen(output_fd, "w");
169 if (!new_output_file)
170 abort();
171 if (!__sanitizer_set_report_fd)
172 return;
173 __sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));
174 discard_output(output_fileno);
175}
176
177static void Printf(const char *Fmt, ...) {
178 va_list ap;
179 va_start(ap, Fmt);
180 vfprintf(output_file, Fmt, ap);
181 va_end(ap);
182 fflush(output_file);
183}
184
185// Close stdout and/or stderr if user asks for it.
186static void maybe_close_fd_mask() {
187 char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
188 if (!fd_mask_str)
189 return;
190 int fd_mask = atoi(fd_mask_str);
191 if (fd_mask & 2)
192 dup_and_close_stderr();
193 if (fd_mask & 1)
194 close_stdout();
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000195}
196
197// Define LLVMFuzzerMutate to avoid link failures for targets that use it
198// with libFuzzer's LLVMFuzzerCustomMutator.
199extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
200 assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
201 return 0;
202}
203
204// Execute any files provided as parameters.
Jonathan Metzman139e2162019-04-18 18:49:11 +0000205static int ExecuteFilesOnyByOne(int argc, char **argv) {
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000206 for (int i = 1; i < argc; i++) {
Jonathan Metzman39b6ba92018-11-06 23:25:25 +0000207 std::ifstream in(argv[i], std::ios::binary);
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000208 in.seekg(0, in.end);
209 size_t length = in.tellg();
210 in.seekg (0, in.beg);
211 std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
212 // Allocate exactly length bytes so that we reliably catch buffer overflows.
213 std::vector<char> bytes(length);
214 in.read(bytes.data(), bytes.size());
215 assert(in);
216 LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
217 bytes.size());
Sylvestre Ledrud9a8b6a2018-03-13 14:35:10 +0000218 std::cout << "Execution successful" << std::endl;
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000219 }
220 return 0;
221}
222
223int main(int argc, char **argv) {
Jonathan Metzman139e2162019-04-18 18:49:11 +0000224 Printf(
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000225 "======================= INFO =========================\n"
226 "This binary is built for AFL-fuzz.\n"
227 "To run the target function on individual input(s) execute this:\n"
228 " %s < INPUT_FILE\n"
229 "or\n"
230 " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
231 "To fuzz with afl-fuzz execute this:\n"
232 " afl-fuzz [afl-flags] %s [-N]\n"
233 "afl-fuzz will run N iterations before "
234 "re-spawning the process (default: 1000)\n"
235 "======================================================\n",
236 argv[0], argv[0], argv[0]);
Jonathan Metzman139e2162019-04-18 18:49:11 +0000237
238 maybe_duplicate_stderr();
239 maybe_close_fd_mask();
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000240 if (LLVMFuzzerInitialize)
241 LLVMFuzzerInitialize(&argc, &argv);
242 // Do any other expensive one-time initialization here.
243
Matt Morehousef66221c2018-04-23 21:36:21 +0000244 if (!getenv("AFL_DRIVER_DONT_DEFER"))
245 __afl_manual_init();
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000246
247 int N = 1000;
248 if (argc == 2 && argv[1][0] == '-')
Matt Morehouse0e904e82018-07-10 19:58:42 +0000249 N = atoi(argv[1] + 1);
250 else if(argc == 2 && (N = atoi(argv[1])) > 0)
Jonathan Metzman139e2162019-04-18 18:49:11 +0000251 Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
Matt Morehouse0e904e82018-07-10 19:58:42 +0000252 else if (argc > 1)
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000253 return ExecuteFilesOnyByOne(argc, argv);
254
255 assert(N > 0);
Matt Morehouse6e294952017-12-13 22:02:44 +0000256
257 // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
258 // on the first execution of LLVMFuzzerTestOneInput is ignored.
259 uint8_t dummy_input[1] = {0};
260 LLVMFuzzerTestOneInput(dummy_input, 1);
261
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000262 int num_runs = 0;
263 while (__afl_persistent_loop(N)) {
264 ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
265 if (n_read > 0) {
266 // Copy AflInputBuf into a separate buffer to let asan find buffer
267 // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
268 uint8_t *copy = new uint8_t[n_read];
269 memcpy(copy, AflInputBuf, n_read);
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000270 num_runs++;
271 LLVMFuzzerTestOneInput(copy, n_read);
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000272 delete[] copy;
273 }
274 }
Jonathan Metzman139e2162019-04-18 18:49:11 +0000275 Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
George Karpenkov10ab2ac2017-08-21 23:25:50 +0000276}