1 //===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //===----------------------------------------------------------------------===//
9 /* This file allows to fuzz libFuzzer-style target functions
10 (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
13 ################################################################################
14 cat << EOF > test_fuzzer.cc
17 extern "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] == '!')
25 # Build your target with -fsanitize-coverage=trace-pc using fresh clang.
26 clang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c
27 # Build afl-llvm-rt.o.c from the AFL distribution.
28 clang -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.
30 clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
32 rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
33 $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
34 ################################################################################
35 Environment Variables:
36 There are a few environment variables that can be set to use features that
37 afl-fuzz doesn't have.
39 AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
40 specified. If the file does not exist, it is created. This is useful for getting
41 stack traces (when using ASAN for example) or original error messages on hard to
44 AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
45 statistics 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
47 the file does not exist it is created. If the file does exist then
48 afl_driver assumes it was restarted by afl-fuzz and will try to read old
49 statistics from the file. If that fails then the process will quit.
59 #include <sys/resource.h>
67 // Platform detection. Copied from FuzzerInternal.h
69 #define LIBFUZZER_LINUX 1
70 #define LIBFUZZER_APPLE 0
72 #define LIBFUZZER_LINUX 0
73 #define LIBFUZZER_APPLE 1
75 #error "Support for your platform has not been implemented"
78 // Used to avoid repeating error checking boilerplate. If cond is false, a
79 // fatal error has occured in the program. In this event print error_message
80 // to stderr and abort(). Otherwise do nothing. Note that setting
81 // AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
82 // to the file as well, if the error occurs after the duplication is performed.
83 #define CHECK_ERROR(cond, error_message) \
85 fprintf(stderr, (error_message)); \
89 // libFuzzer interface is thin, so we don't include any libFuzzer headers.
91 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
92 __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
95 // Notify AFL about persistent mode.
96 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
97 extern "C" int __afl_persistent_loop(unsigned int);
98 static volatile char suppress_warning2 = AFL_PERSISTENT[0];
100 // Notify AFL about deferred forkserver.
101 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
102 extern "C" void __afl_manual_init();
103 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
106 static const size_t kMaxAflInputSize = 1 << 20;
107 static uint8_t AflInputBuf[kMaxAflInputSize];
109 // Variables we need for writing to the extra stats file.
110 static FILE *extra_stats_file = NULL;
111 static uint32_t previous_peak_rss = 0;
112 static time_t slowest_unit_time_secs = 0;
113 static const int kNumExtraStats = 2;
114 static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n"
115 "slowest_unit_time_sec : %u\n";
117 // Copied from FuzzerUtil.cpp.
118 size_t GetPeakRSSMb() {
120 if (getrusage(RUSAGE_SELF, &usage))
122 if (LIBFUZZER_LINUX) {
123 // ru_maxrss is in KiB
124 return usage.ru_maxrss >> 10;
125 } else if (LIBFUZZER_APPLE) {
126 // ru_maxrss is in bytes
127 return usage.ru_maxrss >> 20;
129 assert(0 && "GetPeakRSSMb() is not implemented for your platform");
133 // Based on SetSigaction in FuzzerUtil.cpp
134 static void SetSigaction(int signum,
135 void (*callback)(int, siginfo_t *, void *)) {
136 struct sigaction sigact;
137 memset(&sigact, 0, sizeof(sigact));
138 sigact.sa_sigaction = callback;
139 if (sigaction(signum, &sigact, 0)) {
140 fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
145 // Write extra stats to the file specified by the user. If none is specified
146 // this function will never be called.
147 static void write_extra_stats() {
148 uint32_t peak_rss = GetPeakRSSMb();
150 if (peak_rss < previous_peak_rss)
151 peak_rss = previous_peak_rss;
153 int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
154 peak_rss, slowest_unit_time_secs);
156 CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
158 CHECK_ERROR(fclose(extra_stats_file) == 0,
159 "Failed to close extra_stats_file");
162 // Call write_extra_stats before we exit.
163 static void crash_handler(int, siginfo_t *, void *) {
164 // Make sure we don't try calling write_extra_stats again if we crashed while
165 // trying to call it.
166 static bool first_crash = true;
167 CHECK_ERROR(first_crash,
168 "Crashed in crash signal handler. This is a bug in the fuzzer.");
174 // If the user has specified an extra_stats_file through the environment
175 // variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
176 // to write stats to it on exit. If no file is specified, do nothing. Otherwise
177 // install signal and exit handlers to write to the file when the process exits.
178 // Then if the file doesn't exist create it and set extra stats to 0. But if it
179 // does exist then read the initial values of the extra stats from the file
180 // and check that the file is writable.
181 static void maybe_initialize_extra_stats() {
182 // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
183 char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
184 if (!extra_stats_filename)
187 // Open the file and find the previous peak_rss_mb value.
188 // This is necessary because the fuzzing process is restarted after N
189 // iterations are completed. So we may need to get this value from a previous
190 // process to be accurate.
191 extra_stats_file = fopen(extra_stats_filename, "r");
193 // If extra_stats_file already exists: read old stats from it.
194 if (extra_stats_file) {
195 int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
196 &previous_peak_rss, &slowest_unit_time_secs);
198 // Make sure we have read a real extra stats file and that we have used it
199 // to set slowest_unit_time_secs and previous_peak_rss.
200 CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
202 CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
204 // Now open the file for writing.
205 extra_stats_file = fopen(extra_stats_filename, "w");
206 CHECK_ERROR(extra_stats_file,
207 "Failed to open extra stats file for writing");
209 // Looks like this is the first time in a fuzzing job this is being called.
210 extra_stats_file = fopen(extra_stats_filename, "w+");
211 CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
214 // Make sure that crash_handler gets called on any kind of fatal error.
215 int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT,
218 const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
220 for (size_t idx = 0; idx < num_signals; idx++)
221 SetSigaction(crash_signals[idx], crash_handler);
223 // Make sure it gets called on other kinds of exits.
224 atexit(write_extra_stats);
227 // If the user asks us to duplicate stderr, then do it.
228 static void maybe_duplicate_stderr() {
229 char* stderr_duplicate_filename =
230 getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
232 if (!stderr_duplicate_filename)
235 FILE* stderr_duplicate_stream =
236 freopen(stderr_duplicate_filename, "a+", stderr);
238 if (!stderr_duplicate_stream) {
241 "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
246 // Define LLVMFuzzerMutate to avoid link failures for targets that use it
247 // with libFuzzer's LLVMFuzzerCustomMutator.
248 extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
249 assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
253 // Execute any files provided as parameters.
254 int ExecuteFilesOnyByOne(int argc, char **argv) {
255 for (int i = 1; i < argc; i++) {
256 std::ifstream in(argv[i]);
258 size_t length = in.tellg();
259 in.seekg (0, in.beg);
260 std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
261 // Allocate exactly length bytes so that we reliably catch buffer overflows.
262 std::vector<char> bytes(length);
263 in.read(bytes.data(), bytes.size());
265 LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
267 std::cout << "Execution successfull" << std::endl;
272 int main(int argc, char **argv) {
274 "======================= INFO =========================\n"
275 "This binary is built for AFL-fuzz.\n"
276 "To run the target function on individual input(s) execute this:\n"
279 " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
280 "To fuzz with afl-fuzz execute this:\n"
281 " afl-fuzz [afl-flags] %s [-N]\n"
282 "afl-fuzz will run N iterations before "
283 "re-spawning the process (default: 1000)\n"
284 "======================================================\n",
285 argv[0], argv[0], argv[0]);
286 if (LLVMFuzzerInitialize)
287 LLVMFuzzerInitialize(&argc, &argv);
288 // Do any other expensive one-time initialization here.
290 maybe_duplicate_stderr();
291 maybe_initialize_extra_stats();
296 if (argc == 2 && argv[1][0] == '-')
297 N = atoi(argv[1] + 1);
298 else if(argc == 2 && (N = atoi(argv[1])) > 0)
299 fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
302 return ExecuteFilesOnyByOne(argc, argv);
305 time_t unit_time_secs;
307 while (__afl_persistent_loop(N)) {
308 ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
310 // Copy AflInputBuf into a separate buffer to let asan find buffer
311 // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
312 uint8_t *copy = new uint8_t[n_read];
313 memcpy(copy, AflInputBuf, n_read);
315 struct timeval unit_start_time;
316 CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
317 "Calling gettimeofday failed");
320 LLVMFuzzerTestOneInput(copy, n_read);
322 struct timeval unit_stop_time;
323 CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
324 "Calling gettimeofday failed");
326 // Update slowest_unit_time_secs if we see a new max.
327 unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
328 if (slowest_unit_time_secs < unit_time_secs)
329 slowest_unit_time_secs = unit_time_secs;
334 fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);