|
| 1 | +# libafl_libfuzzer |
| 2 | + |
| 3 | +`libafl_libfuzzer` is a shim for [libFuzzer] which may be used in place of libFuzzer in most contexts. |
| 4 | +It can be used both as a direct shim for existing libFuzzer-compatible targets which are simply linked with libFuzzer |
| 5 | +(e.g., `clang -fsanitize=fuzzer`) and as a Rust crate for [`libfuzzer-sys`]-based harnesses. |
| 6 | + |
| 7 | +## Background |
| 8 | + |
| 9 | +`libafl_libfuzzer` was first developed as a shim in light of the [de-facto deprecation of libFuzzer]. |
| 10 | +Given the widespread use of libFuzzer and that LibAFL already supported most of the instrumentation used by libFuzzer, |
| 11 | +we sought to develop a replacement which could directly replace it without much additional effort from the end user. |
| 12 | +To do so, `libafl_libfuzzer` provides the same interface and uses the same instrumentation as libFuzzer so that |
| 13 | +libFuzzer users can change over to a more modern LibAFL-based runtime without needing extensive changes to their |
| 14 | +fuzzing environment or updating their harnesses. |
| 15 | + |
| 16 | +## Usage |
| 17 | + |
| 18 | +`libafl_libfuzzer` currently has known support for Rust, C, and C++ targets on Linux. |
| 19 | +macOS has experimental support, but requires patching of LibAFL which leads to breaking changes elsewhere (ask in the |
| 20 | +Discord for a patch file -- and [let us know what problems you face](https://github.com/AFLplusplus/LibAFL/issues/1564)). |
| 21 | +Windows is not currently supported, as we do not currently test or develop for Windows machines, but [we will happily |
| 22 | +hear what issues you face and patch them as possible](https://github.com/AFLplusplus/LibAFL/issues/1563). |
| 23 | + |
| 24 | +For both cases, you should install a recent **nightly** version of Rust via `rustup` and add the `llvm-tools` component |
| 25 | +with `rustup component add llvm-tools`. |
| 26 | + |
| 27 | +### Usage with Rust harnesses |
| 28 | + |
| 29 | +To use `libafl_libfuzzer` on Rust harnesses which use `libfuzzer-sys`, all you need to do is change the following line |
| 30 | +in your Cargo.toml: |
| 31 | + |
| 32 | +```toml |
| 33 | +libfuzzer-sys = { version = "...", features = ["your", "features", "here"] } |
| 34 | +``` |
| 35 | + |
| 36 | +to |
| 37 | + |
| 38 | +```toml |
| 39 | +libfuzzer-sys = { version = "0.11.0", features = ["your", "features", "here"], package = "libafl_libfuzzer" } |
| 40 | +``` |
| 41 | + |
| 42 | +If, in the case that you want to work with experimental changes, the `libfuzzer-best` branch contains the current |
| 43 | +experimental best version of `libafl_libfuzzer`. |
| 44 | +To use the experimental version, use: |
| 45 | + |
| 46 | +```toml |
| 47 | +libfuzzer-sys = { git = "https://github.com/AFLplusplus/LibAFL.git", branch = "libfuzzer-best", features = ["your", "features", "here"], package = "libafl_libfuzzer" } |
| 48 | +``` |
| 49 | + |
| 50 | +As this branch generally offers the highest performance version of `libafl_libfuzzer`, we recommend the latter. |
| 51 | +Remember to `cargo update` often if using the experimental changes, and please [submit an issue] |
| 52 | +if you encounter problems while using `libfuzzer-best`! |
| 53 | + |
| 54 | +#### Caveats |
| 55 | + |
| 56 | +Like harnesses built with `libfuzzer-sys`, Rust targets which build other libraries (e.g. C/C++ FFI) may not |
| 57 | +automatically apply instrumentation. |
| 58 | +In addition to installing clang, you may also wish to set the following environmental variables: |
| 59 | + |
| 60 | +```bash |
| 61 | +CC=clang |
| 62 | +CXX=clang++ |
| 63 | +CFLAGS='-fsanitize=fuzzer-no-link' |
| 64 | +CXXFLAGS='-fsanitize=fuzzer-no-link' |
| 65 | +``` |
| 66 | + |
| 67 | +### Usage as a standalone library (for C/C++/etc.) |
| 68 | + |
| 69 | +The runtime for `libafl_libfuzzer` may be used standalone as a direct replacement for libFuzzer with other targets as |
| 70 | +well. |
| 71 | +To do so, [ensure a recent nightly version of Rust is installed](https://rustup.rs/), then enter the |
| 72 | +[`libafl_libfuzzer_runtime`](libafl_libfuzzer_runtime) folder and build the runtime with the following command: |
| 73 | + |
| 74 | +```bash |
| 75 | +./build.sh |
| 76 | +``` |
| 77 | + |
| 78 | +The static library will be available at `libFuzzer.a` in the [`libafl_libfuzzer_runtime`](libafl_libfuzzer_runtime) |
| 79 | +directory. |
| 80 | +If you encounter build failures without clear error outputs that help you resolve the issue, please [submit an issue]. |
| 81 | + |
| 82 | +This library may now be used in place of libFuzzer. |
| 83 | +To do so, change your CFLAGS/CXXFLAGS from `-fsanitize=fuzzer` to: |
| 84 | + |
| 85 | +``` |
| 86 | +-fsanitize=fuzzer-no-link -L/path/to/libafl_libfuzzer_runtime -lFuzzer |
| 87 | +``` |
| 88 | + |
| 89 | +Alternatively, you may directly overwrite the system libFuzzer library and use `-fsanitize=fuzzer` as normal. |
| 90 | +This changes per system, but on my machine is located at `/usr/lib64/clang/16/lib/linux/libclang_rt.fuzzer-x86_64.a`. |
| 91 | + |
| 92 | +#### Caveats |
| 93 | + |
| 94 | +This standalone library is _not_ compatible with Rust targets; you must instead use the crate-based dependency. |
| 95 | +This is due to potential symbol conflict between your harness and the fuzzer runtime, which is resolved by additional |
| 96 | +build steps provided in the `libafl_libfuzzer` crate itself. |
| 97 | + |
| 98 | +## Flags |
| 99 | + |
| 100 | +You can pass additional flags to the libFuzzer runtime in `cargo-fuzz` like so: |
| 101 | + |
| 102 | +```bash |
| 103 | +cargo fuzz run fuzz_target -- -extra_flag=1 |
| 104 | +``` |
| 105 | + |
| 106 | +When the runtime is used standalone, flags may be passed just like normal libFuzzer. |
| 107 | + |
| 108 | +You will commonly need this for flags such as `-ignore_crashes=1` and `-timeout=5`. In addition |
| 109 | +to partial support of libfuzzer flags, `libafl_libfuzzer` offers: |
| 110 | + |
| 111 | +- `-dedup=n`, with `n` = 1 enabling deduplication of crashes by stacktrace. |
| 112 | +- `-grimoire=n`, with `n` set to 0 or 1 disabling or enabling [grimoire] mutations, respectively. |
| 113 | + - if not specified explicitly, `libafl_libfuzzer` will select based on whether existing inputs are UTF-8 |
| 114 | + - you should disable grimoire if your target is not string-like |
| 115 | +- `-report=n`, with `n` = 1 causing `libafl_libfuzzer` to emit a report on the corpus content. |
| 116 | +- `-skip_tracing=n`, with `n` = 1 causing `libafl_libfuzzer` to disable cmplog tracing. |
| 117 | + - you should do this if your target performs many comparisons on memory sequences which are |
| 118 | + not contained in the input |
| 119 | +- `-tui=n`, with `n` = 1 enabling a graphical terminal interface. |
| 120 | + - experimental; some users report inconsistent behaviour with tui enabled |
| 121 | + |
| 122 | +### Supported flags from libfuzzer |
| 123 | + |
| 124 | +- `-merge` |
| 125 | +- `-minimize_crash` |
| 126 | +- `-artifact_prefix` |
| 127 | +- `-timeout` |
| 128 | + - unlike libfuzzer, `libafl_libfuzzer` supports partial second timeouts (e.g. `-timeout=.5`) |
| 129 | +- `-dict` |
| 130 | +- `-fork` and `-jobs` |
| 131 | + - in `libafl_libfuzzer`, these are synonymous |
| 132 | +- `-ignore_crashes`, `-ignore_ooms`, and `-ignore_timeouts` |
| 133 | +- `-rss_limit_mb` and `-malloc_limit_mb` |
| 134 | +- `-ignore_remaining_args` |
| 135 | +- `-shrink` |
| 136 | +- `-runs` |
| 137 | +- `-close_fd_mask` |
| 138 | + |
| 139 | +[libFuzzer]: https://llvm.org/docs/LibFuzzer.html |
| 140 | +[`libfuzzer-sys`]: https://docs.rs/libfuzzer-sys/ |
| 141 | +[de-facto deprecation of libFuzzer]: https://llvm.org/docs/LibFuzzer.html#status |
| 142 | +[submit an issue]: https://github.com/AFLplusplus/LibAFL/issues/new/choose |
| 143 | +[grimoire]: https://www.usenix.org/conference/usenixsecurity19/presentation/blazytko |
0 commit comments