1 //===- 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 12 Usage: 13 ################################################################################ 14 cat << EOF > test_fuzzer.cc 15 #include <stddef.h> 16 #include <stdint.h> 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] == '!') 21 __builtin_trap(); 22 return 0; 23 } 24 EOF 25 # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. 26 clang -g -fsanitize-coverage=trace-pc-guard 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 31 # Run AFL: 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. 38 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 42 reproduce bugs. 43 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. 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 71 #define LIBFUZZER_NETBSD 0 72 #define LIBFUZZER_FREEBSD 0 73 #define LIBFUZZER_OPENBSD 0 74 #elif __APPLE__ 75 #define LIBFUZZER_LINUX 0 76 #define LIBFUZZER_APPLE 1 77 #define LIBFUZZER_NETBSD 0 78 #define LIBFUZZER_FREEBSD 0 79 #define LIBFUZZER_OPENBSD 0 80 #elif __NetBSD__ 81 #define LIBFUZZER_LINUX 0 82 #define LIBFUZZER_APPLE 0 83 #define LIBFUZZER_NETBSD 1 84 #define LIBFUZZER_FREEBSD 0 85 #define LIBFUZZER_OPENBSD 0 86 #elif __FreeBSD__ 87 #define LIBFUZZER_LINUX 0 88 #define LIBFUZZER_APPLE 0 89 #define LIBFUZZER_NETBSD 0 90 #define LIBFUZZER_FREEBSD 1 91 #define LIBFUZZER_OPENBSD 0 92 #elif __OpenBSD__ 93 #define LIBFUZZER_LINUX 0 94 #define LIBFUZZER_APPLE 0 95 #define LIBFUZZER_NETBSD 0 96 #define LIBFUZZER_FREEBSD 0 97 #define LIBFUZZER_OPENBSD 1 98 #else 99 #error "Support for your platform has not been implemented" 100 #endif 101 102 // Used to avoid repeating error checking boilerplate. If cond is false, a 103 // fatal error has occurred in the program. In this event print error_message 104 // to stderr and abort(). Otherwise do nothing. Note that setting 105 // AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended 106 // to the file as well, if the error occurs after the duplication is performed. 107 #define CHECK_ERROR(cond, error_message) \ 108 if (!(cond)) { \ 109 fprintf(stderr, "%s\n", (error_message)); \ 110 abort(); \ 111 } 112 113 // libFuzzer interface is thin, so we don't include any libFuzzer headers. 114 extern "C" { 115 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); 116 __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); 117 } 118 119 // Notify AFL about persistent mode. 120 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; 121 extern "C" int __afl_persistent_loop(unsigned int); 122 static volatile char suppress_warning2 = AFL_PERSISTENT[0]; 123 124 // Notify AFL about deferred forkserver. 125 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; 126 extern "C" void __afl_manual_init(); 127 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; 128 129 // Input buffer. 130 static const size_t kMaxAflInputSize = 1 << 20; 131 static uint8_t AflInputBuf[kMaxAflInputSize]; 132 133 // Variables we need for writing to the extra stats file. 134 static FILE *extra_stats_file = NULL; 135 static uint32_t previous_peak_rss = 0; 136 static time_t slowest_unit_time_secs = 0; 137 static const int kNumExtraStats = 2; 138 static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n" 139 "slowest_unit_time_sec : %u\n"; 140 141 // Experimental feature to use afl_driver without AFL's deferred mode. 142 // Needs to run before __afl_auto_init. 143 __attribute__((constructor(0))) void __decide_deferred_forkserver(void) { 144 if (getenv("AFL_DRIVER_DONT_DEFER")) { 145 if (unsetenv("__AFL_DEFER_FORKSRV")) { 146 perror("Failed to unset __AFL_DEFER_FORKSRV"); 147 abort(); 148 } 149 } 150 } 151 152 // Copied from FuzzerUtil.cpp. 153 size_t GetPeakRSSMb() { 154 struct rusage usage; 155 if (getrusage(RUSAGE_SELF, &usage)) 156 return 0; 157 if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD || 158 LIBFUZZER_OPENBSD) { 159 // ru_maxrss is in KiB 160 return usage.ru_maxrss >> 10; 161 } else if (LIBFUZZER_APPLE) { 162 // ru_maxrss is in bytes 163 return usage.ru_maxrss >> 20; 164 } 165 assert(0 && "GetPeakRSSMb() is not implemented for your platform"); 166 return 0; 167 } 168 169 // Based on SetSigaction in FuzzerUtil.cpp 170 static void SetSigaction(int signum, 171 void (*callback)(int, siginfo_t *, void *)) { 172 struct sigaction sigact; 173 memset(&sigact, 0, sizeof(sigact)); 174 sigact.sa_sigaction = callback; 175 if (sigaction(signum, &sigact, 0)) { 176 fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno); 177 exit(1); 178 } 179 } 180 181 // Write extra stats to the file specified by the user. If none is specified 182 // this function will never be called. 183 static void write_extra_stats() { 184 uint32_t peak_rss = GetPeakRSSMb(); 185 186 if (peak_rss < previous_peak_rss) 187 peak_rss = previous_peak_rss; 188 189 int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString, 190 peak_rss, slowest_unit_time_secs); 191 192 CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file"); 193 194 CHECK_ERROR(fclose(extra_stats_file) == 0, 195 "Failed to close extra_stats_file"); 196 } 197 198 // Call write_extra_stats before we exit. 199 static void crash_handler(int, siginfo_t *, void *) { 200 // Make sure we don't try calling write_extra_stats again if we crashed while 201 // trying to call it. 202 static bool first_crash = true; 203 CHECK_ERROR(first_crash, 204 "Crashed in crash signal handler. This is a bug in the fuzzer."); 205 206 first_crash = false; 207 write_extra_stats(); 208 } 209 210 // If the user has specified an extra_stats_file through the environment 211 // variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up 212 // to write stats to it on exit. If no file is specified, do nothing. Otherwise 213 // install signal and exit handlers to write to the file when the process exits. 214 // Then if the file doesn't exist create it and set extra stats to 0. But if it 215 // does exist then read the initial values of the extra stats from the file 216 // and check that the file is writable. 217 static void maybe_initialize_extra_stats() { 218 // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do. 219 char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME"); 220 if (!extra_stats_filename) 221 return; 222 223 // Open the file and find the previous peak_rss_mb value. 224 // This is necessary because the fuzzing process is restarted after N 225 // iterations are completed. So we may need to get this value from a previous 226 // process to be accurate. 227 extra_stats_file = fopen(extra_stats_filename, "r"); 228 229 // If extra_stats_file already exists: read old stats from it. 230 if (extra_stats_file) { 231 int matches = fscanf(extra_stats_file, kExtraStatsFormatString, 232 &previous_peak_rss, &slowest_unit_time_secs); 233 234 // Make sure we have read a real extra stats file and that we have used it 235 // to set slowest_unit_time_secs and previous_peak_rss. 236 CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt"); 237 238 CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file"); 239 240 // Now open the file for writing. 241 extra_stats_file = fopen(extra_stats_filename, "w"); 242 CHECK_ERROR(extra_stats_file, 243 "Failed to open extra stats file for writing"); 244 } else { 245 // Looks like this is the first time in a fuzzing job this is being called. 246 extra_stats_file = fopen(extra_stats_filename, "w+"); 247 CHECK_ERROR(extra_stats_file, "failed to create extra stats file"); 248 } 249 250 // Make sure that crash_handler gets called on any kind of fatal error. 251 int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT, 252 SIGTERM}; 253 254 const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]); 255 256 for (size_t idx = 0; idx < num_signals; idx++) 257 SetSigaction(crash_signals[idx], crash_handler); 258 259 // Make sure it gets called on other kinds of exits. 260 atexit(write_extra_stats); 261 } 262 263 // If the user asks us to duplicate stderr, then do it. 264 static void maybe_duplicate_stderr() { 265 char* stderr_duplicate_filename = 266 getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); 267 268 if (!stderr_duplicate_filename) 269 return; 270 271 FILE* stderr_duplicate_stream = 272 freopen(stderr_duplicate_filename, "a+", stderr); 273 274 if (!stderr_duplicate_stream) { 275 fprintf( 276 stderr, 277 "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); 278 abort(); 279 } 280 } 281 282 // Define LLVMFuzzerMutate to avoid link failures for targets that use it 283 // with libFuzzer's LLVMFuzzerCustomMutator. 284 extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { 285 assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); 286 return 0; 287 } 288 289 // Execute any files provided as parameters. 290 int ExecuteFilesOnyByOne(int argc, char **argv) { 291 for (int i = 1; i < argc; i++) { 292 std::ifstream in(argv[i], std::ios::binary); 293 in.seekg(0, in.end); 294 size_t length = in.tellg(); 295 in.seekg (0, in.beg); 296 std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl; 297 // Allocate exactly length bytes so that we reliably catch buffer overflows. 298 std::vector<char> bytes(length); 299 in.read(bytes.data(), bytes.size()); 300 assert(in); 301 LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()), 302 bytes.size()); 303 std::cout << "Execution successful" << std::endl; 304 } 305 return 0; 306 } 307 308 int main(int argc, char **argv) { 309 fprintf(stderr, 310 "======================= INFO =========================\n" 311 "This binary is built for AFL-fuzz.\n" 312 "To run the target function on individual input(s) execute this:\n" 313 " %s < INPUT_FILE\n" 314 "or\n" 315 " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" 316 "To fuzz with afl-fuzz execute this:\n" 317 " afl-fuzz [afl-flags] %s [-N]\n" 318 "afl-fuzz will run N iterations before " 319 "re-spawning the process (default: 1000)\n" 320 "======================================================\n", 321 argv[0], argv[0], argv[0]); 322 if (LLVMFuzzerInitialize) 323 LLVMFuzzerInitialize(&argc, &argv); 324 // Do any other expensive one-time initialization here. 325 326 maybe_duplicate_stderr(); 327 maybe_initialize_extra_stats(); 328 329 if (!getenv("AFL_DRIVER_DONT_DEFER")) 330 __afl_manual_init(); 331 332 int N = 1000; 333 if (argc == 2 && argv[1][0] == '-') 334 N = atoi(argv[1] + 1); 335 else if(argc == 2 && (N = atoi(argv[1])) > 0) 336 fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n", 337 argv[0], N); 338 else if (argc > 1) 339 return ExecuteFilesOnyByOne(argc, argv); 340 341 assert(N > 0); 342 343 // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization 344 // on the first execution of LLVMFuzzerTestOneInput is ignored. 345 uint8_t dummy_input[1] = {0}; 346 LLVMFuzzerTestOneInput(dummy_input, 1); 347 348 time_t unit_time_secs; 349 int num_runs = 0; 350 while (__afl_persistent_loop(N)) { 351 ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); 352 if (n_read > 0) { 353 // Copy AflInputBuf into a separate buffer to let asan find buffer 354 // overflows. Don't use unique_ptr/etc to avoid extra dependencies. 355 uint8_t *copy = new uint8_t[n_read]; 356 memcpy(copy, AflInputBuf, n_read); 357 358 struct timeval unit_start_time; 359 CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0, 360 "Calling gettimeofday failed"); 361 362 num_runs++; 363 LLVMFuzzerTestOneInput(copy, n_read); 364 365 struct timeval unit_stop_time; 366 CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0, 367 "Calling gettimeofday failed"); 368 369 // Update slowest_unit_time_secs if we see a new max. 370 unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec; 371 if (slowest_unit_time_secs < unit_time_secs) 372 slowest_unit_time_secs = unit_time_secs; 373 374 delete[] copy; 375 } 376 } 377 fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs); 378 } 379