1c5f01b2fSopenharmony_ci//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===// 2c5f01b2fSopenharmony_ci// 3c5f01b2fSopenharmony_ci// The LLVM Compiler Infrastructure 4c5f01b2fSopenharmony_ci// 5c5f01b2fSopenharmony_ci// This file is distributed under the University of Illinois Open Source 6c5f01b2fSopenharmony_ci// License. See LICENSE.TXT for details. 7c5f01b2fSopenharmony_ci//===----------------------------------------------------------------------===// 8c5f01b2fSopenharmony_ci 9c5f01b2fSopenharmony_ci/* This file allows to fuzz libFuzzer-style target functions 10c5f01b2fSopenharmony_ci (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. 11c5f01b2fSopenharmony_ci 12c5f01b2fSopenharmony_ciUsage: 13c5f01b2fSopenharmony_ci################################################################################ 14c5f01b2fSopenharmony_cicat << EOF > test_fuzzer.cc 15c5f01b2fSopenharmony_ci#include <stdint.h> 16c5f01b2fSopenharmony_ci#include <stddef.h> 17c5f01b2fSopenharmony_ciextern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 18c5f01b2fSopenharmony_ci if (size > 0 && data[0] == 'H') 19c5f01b2fSopenharmony_ci if (size > 1 && data[1] == 'I') 20c5f01b2fSopenharmony_ci if (size > 2 && data[2] == '!') 21c5f01b2fSopenharmony_ci __builtin_trap(); 22c5f01b2fSopenharmony_ci return 0; 23c5f01b2fSopenharmony_ci} 24c5f01b2fSopenharmony_ciEOF 25c5f01b2fSopenharmony_ci# Build your target with -fsanitize-coverage=trace-pc using fresh clang. 26c5f01b2fSopenharmony_ciclang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c 27c5f01b2fSopenharmony_ci# Build afl-llvm-rt.o.c from the AFL distribution. 28c5f01b2fSopenharmony_ciclang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c 29c5f01b2fSopenharmony_ci# Build this file, link it with afl-llvm-rt.o.o and the target code. 30c5f01b2fSopenharmony_ciclang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o 31c5f01b2fSopenharmony_ci# Run AFL: 32c5f01b2fSopenharmony_cirm -rf IN OUT; mkdir IN OUT; echo z > IN/z; 33c5f01b2fSopenharmony_ci$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out 34c5f01b2fSopenharmony_ci################################################################################ 35c5f01b2fSopenharmony_ciEnvironment Variables: 36c5f01b2fSopenharmony_ciThere are a few environment variables that can be set to use features that 37c5f01b2fSopenharmony_ciafl-fuzz doesn't have. 38c5f01b2fSopenharmony_ci 39c5f01b2fSopenharmony_ciAFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file 40c5f01b2fSopenharmony_cispecified. If the file does not exist, it is created. This is useful for getting 41c5f01b2fSopenharmony_cistack traces (when using ASAN for example) or original error messages on hard to 42c5f01b2fSopenharmony_cireproduce bugs. 43c5f01b2fSopenharmony_ci 44c5f01b2fSopenharmony_ciAFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra 45c5f01b2fSopenharmony_cistatistics to the file specified. Currently these are peak_rss_mb 46c5f01b2fSopenharmony_ci(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If 47c5f01b2fSopenharmony_cithe file does not exist it is created. If the file does exist then 48c5f01b2fSopenharmony_ciafl_driver assumes it was restarted by afl-fuzz and will try to read old 49c5f01b2fSopenharmony_cistatistics from the file. If that fails then the process will quit. 50c5f01b2fSopenharmony_ci 51c5f01b2fSopenharmony_ci*/ 52c5f01b2fSopenharmony_ci#include <assert.h> 53c5f01b2fSopenharmony_ci#include <stdio.h> 54c5f01b2fSopenharmony_ci#include <stdint.h> 55c5f01b2fSopenharmony_ci#include <stdlib.h> 56c5f01b2fSopenharmony_ci#include <string.h> 57c5f01b2fSopenharmony_ci#include <unistd.h> 58c5f01b2fSopenharmony_ci#include <errno.h> 59c5f01b2fSopenharmony_ci#include <signal.h> 60c5f01b2fSopenharmony_ci#include <sys/resource.h> 61c5f01b2fSopenharmony_ci#include <sys/time.h> 62c5f01b2fSopenharmony_ci// Platform detection. Copied from FuzzerInternal.h 63c5f01b2fSopenharmony_ci#ifdef __linux__ 64c5f01b2fSopenharmony_ci#define LIBFUZZER_LINUX 1 65c5f01b2fSopenharmony_ci#define LIBFUZZER_APPLE 0 66c5f01b2fSopenharmony_ci#elif __APPLE__ 67c5f01b2fSopenharmony_ci#define LIBFUZZER_LINUX 0 68c5f01b2fSopenharmony_ci#define LIBFUZZER_APPLE 1 69c5f01b2fSopenharmony_ci#else 70c5f01b2fSopenharmony_ci#error "Support for your platform has not been implemented" 71c5f01b2fSopenharmony_ci#endif 72c5f01b2fSopenharmony_ci 73c5f01b2fSopenharmony_ci// Used to avoid repeating error checking boilerplate. If cond is false, a 74c5f01b2fSopenharmony_ci// fatal error has occured in the program. In this event print error_message 75c5f01b2fSopenharmony_ci// to stderr and abort(). Otherwise do nothing. Note that setting 76c5f01b2fSopenharmony_ci// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended 77c5f01b2fSopenharmony_ci// to the file as well, if the error occurs after the duplication is performed. 78c5f01b2fSopenharmony_ci#define CHECK_ERROR(cond, error_message) \ 79c5f01b2fSopenharmony_ci if (!(cond)) { \ 80c5f01b2fSopenharmony_ci fprintf(stderr, (error_message)); \ 81c5f01b2fSopenharmony_ci abort(); \ 82c5f01b2fSopenharmony_ci } 83c5f01b2fSopenharmony_ci 84c5f01b2fSopenharmony_ci// libFuzzer interface is thin, so we don't include any libFuzzer headers. 85c5f01b2fSopenharmony_ciextern "C" { 86c5f01b2fSopenharmony_ciint LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); 87c5f01b2fSopenharmony_ci__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); 88c5f01b2fSopenharmony_ci} 89c5f01b2fSopenharmony_ci 90c5f01b2fSopenharmony_ci// Notify AFL about persistent mode. 91c5f01b2fSopenharmony_cistatic volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; 92c5f01b2fSopenharmony_ciextern "C" int __afl_persistent_loop(unsigned int); 93c5f01b2fSopenharmony_cistatic volatile char suppress_warning2 = AFL_PERSISTENT[0]; 94c5f01b2fSopenharmony_ci 95c5f01b2fSopenharmony_ci// Notify AFL about deferred forkserver. 96c5f01b2fSopenharmony_cistatic volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; 97c5f01b2fSopenharmony_ciextern "C" void __afl_manual_init(); 98c5f01b2fSopenharmony_cistatic volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; 99c5f01b2fSopenharmony_ci 100c5f01b2fSopenharmony_ci// Input buffer. 101c5f01b2fSopenharmony_cistatic const size_t kMaxAflInputSize = 1 << 20; 102c5f01b2fSopenharmony_cistatic uint8_t AflInputBuf[kMaxAflInputSize]; 103c5f01b2fSopenharmony_ci 104c5f01b2fSopenharmony_ci// Variables we need for writing to the extra stats file. 105c5f01b2fSopenharmony_cistatic FILE *extra_stats_file = NULL; 106c5f01b2fSopenharmony_cistatic uint32_t previous_peak_rss = 0; 107c5f01b2fSopenharmony_cistatic time_t slowest_unit_time_secs = 0; 108c5f01b2fSopenharmony_cistatic const int kNumExtraStats = 2; 109c5f01b2fSopenharmony_cistatic const char *kExtraStatsFormatString = "peak_rss_mb : %u\n" 110c5f01b2fSopenharmony_ci "slowest_unit_time_sec : %u\n"; 111c5f01b2fSopenharmony_ci 112c5f01b2fSopenharmony_ci// Copied from FuzzerUtil.cpp. 113c5f01b2fSopenharmony_cisize_t GetPeakRSSMb() { 114c5f01b2fSopenharmony_ci struct rusage usage; 115c5f01b2fSopenharmony_ci if (getrusage(RUSAGE_SELF, &usage)) 116c5f01b2fSopenharmony_ci return 0; 117c5f01b2fSopenharmony_ci if (LIBFUZZER_LINUX) { 118c5f01b2fSopenharmony_ci // ru_maxrss is in KiB 119c5f01b2fSopenharmony_ci return usage.ru_maxrss >> 10; 120c5f01b2fSopenharmony_ci } else if (LIBFUZZER_APPLE) { 121c5f01b2fSopenharmony_ci // ru_maxrss is in bytes 122c5f01b2fSopenharmony_ci return usage.ru_maxrss >> 20; 123c5f01b2fSopenharmony_ci } 124c5f01b2fSopenharmony_ci assert(0 && "GetPeakRSSMb() is not implemented for your platform"); 125c5f01b2fSopenharmony_ci return 0; 126c5f01b2fSopenharmony_ci} 127c5f01b2fSopenharmony_ci 128c5f01b2fSopenharmony_ci// Based on SetSigaction in FuzzerUtil.cpp 129c5f01b2fSopenharmony_cistatic void SetSigaction(int signum, 130c5f01b2fSopenharmony_ci void (*callback)(int, siginfo_t *, void *)) { 131c5f01b2fSopenharmony_ci struct sigaction sigact; 132c5f01b2fSopenharmony_ci memset(&sigact, 0, sizeof(sigact)); 133c5f01b2fSopenharmony_ci sigact.sa_sigaction = callback; 134c5f01b2fSopenharmony_ci if (sigaction(signum, &sigact, 0)) { 135c5f01b2fSopenharmony_ci fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno); 136c5f01b2fSopenharmony_ci exit(1); 137c5f01b2fSopenharmony_ci } 138c5f01b2fSopenharmony_ci} 139c5f01b2fSopenharmony_ci 140c5f01b2fSopenharmony_ci// Write extra stats to the file specified by the user. If none is specified 141c5f01b2fSopenharmony_ci// this function will never be called. 142c5f01b2fSopenharmony_cistatic void write_extra_stats() { 143c5f01b2fSopenharmony_ci uint32_t peak_rss = GetPeakRSSMb(); 144c5f01b2fSopenharmony_ci 145c5f01b2fSopenharmony_ci if (peak_rss < previous_peak_rss) 146c5f01b2fSopenharmony_ci peak_rss = previous_peak_rss; 147c5f01b2fSopenharmony_ci 148c5f01b2fSopenharmony_ci int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString, 149c5f01b2fSopenharmony_ci peak_rss, slowest_unit_time_secs); 150c5f01b2fSopenharmony_ci 151c5f01b2fSopenharmony_ci CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file"); 152c5f01b2fSopenharmony_ci 153c5f01b2fSopenharmony_ci CHECK_ERROR(fclose(extra_stats_file) == 0, 154c5f01b2fSopenharmony_ci "Failed to close extra_stats_file"); 155c5f01b2fSopenharmony_ci} 156c5f01b2fSopenharmony_ci 157c5f01b2fSopenharmony_ci// Call write_extra_stats before we exit. 158c5f01b2fSopenharmony_cistatic void crash_handler(int, siginfo_t *, void *) { 159c5f01b2fSopenharmony_ci // Make sure we don't try calling write_extra_stats again if we crashed while 160c5f01b2fSopenharmony_ci // trying to call it. 161c5f01b2fSopenharmony_ci static bool first_crash = true; 162c5f01b2fSopenharmony_ci CHECK_ERROR(first_crash, 163c5f01b2fSopenharmony_ci "Crashed in crash signal handler. This is a bug in the fuzzer."); 164c5f01b2fSopenharmony_ci 165c5f01b2fSopenharmony_ci first_crash = false; 166c5f01b2fSopenharmony_ci write_extra_stats(); 167c5f01b2fSopenharmony_ci} 168c5f01b2fSopenharmony_ci 169c5f01b2fSopenharmony_ci// If the user has specified an extra_stats_file through the environment 170c5f01b2fSopenharmony_ci// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up 171c5f01b2fSopenharmony_ci// to write stats to it on exit. If no file is specified, do nothing. Otherwise 172c5f01b2fSopenharmony_ci// install signal and exit handlers to write to the file when the process exits. 173c5f01b2fSopenharmony_ci// Then if the file doesn't exist create it and set extra stats to 0. But if it 174c5f01b2fSopenharmony_ci// does exist then read the initial values of the extra stats from the file 175c5f01b2fSopenharmony_ci// and check that the file is writable. 176c5f01b2fSopenharmony_cistatic void maybe_initialize_extra_stats() { 177c5f01b2fSopenharmony_ci // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do. 178c5f01b2fSopenharmony_ci char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME"); 179c5f01b2fSopenharmony_ci if (!extra_stats_filename) 180c5f01b2fSopenharmony_ci return; 181c5f01b2fSopenharmony_ci 182c5f01b2fSopenharmony_ci // Open the file and find the previous peak_rss_mb value. 183c5f01b2fSopenharmony_ci // This is necessary because the fuzzing process is restarted after N 184c5f01b2fSopenharmony_ci // iterations are completed. So we may need to get this value from a previous 185c5f01b2fSopenharmony_ci // process to be accurate. 186c5f01b2fSopenharmony_ci extra_stats_file = fopen(extra_stats_filename, "r"); 187c5f01b2fSopenharmony_ci 188c5f01b2fSopenharmony_ci // If extra_stats_file already exists: read old stats from it. 189c5f01b2fSopenharmony_ci if (extra_stats_file) { 190c5f01b2fSopenharmony_ci int matches = fscanf(extra_stats_file, kExtraStatsFormatString, 191c5f01b2fSopenharmony_ci &previous_peak_rss, &slowest_unit_time_secs); 192c5f01b2fSopenharmony_ci 193c5f01b2fSopenharmony_ci // Make sure we have read a real extra stats file and that we have used it 194c5f01b2fSopenharmony_ci // to set slowest_unit_time_secs and previous_peak_rss. 195c5f01b2fSopenharmony_ci CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt"); 196c5f01b2fSopenharmony_ci 197c5f01b2fSopenharmony_ci CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file"); 198c5f01b2fSopenharmony_ci 199c5f01b2fSopenharmony_ci // Now open the file for writing. 200c5f01b2fSopenharmony_ci extra_stats_file = fopen(extra_stats_filename, "w"); 201c5f01b2fSopenharmony_ci CHECK_ERROR(extra_stats_file, 202c5f01b2fSopenharmony_ci "Failed to open extra stats file for writing"); 203c5f01b2fSopenharmony_ci } else { 204c5f01b2fSopenharmony_ci // Looks like this is the first time in a fuzzing job this is being called. 205c5f01b2fSopenharmony_ci extra_stats_file = fopen(extra_stats_filename, "w+"); 206c5f01b2fSopenharmony_ci CHECK_ERROR(extra_stats_file, "failed to create extra stats file"); 207c5f01b2fSopenharmony_ci } 208c5f01b2fSopenharmony_ci 209c5f01b2fSopenharmony_ci // Make sure that crash_handler gets called on any kind of fatal error. 210c5f01b2fSopenharmony_ci int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT, 211c5f01b2fSopenharmony_ci SIGTERM}; 212c5f01b2fSopenharmony_ci 213c5f01b2fSopenharmony_ci const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]); 214c5f01b2fSopenharmony_ci 215c5f01b2fSopenharmony_ci for (size_t idx = 0; idx < num_signals; idx++) 216c5f01b2fSopenharmony_ci SetSigaction(crash_signals[idx], crash_handler); 217c5f01b2fSopenharmony_ci 218c5f01b2fSopenharmony_ci // Make sure it gets called on other kinds of exits. 219c5f01b2fSopenharmony_ci atexit(write_extra_stats); 220c5f01b2fSopenharmony_ci} 221c5f01b2fSopenharmony_ci 222c5f01b2fSopenharmony_ci// If the user asks us to duplicate stderr, then do it. 223c5f01b2fSopenharmony_cistatic void maybe_duplicate_stderr() { 224c5f01b2fSopenharmony_ci char* stderr_duplicate_filename = 225c5f01b2fSopenharmony_ci getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); 226c5f01b2fSopenharmony_ci 227c5f01b2fSopenharmony_ci if (!stderr_duplicate_filename) 228c5f01b2fSopenharmony_ci return; 229c5f01b2fSopenharmony_ci 230c5f01b2fSopenharmony_ci FILE* stderr_duplicate_stream = 231c5f01b2fSopenharmony_ci freopen(stderr_duplicate_filename, "a+", stderr); 232c5f01b2fSopenharmony_ci 233c5f01b2fSopenharmony_ci if (!stderr_duplicate_stream) { 234c5f01b2fSopenharmony_ci fprintf( 235c5f01b2fSopenharmony_ci stderr, 236c5f01b2fSopenharmony_ci "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); 237c5f01b2fSopenharmony_ci abort(); 238c5f01b2fSopenharmony_ci } 239c5f01b2fSopenharmony_ci} 240c5f01b2fSopenharmony_ci 241c5f01b2fSopenharmony_ciint main(int argc, char **argv) { 242c5f01b2fSopenharmony_ci fprintf(stderr, "======================= INFO =========================\n" 243c5f01b2fSopenharmony_ci "This binary is built for AFL-fuzz.\n" 244c5f01b2fSopenharmony_ci "To run the target function on a single input execute this:\n" 245c5f01b2fSopenharmony_ci " %s < INPUT_FILE\n" 246c5f01b2fSopenharmony_ci "To run the fuzzing execute this:\n" 247c5f01b2fSopenharmony_ci " afl-fuzz [afl-flags] %s [N] " 248c5f01b2fSopenharmony_ci "-- run N fuzzing iterations before " 249c5f01b2fSopenharmony_ci "re-spawning the process (default: 1000)\n" 250c5f01b2fSopenharmony_ci "======================================================\n", 251c5f01b2fSopenharmony_ci argv[0], argv[0]); 252c5f01b2fSopenharmony_ci if (LLVMFuzzerInitialize) 253c5f01b2fSopenharmony_ci LLVMFuzzerInitialize(&argc, &argv); 254c5f01b2fSopenharmony_ci // Do any other expensive one-time initialization here. 255c5f01b2fSopenharmony_ci 256c5f01b2fSopenharmony_ci maybe_duplicate_stderr(); 257c5f01b2fSopenharmony_ci maybe_initialize_extra_stats(); 258c5f01b2fSopenharmony_ci 259c5f01b2fSopenharmony_ci __afl_manual_init(); 260c5f01b2fSopenharmony_ci 261c5f01b2fSopenharmony_ci int N = 1000; 262c5f01b2fSopenharmony_ci if (argc >= 2) 263c5f01b2fSopenharmony_ci N = atoi(argv[1]); 264c5f01b2fSopenharmony_ci assert(N > 0); 265c5f01b2fSopenharmony_ci time_t unit_time_secs; 266c5f01b2fSopenharmony_ci int num_runs = 0; 267c5f01b2fSopenharmony_ci while (__afl_persistent_loop(N)) { 268c5f01b2fSopenharmony_ci ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); 269c5f01b2fSopenharmony_ci if (n_read > 0) { 270c5f01b2fSopenharmony_ci // Copy AflInputBuf into a separate buffer to let asan find buffer 271c5f01b2fSopenharmony_ci // overflows. Don't use unique_ptr/etc to avoid extra dependencies. 272c5f01b2fSopenharmony_ci uint8_t *copy = new uint8_t[n_read]; 273c5f01b2fSopenharmony_ci memcpy(copy, AflInputBuf, n_read); 274c5f01b2fSopenharmony_ci 275c5f01b2fSopenharmony_ci struct timeval unit_start_time; 276c5f01b2fSopenharmony_ci CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0, 277c5f01b2fSopenharmony_ci "Calling gettimeofday failed"); 278c5f01b2fSopenharmony_ci 279c5f01b2fSopenharmony_ci num_runs++; 280c5f01b2fSopenharmony_ci LLVMFuzzerTestOneInput(copy, n_read); 281c5f01b2fSopenharmony_ci 282c5f01b2fSopenharmony_ci struct timeval unit_stop_time; 283c5f01b2fSopenharmony_ci CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0, 284c5f01b2fSopenharmony_ci "Calling gettimeofday failed"); 285c5f01b2fSopenharmony_ci 286c5f01b2fSopenharmony_ci // Update slowest_unit_time_secs if we see a new max. 287c5f01b2fSopenharmony_ci unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec; 288c5f01b2fSopenharmony_ci if (slowest_unit_time_secs < unit_time_secs) 289c5f01b2fSopenharmony_ci slowest_unit_time_secs = unit_time_secs; 290c5f01b2fSopenharmony_ci 291c5f01b2fSopenharmony_ci delete[] copy; 292c5f01b2fSopenharmony_ci } 293c5f01b2fSopenharmony_ci } 294c5f01b2fSopenharmony_ci fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs); 295c5f01b2fSopenharmony_ci} 296