Skip to content

Commit 20f1119

Browse files
authored
libafl_libfuzzer: documentation and build script (#1596)
* add docs; add build script for prepping libFuzzer * clarifications
1 parent a27553d commit 20f1119

File tree

3 files changed

+181
-2
lines changed

3 files changed

+181
-2
lines changed

libafl_libfuzzer/README.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
3+
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
4+
5+
cd "${SCRIPT_DIR}" || exit 1
6+
7+
if ! cargo +nightly --version >& /dev/null; then
8+
echo -e "You must install a recent Rust nightly to build the libafl_libfuzzer runtime!"
9+
exit 1
10+
fi
11+
12+
RUSTC_BIN="$(cargo +nightly rustc -Zunstable-options --print target-libdir)/../bin"
13+
RUST_LLD="${RUSTC_BIN}/rust-lld"
14+
RUST_AR="${RUSTC_BIN}/llvm-ar"
15+
16+
if ! [ -f "${RUST_LLD}" ] && [ -f "${RUST_AR}" ]; then
17+
echo -e "You must install the llvm-tools component: \`rustup component add llvm-tools'"
18+
exit 1
19+
fi
20+
21+
cargo +nightly build --release
22+
23+
tmpdir=""
24+
25+
cleanup() {
26+
rm -rf "${tmpdir}"
27+
exit
28+
}
29+
trap cleanup INT TERM
30+
31+
tmpdir="$(mktemp -d)"
32+
"${RUST_LLD}" -flavor gnu -r --whole-archive target/release/libafl_libfuzzer_runtime.a -o "${tmpdir}/libFuzzer.o"
33+
"${RUST_AR}" cr libFuzzer.a "${tmpdir}/libFuzzer.o"
34+
35+
echo "Done! Wrote the runtime to \`${SCRIPT_DIR}/libFuzzer.a'"
36+
cleanup

libafl_libfuzzer/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
//!
3737
//! - `-dedup=n`, with `n` = 1 enabling deduplication of crashes by stacktrace.
3838
//! - `-grimoire=n`, with `n` set to 0 or 1 disabling or enabling [grimoire] mutations, respectively.
39-
//! - if not specified explicitly, `libafl_libfuzzer` will "guess" which setting is appropriate
39+
//! - if not specified explicitly, `libafl_libfuzzer` will select based on whether existing inputs are UTF-8
4040
//! - you should disable grimoire if your target is not string-like
4141
//! - `-report=n`, with `n` = 1 causing `libafl_libfuzzer` to emit a report on the corpus content.
42-
//! - `-skip_tracing=n`, with `n` = 1 causing `libafl_libfuzzer` to disable comparison log tracing.
42+
//! - `-skip_tracing=n`, with `n` = 1 causing `libafl_libfuzzer` to disable cmplog tracing.
4343
//! - you should do this if your target performs many comparisons on memory sequences which are
4444
//! not contained in the input
4545
//! - `-tui=n`, with `n` = 1 enabling a graphical terminal interface.

0 commit comments

Comments
 (0)