Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcondiro committed Jan 7, 2025
2 parents 4a696c0 + 719a3c0 commit 6ff478a
Show file tree
Hide file tree
Showing 322 changed files with 7,786 additions and 3,158 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ clap = "4.5.18"
cc = "1.1.21"
cmake = "0.1.51"
document-features = "0.2.10"
fastbloom = { version = "0.8.0", default-features = false }
hashbrown = { version = "0.14.5", default-features = false } # A faster hashmap, nostd compatible
libc = "0.2.159" # For (*nix) libc
libipt = "0.2.0"
Expand Down
3 changes: 3 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
- Related: `MutVecInput` is deprecated in favor of directly using `&mut Vec<u8>`
- Related: `MappedInputFunctionMappingMutator` and `ToMappedInputFunctionMappingMutatorMapper` have been removed as now duplicates of `MappingMutator` (previously `FunctionMappingMutator`) and `ToMappingMutator` (previously `ToFunctionMappingMutatorMapper`)
- Related: `ToOptionMappingMutatorMapper` and `ToFunctionMappingMutatorMapper` have been renamed to `ToOptionalMutator` and `ToMappingMutator` respectively
- `Qemu` cannot be used to initialize `Emulator` directly anymore. Instead, `Qemu` should be initialized through `Emulator` systematically if `Emulator` should be used.
- Related: `EmulatorBuilder` uses a single function to provide a `Qemu` initializer: `EmulatorBuilder::qemu_parameters`. For now, it can be either a `Vec<String>` or a `QemuConfig` instance.
- Related: Qemu's `AsanModule` does not need any special call to `Qemu` init methods anymore. It is now possible to simply initialize `AsanModule` (or `AsanGuestModule`) with a reference to the environment as parameter.

