1# llvm_mode persistent mode 2 3## 1) Introduction 4 5In persistent mode, AFL++ fuzzes a target multiple times in a single forked 6process, instead of forking a new process for each fuzz execution. This is the 7most effective way to fuzz, as the speed can easily be x10 or x20 times faster 8without any disadvantages. *All professional fuzzing uses this mode.* 9 10Persistent mode requires that the target can be called in one or more functions, 11and that it's state can be completely reset so that multiple calls can be 12performed without resource leaks, and that earlier runs will have no impact on 13future runs. An indicator for this is the `stability` value in the `afl-fuzz` 14UI. If this decreases to lower values in persistent mode compared to 15non-persistent mode, then the fuzz target keeps state. 16 17Examples can be found in [utils/persistent_mode](../utils/persistent_mode). 18 19## 2) TL;DR: 20 21Example `fuzz_target.c`: 22 23```c 24#include "what_you_need_for_your_target.h" 25 26__AFL_FUZZ_INIT(); 27 28main() { 29 30 // anything else here, e.g. command line arguments, initialization, etc. 31 32#ifdef __AFL_HAVE_MANUAL_CONTROL 33 __AFL_INIT(); 34#endif 35 36 unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT 37 // and before __AFL_LOOP! 38 39 while (__AFL_LOOP(10000)) { 40 41 int len = __AFL_FUZZ_TESTCASE_LEN; // don't use the macro directly in a 42 // call! 43 44 if (len < 8) continue; // check for a required/useful minimum input length 45 46 /* Setup function call, e.g. struct target *tmp = libtarget_init() */ 47 /* Call function to be fuzzed, e.g.: */ 48 target_function(buf, len); 49 /* Reset state. e.g. libtarget_free(tmp) */ 50 51 } 52 53 return 0; 54 55} 56``` 57 58And then compile: 59 60``` 61afl-clang-fast -o fuzz_target fuzz_target.c -lwhat_you_need_for_your_target 62``` 63 64And that is it! The speed increase is usually x10 to x20. 65 66If you want to be able to compile the target without afl-clang-fast/lto, then 67add this just after the includes: 68 69```c 70#ifndef __AFL_FUZZ_TESTCASE_LEN 71 ssize_t fuzz_len; 72 #define __AFL_FUZZ_TESTCASE_LEN fuzz_len 73 unsigned char fuzz_buf[1024000]; 74 #define __AFL_FUZZ_TESTCASE_BUF fuzz_buf 75 #define __AFL_FUZZ_INIT() void sync(void); 76 #define __AFL_LOOP(x) ((fuzz_len = read(0, fuzz_buf, sizeof(fuzz_buf))) > 0 ? 1 : 0) 77 #define __AFL_INIT() sync() 78#endif 79``` 80 81## 3) Deferred initialization 82 83AFL++ tries to optimize performance by executing the targeted binary just once, 84stopping it just before `main()`, and then cloning this "main" process to get a 85steady supply of targets to fuzz. 86 87Although this approach eliminates much of the OS-, linker- and libc-level costs 88of executing the program, it does not always help with binaries that perform 89other time-consuming initialization steps - say, parsing a large config file 90before getting to the fuzzed data. 91 92In such cases, it's beneficial to initialize the forkserver a bit later, once 93most of the initialization work is already done, but before the binary attempts 94to read the fuzzed input and parse it; in some cases, this can offer a 10x+ 95performance gain. You can implement delayed initialization in LLVM mode in a 96fairly simple way. 97 98First, find a suitable location in the code where the delayed cloning can take 99place. This needs to be done with *extreme* care to avoid breaking the binary. 100In particular, the program will probably malfunction if you select a location 101after: 102 103- The creation of any vital threads or child processes - since the forkserver 104 can't clone them easily. 105 106- The initialization of timers via `setitimer()` or equivalent calls. 107 108- The creation of temporary files, network sockets, offset-sensitive file 109 descriptors, and similar shared-state resources - but only provided that their 110 state meaningfully influences the behavior of the program later on. 111 112- Any access to the fuzzed input, including reading the metadata about its size. 113 114With the location selected, add this code in the appropriate spot: 115 116```c 117#ifdef __AFL_HAVE_MANUAL_CONTROL 118 __AFL_INIT(); 119#endif 120``` 121 122You don't need the #ifdef guards, but including them ensures that the program 123will keep working normally when compiled with a tool other than afl-clang-fast/ 124afl-clang-lto/afl-gcc-fast. 125 126Finally, recompile the program with afl-clang-fast/afl-clang-lto/afl-gcc-fast 127(afl-gcc or afl-clang will *not* generate a deferred-initialization binary) - 128and you should be all set! 129 130## 4) Persistent mode 131 132Some libraries provide APIs that are stateless, or whose state can be reset in 133between processing different input files. When such a reset is performed, a 134single long-lived process can be reused to try out multiple test cases, 135eliminating the need for repeated `fork()` calls and the associated OS overhead. 136 137The basic structure of the program that does this would be: 138 139```c 140 while (__AFL_LOOP(1000)) { 141 142 /* Read input data. */ 143 /* Call library code to be fuzzed. */ 144 /* Reset state. */ 145 146 } 147 148 /* Exit normally. */ 149``` 150 151The numerical value specified within the loop controls the maximum number of 152iterations before AFL++ will restart the process from scratch. This minimizes 153the impact of memory leaks and similar glitches; 1000 is a good starting point, 154and going much higher increases the likelihood of hiccups without giving you any 155real performance benefits. 156 157A more detailed template is shown in 158[utils/persistent_mode](../utils/persistent_mode). Similarly to the deferred 159initialization, the feature works only with afl-clang-fast; `#ifdef` guards can 160be used to suppress it when using other compilers. 161 162Note that as with the deferred initialization, the feature is easy to misuse; if 163you do not fully reset the critical state, you may end up with false positives 164or waste a whole lot of CPU power doing nothing useful at all. Be particularly 165wary of memory leaks and of the state of file descriptors. 166 167When running in this mode, the execution paths will inherently vary a bit 168depending on whether the input loop is being entered for the first time or 169executed again. 170 171## 5) Shared memory fuzzing 172 173You can speed up the fuzzing process even more by receiving the fuzzing data via 174shared memory instead of stdin or files. This is a further speed multiplier of 175about 2x. 176 177Setting this up is very easy: 178 179After the includes set the following macro: 180 181```c 182__AFL_FUZZ_INIT(); 183``` 184 185Directly at the start of main - or if you are using the deferred forkserver with 186`__AFL_INIT()`, then *after* `__AFL_INIT()`: 187 188```c 189 unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; 190``` 191 192Then as first line after the `__AFL_LOOP` while loop: 193 194```c 195 int len = __AFL_FUZZ_TESTCASE_LEN; 196``` 197 198And that is all!