afl.rs

repository·master·Indexed 23 days ago

https://github.com/rust-fuzz/afl.rs

A toolset for fuzzing Rust code with AFL++ (American Fuzzy Lop++), featuring the cargo-afl subcommand. It automates the configuration of RUSTFLAGS, LLVM plugins, and sanitizer coverage. The library provides macros like fuzz!, fuzz_with_reset!, and IJON instrumentation (e.g., ijon_max, ijon_hashint) to improve code coverage and handle static state in persistent mode. Version 0.18.2.

Tokens
3.2K
Snippets
12
Records
25
Agent score
82%

What's inside afl.rs

  1. Use IJON for improved code coverage

    master

    IJON helps improve fuzzer coverage through code annotation. In afl.rs, the IJON macros have been 'rustyfied' to lowercase (e.g., ijon_max(x) instead of IJON_MAX(x)).

    To use IJON, you must import the necessary functions from the afl crate. Common imports include:

    • afl::ijon_hashint
    • afl::ijon_hashstr
    use afl::ijon_hashint;
    use afl::ijon_hashstr;
  2. Optimize system performance for fuzzing

    master
    Before starting a fuzzing campaign, you should reconfigure your system for optimal performance and better crash detection. You can do this using the cargo afl system-config command. Note that this subcommand requires root privileges and will use sudo internally, so you may be prompted for your password.
    cargo afl system-config
  3. Manage CMPLOG instrumentation

    master

    AFL++ CMPLOG is enabled by default to improve code coverage.

    • Running multiple instances: If you are running more than two AFL++ instances on the same target, you should disable CMPLOG to avoid performance issues by specifying the command line parameter -c -.
    • Disabling at build time: To omit CMPLOG instrumentation from the built target entirely, set the environment variable AFLRS_NO_CMPLOG=1 when building.
  4. Manage fuzzing configuration during build

    master
    By default, the fuzzing configuration is applied when using cargo-afl to build. To prevent this and use a different configuration, set the environment variable AFL_NO_CFG_FUZZING=1 during the build process.
  5. Update AFL++ to a specific version or stable

    master

    You can update your AFL++ installation using the --update flag. By default, this updates to the latest stable version. If you need a specific version, provide it with the --tag flag.

    To update to the latest stable version:

    cargo afl config --update

    To update to a specific tag:

    # Note: --tag requires --update
    cargo afl config --update --tag <TAG>
  6. Configure AFL++ with cargo afl config

    master

    If the AFL LLVM runtime was not built for your current Rust version, you will see an error message. You can resolve this by running:

    cargo afl config --build

    This command is used to build, rebuild, or update the AFL++ environment required for fuzzing Rust code.

    cargo afl config --build
  7. Enable LLVM plugins for `cargo-afl`

    master

    To enable the building of LLVM plugins (which are required for features like cmplog), use the --plugins flag during configuration.

    Requirements:

    • You must be using a Nightly Rust toolchain, as cargo-afl must be compiled with nightly to support the plugins feature.
    • The command will attempt to locate llvm-config matching your toolchain's LLVM version to ensure compatibility.
  8. Use `fuzz_with_reset_nohook!` for resettable state

    master
    The fuzz_with_reset_nohook! macro is a variant of fuzz_with_reset! that does not override the panic hook. This is useful if you need to maintain custom panic handling while still resetting static state between iterations.
  9. Use `fuzz_with_reset!` to handle static state in persistent mode

    master

    AFL++ persistent mode runs the fuzz target in a loop. Because static initialization (like OnceLock, lazy_static, or once_cell::Lazy) only executes once, subsequent iterations skip these paths, which can cause AFL's stability metric to drop.

    To fix this, use the fuzz_with_reset! macro. It accepts two closures:

    1. The fuzzing closure: Receives the input data: &[u8] and contains your fuzzing logic.
    2. The reset closure: Executed after each successful iteration to clear or reset your static state.
    use std::sync::Mutex;
    
    static CACHE: Mutex<Option<Vec<u8>>> = Mutex::new(None);
    
    fn main() {
        afl::fuzz_with_reset!(|data: &[u8]| {
            let mut cache = CACHE.lock().unwrap();
            if cache.is_none() {
                *cache = Some(data.to_vec());
            }
            drop(cache);
            // ... fuzz logic ...
        }, || {
            // Reset closure: called after each successful iteration
            *CACHE.lock().unwrap() = None;
        });
    }
  10. Fix shmget() errors with cargo afl system-config

    master

    If you encounter errors such as shmget() failed while running cargo afl fuzz, it typically indicates that the system configuration is not set up correctly. You can fix this by running:

    cargo afl system-config

    Note: This command will prompt for your password as it requires sudo privileges to modify system settings.

    cargo afl system-config
  11. Fuzz a closure with `fuzz()`

    master

    Use the fuzz function to run a closure with a &[u8] slice containing random data provided by the fuzzer. This is the standard way to integrate a fuzzing target. If hook is set to true, panics within the closure will be converted into process aborts to ensure the fuzzer detects them as crashes.

    # extern crate afl;
    # use afl::fuzz;
    fn main() {
        fuzz(true, |data|{
            if data.len() != 6 {return}
            if data[0] != b'q' {return}
            if data[1] != b'w' {return}
            if data[2] != b'e' {return}
            if data[3] != b'r' {return}
            if data[4] != b't' {return}
            if data[5] != b'y' {return}
            panic!("BOOM")
        });
    }