Fix fuzzers in docs, add them to CI (fixes #3185) (#3210)

* Fix fuzzers in docs, add them to CI (fixes #3185)

* ignore macos for now

* Ooops wrong one

* fix?

* clp

---------

Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
This commit is contained in:
Dominik Maier 2025-05-13 14:14:12 +02:00 committed by GitHub
parent 1eb61383d3
commit 2dbf636201
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 5473 additions and 110 deletions

View File

@ -64,6 +64,9 @@ jobs:
- name: Test the book (MacOS)
if: runner.os == 'MacOS'
run: cd docs && mdbook test -L ../target/debug/deps $(python3-config --ldflags | cut -d ' ' -f1)
- name: Build individual libafl book examples (linux)
if: runner.os == 'Linux'
run: cd docs/listings/baby_fuzzer/ && just build-all
- name: Run tests (Windows)
if: runner.os == 'Windows'
run: cargo test -- --test-threads 1

View File

@ -40,6 +40,7 @@ default-members = [
exclude = [
"bindings/pylibafl",
"docs",
"fuzzers",
"libafl_libfuzzer_runtime",
"utils/noaslr",

2
docs/listings/baby_fuzzer/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
target
crashes

View File

@ -0,0 +1,17 @@
# Justfile to build all example projects
default: build-all
build PROJECT:
@echo "Building project in directory: {{PROJECT}}"
@cd {{PROJECT}} && cargo build
@echo "Finished building project in directory: {{PROJECT}}"
build-all: listing-01 listing-02 listing-03 listing-04 listing-05 listing-06
listing-01: (build "listing-01")
listing-02: (build "listing-02")
listing-03: (build "listing-03")
listing-04: (build "listing-04")
listing-05: (build "listing-05")
listing-06: (build "listing-06")

View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "baby_fuzzer_listing_01"
version = "0.15.2"

View File

@ -2,7 +2,7 @@
name = "baby_fuzzer_listing_01"
version = "0.15.2"
authors = ["Your Name <you@example.com>"]
edition = "2018"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

File diff suppressed because it is too large Load Diff

View File

@ -2,20 +2,12 @@
name = "baby_fuzzer_listing_02"
version = "0.15.2"
authors = ["Your Name <you@example.com>"]
edition = "2018"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { path = "path/to/libafl/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
#libafl = { version = ".." }
libafl = { path = "../../../../libafl" }
#libafl_bolts = { version = ".." }
libafl_bolts = { path = "../../../../libafl_bolts" }

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,15 @@
name = "baby_fuzzer_listing_03"
version = "0.15.2"
authors = ["Your Name <you@example.com>"]
edition = "2018"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { path = "path/to/libafl/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[features]
panic = []
test-panic = []
[dependencies]
#libafl = { version = ".." }
libafl = { path = "../../../../libafl" }
#libafl_bolts = { version = ".." }
libafl_bolts = { path = "../../../../libafl_bolts" }

View File

@ -10,9 +10,9 @@ fn main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
if buf.len() > 0 && buf[0] == 'a' as u8 {
if buf.len() > 1 && buf[1] == 'b' as u8 {
if buf.len() > 2 && buf[2] == 'c' as u8 {
if buf.len() > 0 && buf[0] == b'a' {
if buf.len() > 1 && buf[1] == b'b' {
if buf.len() > 2 && buf[2] == b'c' {
panic!("=)");
}
}
@ -21,6 +21,6 @@ fn main() {
};
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
#[cfg(feature = "test-panic")]
harness(&input);
}

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,15 @@
name = "baby_fuzzer_listing_04"
version = "0.15.2"
authors = ["Your Name <you@example.com>"]
edition = "2018"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { path = "path/to/libafl/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[features]
panic = []
test-panic = []
[dependencies]
#libafl = { version = ".." }
libafl = { path = "../../../../libafl" }
#libafl_bolts = { version = ".." }
libafl_bolts = { path = "../../../../libafl_bolts" }

View File

@ -3,10 +3,11 @@ extern crate libafl;
extern crate libafl_bolts;
use std::path::PathBuf;
use libafl::{
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
executors::{ExitKind, inprocess::InProcessExecutor},
fuzzer::StdFuzzer,
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
@ -14,16 +15,16 @@ use libafl::{
schedulers::QueueScheduler,
state::StdState,
};
use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice, nonzero};
use libafl_bolts::{AsSlice, nonzero, rands::StdRand};
/* ANCHOR_END: use */
fn main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
if buf.len() > 0 && buf[0] == 'a' as u8 {
if buf.len() > 1 && buf[1] == 'b' as u8 {
if buf.len() > 2 && buf[2] == 'c' as u8 {
if buf.len() > 0 && buf[0] == b'a' {
if buf.len() > 1 && buf[1] == b'b' {
if buf.len() > 2 && buf[2] == b'c' {
panic!("=)");
}
}
@ -32,7 +33,7 @@ fn main() {
};
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
#[cfg(feature = "test-panic")]
harness(&input);
/* ANCHOR: state */

File diff suppressed because it is too large Load Diff

View File

@ -2,22 +2,15 @@
name = "baby_fuzzer_listing_05"
version = "0.15.2"
authors = ["Your Name <you@example.com>"]
edition = "2018"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { path = "path/to/libafl/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[features]
panic = []
test-panic = []
[dependencies]
#libafl = { version = ".." }
libafl = { path = "../../../../libafl" }
#libafl_bolts = { version = ".." }
libafl_bolts = { path = "../../../../libafl_bolts" }

View File

@ -2,21 +2,22 @@
extern crate libafl;
extern crate libafl_bolts;
use std::path::PathBuf;
use libafl::{
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
executors::{ExitKind, inprocess::InProcessExecutor},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::StdFuzzer,
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
observers::StdMapObserver,
observers::ConstMapObserver,
schedulers::QueueScheduler,
state::StdState,
};
use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice, nonzero};
use std::path::PathBuf;
use libafl_bolts::{AsSlice, nonnull_raw_mut, nonzero, rands::StdRand, tuples::tuple_list};
/* ANCHOR_END: use */
/* ANCHOR: signals */
@ -33,11 +34,11 @@ fn main() {
let target = input.target_bytes();
let buf = target.as_slice();
signals_set(0); // set SIGNALS[0]
if buf.len() > 0 && buf[0] == 'a' as u8 {
if buf.len() > 0 && buf[0] == b'a' {
signals_set(1); // set SIGNALS[1]
if buf.len() > 1 && buf[1] == 'b' as u8 {
if buf.len() > 1 && buf[1] == b'b' {
signals_set(2); // set SIGNALS[2]
if buf.len() > 2 && buf[2] == 'c' as u8 {
if buf.len() > 2 && buf[2] == b'c' {
panic!("=)");
}
}
@ -47,12 +48,12 @@ fn main() {
/* ANCHOR_END: signals */
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
#[cfg(feature = "test-panic")]
harness(&input);
/* ANCHOR: observer */
// Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::new("signals", &mut SIGNALS) };
let observer = unsafe { ConstMapObserver::from_mut_ptr("signals", nonnull_raw_mut!(SIGNALS)) };
/* ANCHOR_END: observer */
/* ANCHOR: state_with_feedback_and_objective */

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,15 @@
name = "baby_fuzzer_listing_06"
version = "0.15.2"
authors = ["Your Name <you@example.com>"]
edition = "2018"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libafl = { path = "path/to/libafl/" }
libafl_bolts = { path = "path/to/libafl_bolts/" }
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
lto = true
codegen-units = 1
opt-level = 3
debug = true
[features]
panic = []
test-panic = []
[dependencies]
#libafl = { version = ".." }
libafl = { path = "../../../../libafl" }
#libafl_bolts = { version = ".." }
libafl_bolts = { path = "../../../../libafl_bolts" }

View File

@ -1,25 +1,25 @@
/* ANCHOR: use */
extern crate libafl;
extern crate libafl_bolts;
use std::num::NonZeroUsize;
use std::path::PathBuf;
use libafl::{
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
executors::{ExitKind, inprocess::InProcessExecutor},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer},
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, HavocScheduledMutator},
observers::StdMapObserver,
mutators::{havoc_mutations, scheduled::HavocScheduledMutator},
observers::ConstMapObserver,
schedulers::QueueScheduler,
stages::mutational::StdMutationalStage,
state::StdState,
};
use libafl_bolts::{rands::StdRand, tuples::tuple_list, AsSlice, nonzero};
use std::path::PathBuf;
use libafl_bolts::{AsSlice, nonnull_raw_mut, nonzero, rands::StdRand, tuples::tuple_list};
/* ANCHOR_END: use */
// Coverage map with explicit assignments due to the lack of instrumentation
@ -35,11 +35,11 @@ fn main() {
let target = input.target_bytes();
let buf = target.as_slice();
signals_set(0); // set SIGNALS[0]
if buf.len() > 0 && buf[0] == 'a' as u8 {
if buf.len() > 0 && buf[0] == b'a' {
signals_set(1); // set SIGNALS[1]
if buf.len() > 1 && buf[1] == 'b' as u8 {
if buf.len() > 1 && buf[1] == b'b' {
signals_set(2); // set SIGNALS[2]
if buf.len() > 2 && buf[2] == 'c' as u8 {
if buf.len() > 2 && buf[2] == b'c' {
panic!("=)");
}
}
@ -48,11 +48,11 @@ fn main() {
};
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
#[cfg(feature = "test-panic")]
harness(&input);
// Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::new("signals", &mut SIGNALS) };
let observer = unsafe { ConstMapObserver::from_mut_ptr("signals", nonnull_raw_mut!(SIGNALS)) };
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer);

View File

@ -98,11 +98,11 @@ impl ForkserverBytesCoverageSugar<'_> {
let mut out_dir = self.output_dir.clone();
if fs::create_dir(&out_dir).is_err() {
log::info!("Out dir at {:?} already exists.", &out_dir);
log::info!("Out dir at {} already exists.", out_dir.display());
assert!(
out_dir.is_dir(),
"Out dir at {:?} is not a valid directory!",
&out_dir
"Out dir at {} is not a valid directory!",
out_dir.display()
);
}
let mut crashes = out_dir.clone();