1 //===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===// 2 // 3 // 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 6 //===----------------------------------------------------------------------===// 7 8 /* This file allows to fuzz libFuzzer-style target functions 9 (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode. 10 11 Usage: 12 ################################################################################ 13 cat << EOF > test_fuzzer.cc 14 #include <stddef.h> 15 #include <stdint.h> 16 extern "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 } 23 EOF 24 # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang. 25 clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c 26 # Build afl-llvm-rt.o.c from the AFL distribution. 27 clang -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. 29 clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o 30 # Run AFL: 31 rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; 32 $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out 33 ################################################################################ 34 AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this environment variable 35 *appends* stderr to the file specified. If the file does not exist, it is 36 created. This is useful for getting stack traces (when using ASAN for example) 37 or original error messages on hard to reproduce bugs. 38 39 */ 40 #include <assert.h> 41 #include <errno.h> 42 #include <stdint.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include <fstream> 49 #include <iostream> 50 #include <vector> 51 52 // Platform detection. Copied from FuzzerInternal.h 53 #ifdef __linux__ 54 #define LIBFUZZER_LINUX 1 55 #define LIBFUZZER_APPLE 0 56 #define LIBFUZZER_NETBSD 0 57 #define LIBFUZZER_FREEBSD 0 58 #define LIBFUZZER_OPENBSD 0 59 #elif __APPLE__ 60 #define LIBFUZZER_LINUX 0 61 #define LIBFUZZER_APPLE 1 62 #define LIBFUZZER_NETBSD 0 63 #define LIBFUZZER_FREEBSD 0 64 #define LIBFUZZER_OPENBSD 0 65 #elif __NetBSD__ 66 #define LIBFUZZER_LINUX 0 67 #define LIBFUZZER_APPLE 0 68 #define LIBFUZZER_NETBSD 1 69 #define LIBFUZZER_FREEBSD 0 70 #define LIBFUZZER_OPENBSD 0 71 #elif __FreeBSD__ 72 #define LIBFUZZER_LINUX 0 73 #define LIBFUZZER_APPLE 0 74 #define LIBFUZZER_NETBSD 0 75 #define LIBFUZZER_FREEBSD 1 76 #define LIBFUZZER_OPENBSD 0 77 #elif __OpenBSD__ 78 #define LIBFUZZER_LINUX 0 79 #define LIBFUZZER_APPLE 0 80 #define LIBFUZZER_NETBSD 0 81 #define LIBFUZZER_FREEBSD 0 82 #define LIBFUZZER_OPENBSD 1 83 #else 84 #error "Support for your platform has not been implemented" 85 #endif 86 87 // libFuzzer interface is thin, so we don't include any libFuzzer headers. 88 extern "C" { 89 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); 90 __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv); 91 } 92 93 // Notify AFL about persistent mode. 94 static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##"; 95 extern "C" int __afl_persistent_loop(unsigned int); 96 static volatile char suppress_warning2 = AFL_PERSISTENT[0]; 97 98 // Notify AFL about deferred forkserver. 99 static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##"; 100 extern "C" void __afl_manual_init(); 101 static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; 102 103 // Input buffer. 104 static const size_t kMaxAflInputSize = 1 << 20; 105 static uint8_t AflInputBuf[kMaxAflInputSize]; 106 107 // Experimental feature to use afl_driver without AFL's deferred mode. 108 // Needs to run before __afl_auto_init. 109 __attribute__((constructor(0))) void __decide_deferred_forkserver(void) { 110 if (getenv("AFL_DRIVER_DONT_DEFER")) { 111 if (unsetenv("__AFL_DEFER_FORKSRV")) { 112 perror("Failed to unset __AFL_DEFER_FORKSRV"); 113 abort(); 114 } 115 } 116 } 117 118 // If the user asks us to duplicate stderr, then do it. 119 static void maybe_duplicate_stderr() { 120 char* stderr_duplicate_filename = 121 getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); 122 123 if (!stderr_duplicate_filename) 124 return; 125 126 FILE* stderr_duplicate_stream = 127 freopen(stderr_duplicate_filename, "a+", stderr); 128 129 if (!stderr_duplicate_stream) { 130 fprintf( 131 stderr, 132 "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); 133 abort(); 134 } 135 } 136 137 // Define LLVMFuzzerMutate to avoid link failures for targets that use it 138 // with libFuzzer's LLVMFuzzerCustomMutator. 139 extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { 140 assert(false && "LLVMFuzzerMutate should not be called from afl_driver"); 141 return 0; 142 } 143 144 // Execute any files provided as parameters. 145 int ExecuteFilesOnyByOne(int argc, char **argv) { 146 for (int i = 1; i < argc; i++) { 147 std::ifstream in(argv[i], std::ios::binary); 148 in.seekg(0, in.end); 149 size_t length = in.tellg(); 150 in.seekg (0, in.beg); 151 std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl; 152 // Allocate exactly length bytes so that we reliably catch buffer overflows. 153 std::vector<char> bytes(length); 154 in.read(bytes.data(), bytes.size()); 155 assert(in); 156 LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()), 157 bytes.size()); 158 std::cout << "Execution successful" << std::endl; 159 } 160 return 0; 161 } 162 163 int main(int argc, char **argv) { 164 fprintf(stderr, 165 "======================= INFO =========================\n" 166 "This binary is built for AFL-fuzz.\n" 167 "To run the target function on individual input(s) execute this:\n" 168 " %s < INPUT_FILE\n" 169 "or\n" 170 " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n" 171 "To fuzz with afl-fuzz execute this:\n" 172 " afl-fuzz [afl-flags] %s [-N]\n" 173 "afl-fuzz will run N iterations before " 174 "re-spawning the process (default: 1000)\n" 175 "======================================================\n", 176 argv[0], argv[0], argv[0]); 177 if (LLVMFuzzerInitialize) 178 LLVMFuzzerInitialize(&argc, &argv); 179 // Do any other expensive one-time initialization here. 180 181 maybe_duplicate_stderr(); 182 183 if (!getenv("AFL_DRIVER_DONT_DEFER")) 184 __afl_manual_init(); 185 186 int N = 1000; 187 if (argc == 2 && argv[1][0] == '-') 188 N = atoi(argv[1] + 1); 189 else if(argc == 2 && (N = atoi(argv[1])) > 0) 190 fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n", 191 argv[0], N); 192 else if (argc > 1) 193 return ExecuteFilesOnyByOne(argc, argv); 194 195 assert(N > 0); 196 197 // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization 198 // on the first execution of LLVMFuzzerTestOneInput is ignored. 199 uint8_t dummy_input[1] = {0}; 200 LLVMFuzzerTestOneInput(dummy_input, 1); 201 202 int num_runs = 0; 203 while (__afl_persistent_loop(N)) { 204 ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); 205 if (n_read > 0) { 206 // Copy AflInputBuf into a separate buffer to let asan find buffer 207 // overflows. Don't use unique_ptr/etc to avoid extra dependencies. 208 uint8_t *copy = new uint8_t[n_read]; 209 memcpy(copy, AflInputBuf, n_read); 210 num_runs++; 211 LLVMFuzzerTestOneInput(copy, n_read); 212 delete[] copy; 213 } 214 } 215 fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs); 216 } 217