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 #elif __APPLE__ 74 #define LIBFUZZER_LINUX 0 75 #define LIBFUZZER_APPLE 1 76 #define LIBFUZZER_NETBSD 0 77 #define LIBFUZZER_FREEBSD 0 78 #elif __NetBSD__ 79 #define LIBFUZZER_LINUX 0 80 #define LIBFUZZER_APPLE 0 81 #define LIBFUZZER_NETBSD 1 82 #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 88 #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 93 // fatal error has occured in the program. In this event print error_message 94 // 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)) { \ 99 fprintf(stderr, "%s\n", (error_message)); \ 100 abort(); \ 101 } 102 103 // libFuzzer interface is thin, so we don't include any libFuzzer headers. 104 extern "C" { 105 int 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. 110 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; 111 extern "C" int __afl_persistent_loop(unsigned int); 112 static volatile char suppress_warning2 = AFL_PERSISTENT[0]; 113 114 // Notify AFL about deferred forkserver. 115 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; 116 extern "C" void __afl_manual_init(); 117 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; 118 119 // Input buffer. 120 static const size_t kMaxAflInputSize = 1 << 20; 121 static uint8_t AflInputBuf[kMaxAflInputSize]; 122 123 // Variables we need for writing to the extra stats file. 124 static FILE *extra_stats_file = NULL; 125 static uint32_t previous_peak_rss = 0; 126 static time_t slowest_unit_time_secs = 0; 127 static const int kNumExtraStats = 2; 128 static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n" 129 "slowest_unit_time_sec : %u\n"; 130 131 // Copied from FuzzerUtil.cpp. 132 size_t GetPeakRSSMb() { 133 struct rusage usage; 134 if (getrusage(RUSAGE_SELF, &usage)) 135 return 0; 136 if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD) { 137 // 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 148 static 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. 161 static 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. 177 static 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. 195 static 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. 242 static 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. 262 extern "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. 268 int 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()); 281 std::cout << "Execution successfull" << std::endl; 282 } 283 return 0; 284 } 285 286 int 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); 319 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 325 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 } 356