
* add HasStopNext to State which exposes an API to stop the fuzzer. Stops the fuzzer in fuzz_loop or fuzz_loop_for when set to true * fix import * rename HasStopNext to HasShouldStopFuzzing and stop_next to should_stop_fuzzing * added HasShouldStopFuzzing trait constraint for libafl_libfuzzer_runtime fuzzer * rename HasShouldStopFuzzing to Stoppable and add it as a type constraint in libafl_libfuzzer report.rs * rename should_stop_fuzzing -> should_stop * introduce Event::Stop * fix prelude import * Call send_exiting when processing Event::Stop in restartable managers * fix clippy * introduce on_shutdown function in EventProcessor, a function to exit without saving state gracefully. In contrast with on_restart. * call manager.on_shutdown when stopping in fuzz_loop due to state.should_stop * Add missing on_shutdown implementations Check after every stage in Stages::perform_all if should exit and do so. * remove specialization * fix doc * introduce EventProcessor constraint in libafl_libfuzzer_runtime run clippy in libafl_libfuzzer_runtime * fix CentralizedEventManager's on_shutdown not calling inner.on_shutdown * fix bugs in CentralizedLauncher that wouldn't allow children to terminate properly * don't call send_exiting when processing Event::Stop since it will be called when calling on_shutdown anyways * clippy * add set_exit_after so broker does not need to inner_mut to set exit_cleanly_after * return Cow<str> from Event::name_detailed instead of a String * fix missing import in libafl_libfuzzer_runtime * add initate_stop and reset_stop to Stoppable trait to superceed should_stop_mut * clippy * typo * rename initate_stop to request_stop, should_stop to stop_requested and reset_stop to discard_stop_request * fix missing import * windows clippy fix * fix broker typo
libafl_libfuzzer
libafl_libfuzzer
is a shim for libFuzzer which may be used in place of libFuzzer in most contexts.
It can be used both as a direct shim for existing libFuzzer-compatible targets which are simply linked with libFuzzer
(e.g., clang -fsanitize=fuzzer
) and as a Rust crate for libfuzzer-sys
-based harnesses.
Background
libafl_libfuzzer
was first developed as a shim in light of the de-facto deprecation of libFuzzer.
Given the widespread use of libFuzzer and that LibAFL already supported most of the instrumentation used by libFuzzer,
we sought to develop a replacement which could directly replace it without much additional effort from the end user.
To do so, libafl_libfuzzer
provides the same interface and uses the same instrumentation as libFuzzer so that
libFuzzer users can change over to a more modern LibAFL-based runtime without needing extensive changes to their
fuzzing environment or updating their harnesses.
Usage
libafl_libfuzzer
currently has known support for Rust, C, and C++ targets on Linux and macOS.
Windows is not currently supported, as we do not currently test or develop for Windows machines, but we will happily
hear what issues you face and patch them as possible.
For both cases, you should install a recent nightly version of Rust via rustup
and add the llvm-tools
component
with rustup component add llvm-tools
.
Usage with Rust harnesses
To use libafl_libfuzzer
on Rust harnesses which use libfuzzer-sys
, all you need to do is change the following line
in your Cargo.toml:
libfuzzer-sys = { version = "...", features = ["your", "features", "here"] }
to
libfuzzer-sys = { version = "0.11.0", features = ["your", "features", "here"], package = "libafl_libfuzzer" }
If, in the case that you want to work with experimental changes, the libfuzzer-best
branch contains the current
experimental best version of libafl_libfuzzer
.
To use the experimental version, use:
libfuzzer-sys = { git = "https://github.com/AFLplusplus/LibAFL.git", branch = "libfuzzer-best", features = ["your", "features", "here"], package = "libafl_libfuzzer" }
As this branch generally offers the highest performance version of libafl_libfuzzer
, we recommend the latter.
Remember to cargo update
often if using the experimental changes, and please submit an issue
if you encounter problems while using libfuzzer-best
!
macOS
On macOS, you will need to add weak linking for some functions in a build.rs
file:
fn main() {
for func in [
"_libafl_main",
"_LLVMFuzzerCustomMutator",
"_LLVMFuzzerCustomCrossOver",
] {
println!("cargo:rustc-link-arg=-Wl,-U,{func}");
}
}
Caveats
Like harnesses built with libfuzzer-sys
, Rust targets which build other libraries (e.g. C/C++ FFI) may not
automatically apply instrumentation.
In addition to installing clang, you may also wish to set the following environmental variables:
CC=clang
CXX=clang++
CFLAGS='-fsanitize=fuzzer-no-link'
CXXFLAGS='-fsanitize=fuzzer-no-link'
Usage as a standalone library (for C/C++/etc.)
The runtime for libafl_libfuzzer
may be used standalone as a direct replacement for libFuzzer with other targets as
well.
To do so, ensure a recent nightly version of Rust is installed, then enter the
libafl_libfuzzer_runtime
folder and build the runtime with the following command:
./build.sh
The static library will be available at libFuzzer.a
in the libafl_libfuzzer_runtime
directory.
If you encounter build failures without clear error outputs that help you resolve the issue, please submit an issue.
This library may now be used in place of libFuzzer.
To do so, change your CFLAGS/CXXFLAGS from -fsanitize=fuzzer
to:
-fsanitize=fuzzer-no-link -L/path/to/libafl_libfuzzer_runtime -lFuzzer
Alternatively, you may directly overwrite the system libFuzzer library and use -fsanitize=fuzzer
as normal.
This changes per system, but on my machine is located at /usr/lib64/clang/16/lib/linux/libclang_rt.fuzzer-x86_64.a
.
Caveats
This standalone library is not compatible with Rust targets; you must instead use the crate-based dependency.
This is due to potential symbol conflict between your harness and the fuzzer runtime, which is resolved by additional
build steps provided in the libafl_libfuzzer
crate itself.
Flags
You can pass additional flags to the libFuzzer runtime in cargo-fuzz
like so:
cargo fuzz run fuzz_target -- -extra_flag=1
When the runtime is used standalone, flags may be passed just like normal libFuzzer.
You will commonly need this for flags such as -ignore_crashes=1
and -timeout=5
. In addition
to partial support of libfuzzer flags, libafl_libfuzzer
offers:
-dedup=n
, withn
= 1 enabling deduplication of crashes by stacktrace.-grimoire=n
, withn
set to 0 or 1 disabling or enabling grimoire mutations, respectively.- if not specified explicitly,
libafl_libfuzzer
will select based on whether existing inputs are UTF-8 - you should disable grimoire if your target is not string-like
- if not specified explicitly,
-report=n
, withn
= 1 causinglibafl_libfuzzer
to emit a report on the corpus content.-skip_tracing=n
, withn
= 1 causinglibafl_libfuzzer
to disable cmplog tracing.- you should do this if your target performs many comparisons on memory sequences which are not contained in the input
-tui=n
, withn
= 1 enabling a graphical terminal interface.- experimental; some users report inconsistent behaviour with tui enabled
Supported flags from libfuzzer
-merge
-minimize_crash
-artifact_prefix
-timeout
- unlike libfuzzer,
libafl_libfuzzer
supports partial second timeouts (e.g.-timeout=.5
)
- unlike libfuzzer,
-dict
-fork
and-jobs
- in
libafl_libfuzzer
, these are synonymous
- in
-ignore_crashes
,-ignore_ooms
, and-ignore_timeouts
- note that setting
-tui=1
enables these flags by default, so you'll need to explicitly mention-ignore_...=0
to disable them
- note that setting
-rss_limit_mb
and-malloc_limit_mb
-ignore_remaining_args
-shrink
-runs
-close_fd_mask