Skip to content

Commit

Permalink
Clean up documentation on the baby fuzzer
Browse files Browse the repository at this point in the history
Since the baby fuzzer chapter of the documentation is done in a
"tutorial", step-by-step fashion, it would be nice to be able to see
where exactly new lines have to be placed in the existing code. To that
end, the code used in the tutorial is moved to snippets (as is done in
the Rust Book), as it allows for much more convenient maintenance of the
snippets, as well as easy hiding of the non-important code on any given
snippet.

Furthermore, a few minor fixes are applied; a typo on a comment and a
missing unsafe block.
  • Loading branch information
kokkonisd committed May 23, 2023
1 parent 77b7b29 commit 6bca078
Show file tree
Hide file tree
Showing 14 changed files with 510 additions and 214 deletions.
1 change: 1 addition & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
book
!listings/**/*
9 changes: 9 additions & 0 deletions docs/listings/baby_fuzzer/listing-01/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
3 changes: 3 additions & 0 deletions docs/listings/baby_fuzzer/listing-01/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}
20 changes: 20 additions & 0 deletions docs/listings/baby_fuzzer/listing-02/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <[email protected]>"]
edition = "2018"

# 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
3 changes: 3 additions & 0 deletions docs/listings/baby_fuzzer/listing-02/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}
23 changes: 23 additions & 0 deletions docs/listings/baby_fuzzer/listing-03/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <[email protected]>"]
edition = "2018"

# 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 = []
25 changes: 25 additions & 0 deletions docs/listings/baby_fuzzer/listing-03/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
extern crate libafl;
use libafl::{
bolts::AsSlice,
executors::ExitKind,
inputs::{BytesInput, HasTargetBytes},
};

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 {
panic!("=)");
}
}
}
ExitKind::Ok
};
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
harness(&input);
}
23 changes: 23 additions & 0 deletions docs/listings/baby_fuzzer/listing-04/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <[email protected]>"]
edition = "2018"

# 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 = []
85 changes: 85 additions & 0 deletions docs/listings/baby_fuzzer/listing-04/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* ANCHOR: use */
extern crate libafl;

use libafl::{
bolts::{current_nanos, rands::StdRand, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
fuzzer::StdFuzzer,
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
schedulers::QueueScheduler,
state::StdState,
};
use std::path::PathBuf;
/* 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 {
panic!("=)");
}
}
}
ExitKind::Ok
};
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
harness(&input);

/* ANCHOR: state */
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
&mut (),
&mut (),
)
.unwrap();
/* ANCHOR_END: state */

/* ANCHOR: event_manager */
// The Monitor trait defines how the fuzzer stats are displayed to the user
let mon = SimpleMonitor::new(|s| println!("{s}"));

// The event manager handles the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(mon);
/* ANCHOR_END: event_manager */

/* ANCHOR: scheduler_fuzzer */
// A queue policy to get testcasess from the corpus
let scheduler = QueueScheduler::new();

// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, (), ());
/* ANCHOR_END: scheduler_fuzzer */

/* ANCHOR: executor */
// Create the executor for an in-process function
let mut executor = InProcessExecutor::new(&mut harness, (), &mut fuzzer, &mut state, &mut mgr)
.expect("Failed to create the Executor");
/* ANCHOR_END: executor */

/* ANCHOR: generator */
// Generator of printable bytearrays of max size 32
let mut generator = RandPrintablesGenerator::new(32);

// Generate 8 initial inputs
state
.generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8)
.expect("Failed to generate the initial corpus");
/* ANCHOR_END: generator */
}
23 changes: 23 additions & 0 deletions docs/listings/baby_fuzzer/listing-05/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <[email protected]>"]
edition = "2018"

# 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 = []
115 changes: 115 additions & 0 deletions docs/listings/baby_fuzzer/listing-05/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* ANCHOR: use */
extern crate libafl;

use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::StdFuzzer,
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor,
observers::StdMapObserver,
schedulers::QueueScheduler,
state::StdState,
};
use std::path::PathBuf;
/* ANCHOR_END: use */

/* ANCHOR: signals */
// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];

fn signals_set(idx: usize) {
unsafe { SIGNALS[idx] = 1 };
}

fn main() {
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
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 {
signals_set(1); // set SIGNALS[1]
if buf.len() > 1 && buf[1] == 'b' as u8 {
signals_set(2); // set SIGNALS[2]
if buf.len() > 2 && buf[2] == 'c' as u8 {
panic!("=)");
}
}
}
ExitKind::Ok
};
/* ANCHOR_END: signals */
// To test the panic:
let input = BytesInput::new(Vec::from("abc"));
#[cfg(feature = "panic")]
harness(&input);

/* ANCHOR: observer */
// Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::new("signals", unsafe { &mut SIGNALS }) };
/* ANCHOR_END: observer */

/* ANCHOR: state_with_feedback_and_objective */
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new(&observer);

// A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new();

// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
&mut feedback,
&mut objective,
)
.unwrap();
/* ANCHOR_END: state_with_feedback_and_objective */

// The Monitor trait defines how the fuzzer stats are displayed to the user
let mon = SimpleMonitor::new(|s| println!("{s}"));

// The event manager handles the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(mon);

// A queue policy to get testcasess from the corpus
let scheduler = QueueScheduler::new();
/* ANCHOR: state_with_feedback_and_objective */

// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
/* ANCHOR_END: state_with_feedback_and_objective */

/* ANCHOR: executor_with_observer */
// Create the executor for an in-process function with just one observer
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(observer),
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create the Executor");
/* ANCHOR_END: executor_with_observer */

// Generator of printable bytearrays of max size 32
let mut generator = RandPrintablesGenerator::new(32);

// Generate 8 initial inputs
state
.generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8)
.expect("Failed to generate the initial corpus");
/* ANCHOR: signals */
}
/* ANCHOR_END: signals */
23 changes: 23 additions & 0 deletions docs/listings/baby_fuzzer/listing-06/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "baby_fuzzer"
version = "0.1.0"
authors = ["Your Name <[email protected]>"]
edition = "2018"

# 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 = []
Loading

0 comments on commit 6bca078

Please sign in to comment.