blob: 1d1c16a0f9358aa5002c79646a0e2597a95d4201 [file] [log] [blame]
george.karpenkov29efa6d2017-08-21 23:25:50 +00001//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//===----------------------------------------------------------------------===//
8
9/* This file allows to fuzz libFuzzer-style target functions
10 (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
11
12Usage:
13################################################################################
14cat << EOF > test_fuzzer.cc
15#include <stddef.h>
16#include <stdint.h>
17extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
18 if (size > 0 && data[0] == 'H')
19 if (size > 1 && data[1] == 'I')
20 if (size > 2 && data[2] == '!')
21 __builtin_trap();
22 return 0;
23}
24EOF
25# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
26clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
27# Build afl-llvm-rt.o.c from the AFL distribution.
28clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
29# Build this file, link it with afl-llvm-rt.o.o and the target code.
30clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
31# Run AFL:
32rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
33$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
34################################################################################
35Environment Variables:
36There are a few environment variables that can be set to use features that
37afl-fuzz doesn't have.
38
39AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
40specified. If the file does not exist, it is created. This is useful for getting
41stack traces (when using ASAN for example) or original error messages on hard to
42reproduce bugs.
43
44AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
45statistics to the file specified. Currently these are peak_rss_mb
46(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
47the file does not exist it is created. If the file does exist then
48afl_driver assumes it was restarted by afl-fuzz and will try to read old
49statistics from the file. If that fails then the process will quit.
50
51*/
52#include <assert.h>
53#include <errno.h>
54#include <signal.h>
55#include <stdint.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <sys/resource.h>
60#include <sys/time.h>
61#include <unistd.h>
62
63#include <fstream>
64#include <iostream>
65#include <vector>
66
67// Platform detection. Copied from FuzzerInternal.h
68#ifdef __linux__
69#define LIBFUZZER_LINUX 1
70#define LIBFUZZER_APPLE 0
kamiledcfbba2017-08-30 22:44:11 +000071#define LIBFUZZER_NETBSD 0
kamil21423232018-01-12 17:15:05 +000072#define LIBFUZZER_FREEBSD 0
george.karpenkov29efa6d2017-08-21 23:25:50 +000073#elif __APPLE__
74#define LIBFUZZER_LINUX 0
75#define LIBFUZZER_APPLE 1
kamiledcfbba2017-08-30 22:44:11 +000076#define LIBFUZZER_NETBSD 0
kamil21423232018-01-12 17:15:05 +000077#define LIBFUZZER_FREEBSD 0
kamiledcfbba2017-08-30 22:44:11 +000078#elif __NetBSD__
79#define LIBFUZZER_LINUX 0
80#define LIBFUZZER_APPLE 0
81#define LIBFUZZER_NETBSD 1
kamil21423232018-01-12 17:15:05 +000082#define LIBFUZZER_FREEBSD 0
83#elif __FreeBSD__
84#define LIBFUZZER_LINUX 0
85#define LIBFUZZER_APPLE 0
86#define LIBFUZZER_NETBSD 0
87#define LIBFUZZER_FREEBSD 1
george.karpenkov29efa6d2017-08-21 23:25:50 +000088#else
89#error "Support for your platform has not been implemented"
90#endif
91
92// Used to avoid repeating error checking boilerplate. If cond is false, a
sylvestrea9eb8572018-03-13 14:35:10 +000093// fatal error has occurred in the program. In this event print error_message
george.karpenkov29efa6d2017-08-21 23:25:50 +000094// to stderr and abort(). Otherwise do nothing. Note that setting
95// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
96// to the file as well, if the error occurs after the duplication is performed.
97#define CHECK_ERROR(cond, error_message) \
98 if (!(cond)) { \
morehouseba2c1cd2017-12-13 22:02:44 +000099 fprintf(stderr, "%s\n", (error_message)); \
george.karpenkov29efa6d2017-08-21 23:25:50 +0000100 abort(); \
101 }
102
103// libFuzzer interface is thin, so we don't include any libFuzzer headers.
104extern "C" {
105int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
106__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
107}
108
109// Notify AFL about persistent mode.
110static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
111extern "C" int __afl_persistent_loop(unsigned int);
112static volatile char suppress_warning2 = AFL_PERSISTENT[0];
113
114// Notify AFL about deferred forkserver.
115static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
116extern "C" void __afl_manual_init();
117static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
118
119// Input buffer.
120static const size_t kMaxAflInputSize = 1 << 20;
121static uint8_t AflInputBuf[kMaxAflInputSize];
122
123// Variables we need for writing to the extra stats file.
124static FILE *extra_stats_file = NULL;
125static uint32_t previous_peak_rss = 0;
126static time_t slowest_unit_time_secs = 0;
127static const int kNumExtraStats = 2;
128static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n"
129 "slowest_unit_time_sec : %u\n";
130
131// Copied from FuzzerUtil.cpp.
132size_t GetPeakRSSMb() {
133 struct rusage usage;
134 if (getrusage(RUSAGE_SELF, &usage))
135 return 0;
kamil21423232018-01-12 17:15:05 +0000136 if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD) {
george.karpenkov29efa6d2017-08-21 23:25:50 +0000137 // ru_maxrss is in KiB
138 return usage.ru_maxrss >> 10;
139 } else if (LIBFUZZER_APPLE) {
140 // ru_maxrss is in bytes
141 return usage.ru_maxrss >> 20;
142 }
143 assert(0 && "GetPeakRSSMb() is not implemented for your platform");
144 return 0;
145}
146
147// Based on SetSigaction in FuzzerUtil.cpp
148static void SetSigaction(int signum,
149 void (*callback)(int, siginfo_t *, void *)) {
150 struct sigaction sigact;
151 memset(&sigact, 0, sizeof(sigact));
152 sigact.sa_sigaction = callback;
153 if (sigaction(signum, &sigact, 0)) {
154 fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
155 exit(1);
156 }
157}
158
159// Write extra stats to the file specified by the user. If none is specified
160// this function will never be called.
161static void write_extra_stats() {
162 uint32_t peak_rss = GetPeakRSSMb();
163
164 if (peak_rss < previous_peak_rss)
165 peak_rss = previous_peak_rss;
166
167 int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
168 peak_rss, slowest_unit_time_secs);
169
170 CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
171
172 CHECK_ERROR(fclose(extra_stats_file) == 0,
173 "Failed to close extra_stats_file");
174}
175
176// Call write_extra_stats before we exit.
177static void crash_handler(int, siginfo_t *, void *) {
178 // Make sure we don't try calling write_extra_stats again if we crashed while
179 // trying to call it.
180 static bool first_crash = true;
181 CHECK_ERROR(first_crash,
182 "Crashed in crash signal handler. This is a bug in the fuzzer.");
183
184 first_crash = false;
185 write_extra_stats();
186}
187
188// If the user has specified an extra_stats_file through the environment
189// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
190// to write stats to it on exit. If no file is specified, do nothing. Otherwise
191// install signal and exit handlers to write to the file when the process exits.
192// Then if the file doesn't exist create it and set extra stats to 0. But if it
193// does exist then read the initial values of the extra stats from the file
194// and check that the file is writable.
195static void maybe_initialize_extra_stats() {
196 // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
197 char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
198 if (!extra_stats_filename)
199 return;
200
201 // Open the file and find the previous peak_rss_mb value.
202 // This is necessary because the fuzzing process is restarted after N
203 // iterations are completed. So we may need to get this value from a previous
204 // process to be accurate.
205 extra_stats_file = fopen(extra_stats_filename, "r");
206
207 // If extra_stats_file already exists: read old stats from it.
208 if (extra_stats_file) {
209 int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
210 &previous_peak_rss, &slowest_unit_time_secs);
211
212 // Make sure we have read a real extra stats file and that we have used it
213 // to set slowest_unit_time_secs and previous_peak_rss.
214 CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
215
216 CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
217
218 // Now open the file for writing.
219 extra_stats_file = fopen(extra_stats_filename, "w");
220 CHECK_ERROR(extra_stats_file,
221 "Failed to open extra stats file for writing");
222 } else {
223 // Looks like this is the first time in a fuzzing job this is being called.
224 extra_stats_file = fopen(extra_stats_filename, "w+");
225 CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
226 }
227
228 // Make sure that crash_handler gets called on any kind of fatal error.
229 int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT,
230 SIGTERM};
231
232 const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
233
234 for (size_t idx = 0; idx < num_signals; idx++)
235 SetSigaction(crash_signals[idx], crash_handler);
236
237 // Make sure it gets called on other kinds of exits.
238 atexit(write_extra_stats);
239}
240
241// If the user asks us to duplicate stderr, then do it.
242static void maybe_duplicate_stderr() {
243 char* stderr_duplicate_filename =
244 getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
245
246 if (!stderr_duplicate_filename)
247 return;
248
249 FILE* stderr_duplicate_stream =
250 freopen(stderr_duplicate_filename, "a+", stderr);
251
252 if (!stderr_duplicate_stream) {
253 fprintf(
254 stderr,
255 "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
256 abort();
257 }
258}
259
260// Define LLVMFuzzerMutate to avoid link failures for targets that use it
261// with libFuzzer's LLVMFuzzerCustomMutator.
262extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
263 assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
264 return 0;
265}
266
267// Execute any files provided as parameters.
268int ExecuteFilesOnyByOne(int argc, char **argv) {
269 for (int i = 1; i < argc; i++) {
270 std::ifstream in(argv[i]);
271 in.seekg(0, in.end);
272 size_t length = in.tellg();
273 in.seekg (0, in.beg);
274 std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
275 // Allocate exactly length bytes so that we reliably catch buffer overflows.
276 std::vector<char> bytes(length);
277 in.read(bytes.data(), bytes.size());
278 assert(in);
279 LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
280 bytes.size());
sylvestrea9eb8572018-03-13 14:35:10 +0000281 std::cout << "Execution successful" << std::endl;
george.karpenkov29efa6d2017-08-21 23:25:50 +0000282 }
283 return 0;
284}
285
286int main(int argc, char **argv) {
287 fprintf(stderr,
288 "======================= INFO =========================\n"
289 "This binary is built for AFL-fuzz.\n"
290 "To run the target function on individual input(s) execute this:\n"
291 " %s < INPUT_FILE\n"
292 "or\n"
293 " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
294 "To fuzz with afl-fuzz execute this:\n"
295 " afl-fuzz [afl-flags] %s [-N]\n"
296 "afl-fuzz will run N iterations before "
297 "re-spawning the process (default: 1000)\n"
298 "======================================================\n",
299 argv[0], argv[0], argv[0]);
300 if (LLVMFuzzerInitialize)
301 LLVMFuzzerInitialize(&argc, &argv);
302 // Do any other expensive one-time initialization here.
303
304 maybe_duplicate_stderr();
305 maybe_initialize_extra_stats();
306
307 __afl_manual_init();
308
309 int N = 1000;
310 if (argc == 2 && argv[1][0] == '-')
311 N = atoi(argv[1] + 1);
312 else if(argc == 2 && (N = atoi(argv[1])) > 0)
313 fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
314 argv[0], N);
315 else if (argc > 1)
316 return ExecuteFilesOnyByOne(argc, argv);
317
318 assert(N > 0);
morehouseba2c1cd2017-12-13 22:02:44 +0000319
320 // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
321 // on the first execution of LLVMFuzzerTestOneInput is ignored.
322 uint8_t dummy_input[1] = {0};
323 LLVMFuzzerTestOneInput(dummy_input, 1);
324
george.karpenkov29efa6d2017-08-21 23:25:50 +0000325 time_t unit_time_secs;
326 int num_runs = 0;
327 while (__afl_persistent_loop(N)) {
328 ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
329 if (n_read > 0) {
330 // Copy AflInputBuf into a separate buffer to let asan find buffer
331 // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
332 uint8_t *copy = new uint8_t[n_read];
333 memcpy(copy, AflInputBuf, n_read);
334
335 struct timeval unit_start_time;
336 CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
337 "Calling gettimeofday failed");
338
339 num_runs++;
340 LLVMFuzzerTestOneInput(copy, n_read);
341
342 struct timeval unit_stop_time;
343 CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
344 "Calling gettimeofday failed");
345
346 // Update slowest_unit_time_secs if we see a new max.
347 unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
348 if (slowest_unit_time_secs < unit_time_secs)
349 slowest_unit_time_secs = unit_time_secs;
350
351 delete[] copy;
352 }
353 }
354 fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
355}