blob: 18101aa4d9b0e548ed036bef6d733c71bab768e7 [file] [log] [blame]
george.karpenkov29efa6d2017-08-21 23:25:50 +00001//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
2//
chandlerc40284492019-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.karpenkov29efa6d2017-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################################################################################
metzmanea14bf42019-01-28 17:15:49 +000034AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this environment variable
35*appends* stderr to the file specified. If the file does not exist, it is
36created. This is useful for getting stack traces (when using ASAN for example)
37or original error messages on hard to reproduce bugs.
george.karpenkov29efa6d2017-08-21 23:25:50 +000038
39*/
40#include <assert.h>
41#include <errno.h>
george.karpenkov29efa6d2017-08-21 23:25:50 +000042#include <stdint.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
george.karpenkov29efa6d2017-08-21 23:25:50 +000046#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
kamiledcfbba2017-08-30 22:44:11 +000056#define LIBFUZZER_NETBSD 0
kamil21423232018-01-12 17:15:05 +000057#define LIBFUZZER_FREEBSD 0
vitalybuka5f3206d2018-04-09 22:38:26 +000058#define LIBFUZZER_OPENBSD 0
george.karpenkov29efa6d2017-08-21 23:25:50 +000059#elif __APPLE__
60#define LIBFUZZER_LINUX 0
61#define LIBFUZZER_APPLE 1
kamiledcfbba2017-08-30 22:44:11 +000062#define LIBFUZZER_NETBSD 0
kamil21423232018-01-12 17:15:05 +000063#define LIBFUZZER_FREEBSD 0
vitalybuka5f3206d2018-04-09 22:38:26 +000064#define LIBFUZZER_OPENBSD 0
kamiledcfbba2017-08-30 22:44:11 +000065#elif __NetBSD__
66#define LIBFUZZER_LINUX 0
67#define LIBFUZZER_APPLE 0
68#define LIBFUZZER_NETBSD 1
kamil21423232018-01-12 17:15:05 +000069#define LIBFUZZER_FREEBSD 0
vitalybuka5f3206d2018-04-09 22:38:26 +000070#define LIBFUZZER_OPENBSD 0
kamil21423232018-01-12 17:15:05 +000071#elif __FreeBSD__
72#define LIBFUZZER_LINUX 0
73#define LIBFUZZER_APPLE 0
74#define LIBFUZZER_NETBSD 0
75#define LIBFUZZER_FREEBSD 1
vitalybuka5f3206d2018-04-09 22:38:26 +000076#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
george.karpenkov29efa6d2017-08-21 23:25:50 +000083#else
84#error "Support for your platform has not been implemented"
85#endif
86
george.karpenkov29efa6d2017-08-21 23:25:50 +000087// libFuzzer interface is thin, so we don't include any libFuzzer headers.
88extern "C" {
89int 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.
94static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
95extern "C" int __afl_persistent_loop(unsigned int);
96static volatile char suppress_warning2 = AFL_PERSISTENT[0];
97
98// Notify AFL about deferred forkserver.
99static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
100extern "C" void __afl_manual_init();
101static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
102
103// Input buffer.
104static const size_t kMaxAflInputSize = 1 << 20;
105static uint8_t AflInputBuf[kMaxAflInputSize];
106
morehousefda403c2018-04-23 21:36:21 +0000107// 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
george.karpenkov29efa6d2017-08-21 23:25:50 +0000118// If the user asks us to duplicate stderr, then do it.
119static 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.
139extern "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.
145int ExecuteFilesOnyByOne(int argc, char **argv) {
146 for (int i = 1; i < argc; i++) {
metzman2a530982018-11-06 23:25:25 +0000147 std::ifstream in(argv[i], std::ios::binary);
george.karpenkov29efa6d2017-08-21 23:25:50 +0000148 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());
sylvestrea9eb8572018-03-13 14:35:10 +0000158 std::cout << "Execution successful" << std::endl;
george.karpenkov29efa6d2017-08-21 23:25:50 +0000159 }
160 return 0;
161}
162
163int 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();
george.karpenkov29efa6d2017-08-21 23:25:50 +0000182
morehousefda403c2018-04-23 21:36:21 +0000183 if (!getenv("AFL_DRIVER_DONT_DEFER"))
184 __afl_manual_init();
george.karpenkov29efa6d2017-08-21 23:25:50 +0000185
186 int N = 1000;
187 if (argc == 2 && argv[1][0] == '-')
morehouse4e2102e2018-07-10 19:58:42 +0000188 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)
george.karpenkov29efa6d2017-08-21 23:25:50 +0000193 return ExecuteFilesOnyByOne(argc, argv);
194
195 assert(N > 0);
morehouseba2c1cd2017-12-13 22:02:44 +0000196
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
george.karpenkov29efa6d2017-08-21 23:25:50 +0000202 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);
george.karpenkov29efa6d2017-08-21 23:25:50 +0000210 num_runs++;
211 LLVMFuzzerTestOneInput(copy, n_read);
george.karpenkov29efa6d2017-08-21 23:25:50 +0000212 delete[] copy;
213 }
214 }
215 fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
216}