# 0.14.0 -> 0.14.1
- Removed `with_observers` from `Executor` trait.
Expand Down
19 changes: 17 additions & 2 deletions docs/src/core_concepts/executor.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ In Rust, we bind this concept to the [`Executor`](https://docs.rs/libafl/latest/
By default, we implement some commonly used Executors such as [`InProcessExecutor`](https://docs.rs/libafl/latest/libafl/executors/inprocess/type.InProcessExecutor.html) in which the target is a harness function providing in-process crash detection. Another Executor is the [`ForkserverExecutor`](https://docs.rs/libafl/latest/libafl/executors/forkserver/struct.ForkserverExecutor.html) that implements an AFL-like mechanism to spawn child processes to fuzz.

## InProcessExecutor

Let's begin with the base case; `InProcessExecutor`.
This executor executes the harness program (function) inside the fuzzer process.

When you want to execute the harness as fast as possible, you will most probably want to use this `InprocessExecutor`.

One thing to note here is, when your harness is likely to have heap corruption bugs, you want to use another allocator so that corrupted heap does not affect the fuzzer itself. (For example, we adopt MiMalloc in some of our fuzzers.). Alternatively you can compile your harness with address sanitizer to make sure you can catch these heap bugs.
One thing to note here is, when your harness is likely to have heap corruption bugs, you want to use another allocator so that corrupted heap does not affect the fuzzer itself. (For example, we adopt MiMalloc in some of our fuzzers.). Alternatively you can compile your harness with address sanitizer to make sure you can catch these heap bugs.

## ForkserverExecutor

Next, we'll take a look at the `ForkserverExecutor`. In this case, it is `afl-cc` (from AFL/AFLplusplus) that compiles the harness code, and therefore, we can't use `EDGES_MAP` anymore. Fortunately we have [_a way_](https://github.com/AFLplusplus/AFLplusplus/blob/2e15661f184c77ac1fbb6f868c894e946cbb7f17/instrumentation/afl-compiler-rt.o.c#L270) to tell the forkserver which map to record the coverage in.

As you can see from the forkserver example,
Expand All @@ -36,7 +38,7 @@ let mut shmem_buf = shmem.as_slice_mut();

Here we make a shared memory region; `shmem`, and write this to environmental variable `__AFL_SHM_ID`. Then the instrumented binary, or the forkserver, finds this shared memory region (from the aforementioned env var) to record its coverage. On your fuzzer side, you can pass this shmem map to your `Observer` to obtain coverage feedbacks combined with any `Feedback`.

Another feature of the `ForkserverExecutor` to mention is the shared memory testcases. In normal cases, the mutated input is passed between the forkserver and the instrumented binary via `.cur_input` file. You can improve your forkserver fuzzer's performance by passing the input with shared memory.
Another feature of the `ForkserverExecutor` to mention is the shared memory testcases. In normal cases, the mutated input is passed between the forkserver and the instrumented binary via `.cur_input` file. You can improve your forkserver fuzzer's performance by passing the input with shared memory.

If the target is configured to use shared memory testcases, the `ForkserverExecutor` will notice this during the handshake and will automatically set up things accordingly.
See AFL++'s [_documentation_](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.persistent_mode.md#5-shared-memory-fuzzing) or the fuzzer example in `forkserver_simple/src/program.c` for reference.
Expand Down Expand Up @@ -66,3 +68,16 @@ unsafe{
```

Again, you can pass this shmem map to your `Observer` and `Feedback` to obtain coverage feedbacks.

Additionaly to allow the fuzzer to know when the child has crashed, the program should abort instead of unwinding upon a panic.
Without it, no crashes are saved by the fuzzer.

Cargo.toml:

```toml
[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
```
6 changes: 5 additions & 1 deletion fuzzers/baby/baby_fuzzer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ use libafl_bolts::{current_nanos, nonzero, rands::StdRand, tuples::tuple_list, A

/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() };

/// Assign a signal to the signals map
fn signals_set(idx: usize) {
unsafe { write(SIGNALS_PTR.add(idx), 1) };
}

#[allow(clippy::similar_names, clippy::manual_assert)]
#[expect(clippy::manual_assert)]
pub fn main() {
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
Expand Down Expand Up @@ -61,6 +63,8 @@ pub fn main() {
};

// Create an observation channel using the signals map
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };

// Feedback to rate the interestingness of an input
Expand Down
3 changes: 2 additions & 1 deletion fuzzers/baby/baby_fuzzer_custom_executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ authors = [
edition = "2021"

[features]
default = ["std"]
default = ["std", "bloom_input_filter"]
tui = ["libafl/tui_monitor"]
bloom_input_filter = ["std"]
std = []

[profile.dev]
Expand Down
9 changes: 7 additions & 2 deletions fuzzers/baby/baby_fuzzer_custom_executor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use libafl_bolts::{current_nanos, nonzero, rands::StdRand, tuples::tuple_list, A
/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
static mut SIGNALS_PTR: *mut u8 = &raw mut SIGNALS as _;
static SIGNALS_LEN: usize = unsafe { (*&raw const (SIGNALS)).len() };
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
static SIGNALS_LEN: usize = unsafe { SIGNALS.len() };

/// Assign a signal to the signals map
fn signals_set(idx: usize) {
Expand Down Expand Up @@ -81,7 +83,6 @@ where
}
}

#[allow(clippy::similar_names, clippy::manual_assert)]
pub fn main() {
// Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS_LEN) };
Expand Down Expand Up @@ -133,7 +134,11 @@ pub fn main() {
let scheduler = QueueScheduler::new();

// A fuzzer with feedbacks and a corpus scheduler
#[cfg(not(feature = "bloom_input_filter"))]
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(feature = "bloom_input_filter")]
let mut fuzzer =
StdFuzzer::with_bloom_input_filter(scheduler, feedback, objective, 10_000_000, 0.001);

// Create the executor for an in-process function with just one observer
let executor = CustomExecutor::new(&state);
Expand Down
5 changes: 4 additions & 1 deletion fuzzers/baby/baby_fuzzer_minimizing/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ use libafl_bolts::prelude::*;

/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() };

/// Assign a signal to the signals map
fn signals_set(idx: usize) {
unsafe { write(SIGNALS_PTR.add(idx), 1) };
}

#[allow(clippy::similar_names)]
pub fn main() -> Result<(), Error> {
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
Expand All @@ -34,6 +35,8 @@ pub fn main() -> Result<(), Error> {
};

// Create an observation channel using the signals map
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };

let factory = MapEqualityFactory::new(&observer);
Expand Down
5 changes: 3 additions & 2 deletions fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ mod slicemap {
#[cfg(not(feature = "multimap"))]
use slicemap::{HitcountsMapObserver, EDGES};

#[allow(clippy::similar_names)]
#[allow(clippy::too_many_lines)]
#[expect(clippy::too_many_lines)]
pub fn main() {
// The closure that we want to fuzz
let mut first_harness = |input: &BytesInput| {
Expand Down Expand Up @@ -144,6 +143,8 @@ pub fn main() {
EDGES = core::slice::from_raw_parts_mut(alloc_zeroed(layout), num_edges * 2);
}

// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem on nightly
let edges_ptr = unsafe { EDGES.as_mut_ptr() };

// create the base maps used to observe the different executors by splitting a slice
Expand Down
6 changes: 4 additions & 2 deletions fuzzers/baby/baby_fuzzer_unicode/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice};
/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 64] = [0; 64];
static mut SIGNALS_PTR: *mut u8 = (&raw mut SIGNALS).cast();
static mut SIGNALS_LEN: usize = unsafe { (*&raw const SIGNALS).len() };
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
static mut SIGNALS_LEN: usize = unsafe { SIGNALS.len() };

/// Assign a signal to the signals map
fn signals_set(idx: usize) {
unsafe { write(SIGNALS_PTR.add(idx), 1) };
}

#[allow(clippy::similar_names, clippy::manual_assert)]
#[expect(clippy::manual_assert)]
pub fn main() {
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ extern "C" {

}

#[allow(clippy::similar_names)]
pub fn main() {
let mut shmem_provider = StdShMemProvider::new().unwrap();
unsafe { create_shmem_array() };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ extern "C" {

}

#[allow(clippy::similar_names)]
pub fn main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
Expand Down
7 changes: 4 additions & 3 deletions fuzzers/baby/backtrace_baby_fuzzers/command_executor/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ use std::env;

fn main() {
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
let mut cmd = cc::Build::new().get_compiler().to_command();
cmd.args(["src/test_command.c", "-o"])
.arg(&format!("{}/test_command", &cwd))
let mut command = cc::Build::new().get_compiler().to_command();
command
.args(["src/test_command.c", "-o"])
.arg(format!("{}/test_command", &cwd))
.arg("-fsanitize=address")
.status()
.unwrap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ use libafl_bolts::{
AsSlice, AsSliceMut,
};

#[allow(clippy::similar_names)]
pub fn main() {
let mut shmem_provider = unix_shmem::UnixShMemProvider::new().unwrap();
let mut signals = shmem_provider.new_shmem(3).unwrap();
Expand Down Expand Up @@ -81,13 +80,16 @@ pub fn main() {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

// Create the executor for an in-process function with just one observer
#[expect(clippy::items_after_statements)]
#[derive(Debug)]
struct MyExecutor {
shmem_id: ShMemId,
timeout: Duration,
}

impl CommandConfigurator<BytesInput> for MyExecutor {
#[allow(unknown_lints)] // stable doesn't even know of the lint
#[allow(clippy::zombie_processes)] // only a problem on nightly
fn spawn_child(&mut self, input: &BytesInput) -> Result<Child, Error> {
let mut command = Command::new("./test_command");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn main() {

Command::new(afl_gcc_path)
.args(["src/program.c", "-o"])
.arg(&format!("{}/target/release/program", &cwd))
.arg(format!("{}/target/release/program", &cwd))
.arg("-fsanitize=address")
.status()
.unwrap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ use libafl_bolts::{
AsSliceMut,
};

#[allow(clippy::similar_names)]
pub fn main() {
const MAP_SIZE: usize = 65536;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ use libafl_bolts::{
nonzero,
ownedref::OwnedRefMut,
rands::StdRand,
shmem::{unix_shmem, ShMem, ShMemProvider},
shmem::{unix_shmem, ShMemProvider},
tuples::tuple_list,
AsSlice, AsSliceMut,
};

#[allow(clippy::similar_names)]
pub fn main() {
let mut shmem_provider = unix_shmem::UnixShMemProvider::new().unwrap();
let mut signals = shmem_provider.new_shmem(16).unwrap();
Expand Down Expand Up @@ -66,6 +65,7 @@ pub fn main() {
};

// Create an observation channel using the signals map

let observer = unsafe { StdMapObserver::from_mut_ptr("signals", signals_ptr, signals_len) };
// Create a stacktrace observer
let bt_observer = BacktraceObserver::new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ use libafl_bolts::{nonzero, rands::StdRand, tuples::tuple_list, AsSlice};

/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() };

/// Assign a signal to the signals map
fn signals_set(idx: usize) {
unsafe { write(SIGNALS_PTR.add(idx), 1) };
}

#[allow(clippy::similar_names)]
pub fn main() {
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
Expand Down Expand Up @@ -59,6 +60,8 @@ pub fn main() {
};

// Create an observation channel using the signals map
// TODO: This will break soon, fix me! See https://github.com/AFLplusplus/LibAFL/issues/2786
#[allow(static_mut_refs)] // only a problem in nightly
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };
// Create a stacktrace observer to add the observers tuple
let bt_observer = BacktraceObserver::owned(
Expand Down
1 change: 1 addition & 0 deletions fuzzers/baby/tutorial/src/input.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![expect(unexpected_cfgs)] // deriving NewFuzzed etc. introduces these
use std::hash::Hash;

use lain::prelude::*;
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/binary_only/frida_executable_libpng/src/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub unsafe fn lib(main: extern "C" fn(i32, *const *const u8, *const *const u8) -
}

/// The actual fuzzer
#[allow(clippy::too_many_lines, clippy::too_many_arguments)]
#[expect(clippy::too_many_lines)]
unsafe fn fuzz(
options: &FuzzerOptions,
mut frida_harness: &dyn Fn(&BytesInput) -> ExitKind,
Expand Down
1 change: 0 additions & 1 deletion fuzzers/binary_only/frida_executable_libpng/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ pub unsafe extern "C" fn main_hook(
}

#[no_mangle]
#[allow(clippy::similar_names)]
pub unsafe extern "C" fn __libc_start_main(
main: extern "C" fn(i32, *const *const u8, *const *const u8) -> i32,
argc: i32,
Expand Down
Loading

0 comments on commit 6ff478a

Please sign in to comment.