blob: 37f47b0c8ffe1b5664d880ac7deec339ba437483 [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################################################################################
34Environment Variables:
35There are a few environment variables that can be set to use features that
36afl-fuzz doesn't have.
37
38AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
39specified. If the file does not exist, it is created. This is useful for getting
40stack traces (when using ASAN for example) or original error messages on hard to
41reproduce bugs.
42
43AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
44statistics to the file specified. Currently these are peak_rss_mb
45(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
46the file does not exist it is created. If the file does exist then
47afl_driver assumes it was restarted by afl-fuzz and will try to read old
48statistics from the file. If that fails then the process will quit.
49
50*/
51#include <assert.h>
52#include <errno.h>
53#include <signal.h>
54#include <stdint.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <sys/resource.h>
59#include <sys/time.h>
60#include <unistd.h>
61
62#include <fstream>
63#include <iostream>
64#include <vector>
65
66// Platform detection. Copied from FuzzerInternal.h
67#ifdef __linux__
68#define LIBFUZZER_LINUX 1
69#define LIBFUZZER_APPLE 0
kamiledcfbba2017-08-30 22:44:11 +000070#define LIBFUZZER_NETBSD 0
kamil21423232018-01-12 17:15:05 +000071#define LIBFUZZER_FREEBSD 0
vitalybuka5f3206d2018-04-09 22:38:26 +000072#define LIBFUZZER_OPENBSD 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
vitalybuka5f3206d2018-04-09 22:38:26 +000078#define LIBFUZZER_OPENBSD 0
kamiledcfbba2017-08-30 22:44:11 +000079#elif __NetBSD__
80#define LIBFUZZER_LINUX 0
81#define LIBFUZZER_APPLE 0
82#define LIBFUZZER_NETBSD 1
kamil21423232018-01-12 17:15:05 +000083#define LIBFUZZER_FREEBSD 0
vitalybuka5f3206d2018-04-09 22:38:26 +000084#define LIBFUZZER_OPENBSD 0
kamil21423232018-01-12 17:15:05 +000085#elif __FreeBSD__
86#define LIBFUZZER_LINUX 0
87#define LIBFUZZER_APPLE 0
88#define LIBFUZZER_NETBSD 0
89#define LIBFUZZER_FREEBSD 1
vitalybuka5f3206d2018-04-09 22:38:26 +000090#define LIBFUZZER_OPENBSD 0
91#elif __OpenBSD__
92#define LIBFUZZER_LINUX 0
93#define LIBFUZZER_APPLE 0
94#define LIBFUZZER_NETBSD 0
95#define LIBFUZZER_FREEBSD 0
96#define LIBFUZZER_OPENBSD 1
george.karpenkov29efa6d2017-08-21 23:25:50 +000097#else
98#error "Support for your platform has not been implemented"
99#endif
100
101// Used to avoid repeating error checking boilerplate. If cond is false, a
sylvestrea9eb8572018-03-13 14:35:10 +0000102// fatal error has occurred in the program. In this event print error_message
george.karpenkov29efa6d2017-08-21 23:25:50 +0000103// to stderr and abort(). Otherwise do nothing. Note that setting
104// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
105// to the file as well, if the error occurs after the duplication is performed.
106#define CHECK_ERROR(cond, error_message) \
107 if (!(cond)) { \
morehouseba2c1cd2017-12-13 22:02:44 +0000108 fprintf(stderr, "%s\n", (error_message)); \
george.karpenkov29efa6d2017-08-21 23:25:50 +0000109 abort(); \
110 }
111
112// libFuzzer interface is thin, so we don't include any libFuzzer headers.
113extern "C" {
114int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
115__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
116}
117
118// Notify AFL about persistent mode.
119static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
120extern "C" int __afl_persistent_loop(unsigned int);
121static volatile char suppress_warning2 = AFL_PERSISTENT[0];
122
123// Notify AFL about deferred forkserver.
124static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
125extern "C" void __afl_manual_init();
126static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
127
128// Input buffer.
129static const size_t kMaxAflInputSize = 1 << 20;
130static uint8_t AflInputBuf[kMaxAflInputSize];
131
132// Variables we need for writing to the extra stats file.
133static FILE *extra_stats_file = NULL;
134static uint32_t previous_peak_rss = 0;
135static time_t slowest_unit_time_secs = 0;
136static const int kNumExtraStats = 2;
137static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n"
138 "slowest_unit_time_sec : %u\n";
139
morehousefda403c2018-04-23 21:36:21 +0000140// Experimental feature to use afl_driver without AFL's deferred mode.
141// Needs to run before __afl_auto_init.
142__attribute__((constructor(0))) void __decide_deferred_forkserver(void) {
143 if (getenv("AFL_DRIVER_DONT_DEFER")) {
144 if (unsetenv("__AFL_DEFER_FORKSRV")) {
145 perror("Failed to unset __AFL_DEFER_FORKSRV");
146 abort();
147 }
148 }
149}
150
george.karpenkov29efa6d2017-08-21 23:25:50 +0000151// Copied from FuzzerUtil.cpp.
152size_t GetPeakRSSMb() {
153 struct rusage usage;
154 if (getrusage(RUSAGE_SELF, &usage))
155 return 0;
vitalybuka5f3206d2018-04-09 22:38:26 +0000156 if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD ||
157 LIBFUZZER_OPENBSD) {
george.karpenkov29efa6d2017-08-21 23:25:50 +0000158 // ru_maxrss is in KiB
159 return usage.ru_maxrss >> 10;
160 } else if (LIBFUZZER_APPLE) {
161 // ru_maxrss is in bytes
162 return usage.ru_maxrss >> 20;
163 }
164 assert(0 && "GetPeakRSSMb() is not implemented for your platform");
165 return 0;
166}
167
168// Based on SetSigaction in FuzzerUtil.cpp
169static void SetSigaction(int signum,
170 void (*callback)(int, siginfo_t *, void *)) {
171 struct sigaction sigact;
172 memset(&sigact, 0, sizeof(sigact));
173 sigact.sa_sigaction = callback;
174 if (sigaction(signum, &sigact, 0)) {
175 fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
176 exit(1);
177 }
178}
179
180// Write extra stats to the file specified by the user. If none is specified
181// this function will never be called.
182static void write_extra_stats() {
183 uint32_t peak_rss = GetPeakRSSMb();
184
185 if (peak_rss < previous_peak_rss)
186 peak_rss = previous_peak_rss;
187
188 int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
189 peak_rss, slowest_unit_time_secs);
190
191 CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
192
193 CHECK_ERROR(fclose(extra_stats_file) == 0,
194 "Failed to close extra_stats_file");
195}
196
197// Call write_extra_stats before we exit.
198static void crash_handler(int, siginfo_t *, void *) {
199 // Make sure we don't try calling write_extra_stats again if we crashed while
200 // trying to call it.
201 static bool first_crash = true;
202 CHECK_ERROR(first_crash,
203 "Crashed in crash signal handler. This is a bug in the fuzzer.");
204
205 first_crash = false;
206 write_extra_stats();
207}
208
209// If the user has specified an extra_stats_file through the environment
210// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
211// to write stats to it on exit. If no file is specified, do nothing. Otherwise
212// install signal and exit handlers to write to the file when the process exits.
213// Then if the file doesn't exist create it and set extra stats to 0. But if it
214// does exist then read the initial values of the extra stats from the file
215// and check that the file is writable.
216static void maybe_initialize_extra_stats() {
217 // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
218 char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
219 if (!extra_stats_filename)
220 return;
221
222 // Open the file and find the previous peak_rss_mb value.
223 // This is necessary because the fuzzing process is restarted after N
224 // iterations are completed. So we may need to get this value from a previous
225 // process to be accurate.
226 extra_stats_file = fopen(extra_stats_filename, "r");
227
228 // If extra_stats_file already exists: read old stats from it.
229 if (extra_stats_file) {
230 int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
231 &previous_peak_rss, &slowest_unit_time_secs);
232
233 // Make sure we have read a real extra stats file and that we have used it
234 // to set slowest_unit_time_secs and previous_peak_rss.
235 CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
236
237 CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
238
239 // Now open the file for writing.
240 extra_stats_file = fopen(extra_stats_filename, "w");
241 CHECK_ERROR(extra_stats_file,
242 "Failed to open extra stats file for writing");
243 } else {
244 // Looks like this is the first time in a fuzzing job this is being called.
245 extra_stats_file = fopen(extra_stats_filename, "w+");
246 CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
247 }
248
249 // Make sure that crash_handler gets called on any kind of fatal error.
250 int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT,
251 SIGTERM};
252
253 const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
254
255 for (size_t idx = 0; idx < num_signals; idx++)
256 SetSigaction(crash_signals[idx], crash_handler);
257
258 // Make sure it gets called on other kinds of exits.
259 atexit(write_extra_stats);
260}
261
262// If the user asks us to duplicate stderr, then do it.
263static void maybe_duplicate_stderr() {
264 char* stderr_duplicate_filename =
265 getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
266
267 if (!stderr_duplicate_filename)
268 return;
269
270 FILE* stderr_duplicate_stream =
271 freopen(stderr_duplicate_filename, "a+", stderr);
272
273 if (!stderr_duplicate_stream) {
274 fprintf(
275 stderr,
276 "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
277 abort();
278 }
279}
280
281// Define LLVMFuzzerMutate to avoid link failures for targets that use it
282// with libFuzzer's LLVMFuzzerCustomMutator.
283extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
284 assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
285 return 0;
286}
287
288// Execute any files provided as parameters.
289int ExecuteFilesOnyByOne(int argc, char **argv) {
290 for (int i = 1; i < argc; i++) {
metzman2a530982018-11-06 23:25:25 +0000291 std::ifstream in(argv[i], std::ios::binary);
george.karpenkov29efa6d2017-08-21 23:25:50 +0000292 in.seekg(0, in.end);
293 size_t length = in.tellg();
294 in.seekg (0, in.beg);
295 std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
296 // Allocate exactly length bytes so that we reliably catch buffer overflows.
297 std::vector<char> bytes(length);
298 in.read(bytes.data(), bytes.size());
299 assert(in);
300 LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
301 bytes.size());
sylvestrea9eb8572018-03-13 14:35:10 +0000302 std::cout << "Execution successful" << std::endl;
george.karpenkov29efa6d2017-08-21 23:25:50 +0000303 }
304 return 0;
305}
306
307int main(int argc, char **argv) {
308 fprintf(stderr,
309 "======================= INFO =========================\n"
310 "This binary is built for AFL-fuzz.\n"
311 "To run the target function on individual input(s) execute this:\n"
312 " %s < INPUT_FILE\n"
313 "or\n"
314 " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
315 "To fuzz with afl-fuzz execute this:\n"
316 " afl-fuzz [afl-flags] %s [-N]\n"
317 "afl-fuzz will run N iterations before "
318 "re-spawning the process (default: 1000)\n"
319 "======================================================\n",
320 argv[0], argv[0], argv[0]);
321 if (LLVMFuzzerInitialize)
322 LLVMFuzzerInitialize(&argc, &argv);
323 // Do any other expensive one-time initialization here.
324
325 maybe_duplicate_stderr();
326 maybe_initialize_extra_stats();
327
morehousefda403c2018-04-23 21:36:21 +0000328 if (!getenv("AFL_DRIVER_DONT_DEFER"))
329 __afl_manual_init();
george.karpenkov29efa6d2017-08-21 23:25:50 +0000330
331 int N = 1000;
332 if (argc == 2 && argv[1][0] == '-')
morehouse4e2102e2018-07-10 19:58:42 +0000333 N = atoi(argv[1] + 1);
334 else if(argc == 2 && (N = atoi(argv[1])) > 0)
335 fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
336 argv[0], N);
337 else if (argc > 1)
george.karpenkov29efa6d2017-08-21 23:25:50 +0000338 return ExecuteFilesOnyByOne(argc, argv);
339
340 assert(N > 0);
morehouseba2c1cd2017-12-13 22:02:44 +0000341
342 // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
343 // on the first execution of LLVMFuzzerTestOneInput is ignored.
344 uint8_t dummy_input[1] = {0};
345 LLVMFuzzerTestOneInput(dummy_input, 1);
346
george.karpenkov29efa6d2017-08-21 23:25:50 +0000347 time_t unit_time_secs;
348 int num_runs = 0;
349 while (__afl_persistent_loop(N)) {
350 ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
351 if (n_read > 0) {
352 // Copy AflInputBuf into a separate buffer to let asan find buffer
353 // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
354 uint8_t *copy = new uint8_t[n_read];
355 memcpy(copy, AflInputBuf, n_read);
356
357 struct timeval unit_start_time;
358 CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
359 "Calling gettimeofday failed");
360
361 num_runs++;
362 LLVMFuzzerTestOneInput(copy, n_read);
363
364 struct timeval unit_stop_time;
365 CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
366 "Calling gettimeofday failed");
367
368 // Update slowest_unit_time_secs if we see a new max.
369 unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
370 if (slowest_unit_time_secs < unit_time_secs)
371 slowest_unit_time_secs = unit_time_secs;
372
373 delete[] copy;
374 }
375 }
376 fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
377}