FRET-LibAFL/libafl_libfuzzer
Aarnav eff40320eb
Add Stoppable trait to State which exposes an API to stop the fuzzer (#2325)
* 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
2024-07-02 17:45:20 +02:00
..

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, with n = 1 enabling deduplication of crashes by stacktrace.
  • -grimoire=n, with n 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
  • -report=n, with n = 1 causing libafl_libfuzzer to emit a report on the corpus content.
  • -skip_tracing=n, with n = 1 causing libafl_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, with n = 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)
  • -dict
  • -fork and -jobs
    • in libafl_libfuzzer, these are synonymous
  • -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
  • -rss_limit_mb and -malloc_limit_mb
  • -ignore_remaining_args
  • -shrink
  • -runs
  • -close_fd_mask