Skip to content

Commit

Permalink
Use listings for baby_fuzzer book chapter (#1289)
Browse files Browse the repository at this point in the history
* Clarify setup steps for the baby fuzzer

Specifically:
- Explicitly mention that the dependency path must point to a specific
  directory in the cloned repo (and not the root directory)
- Explicitly mention how to manually trigger the panic in the harness
  for testing purposes

* Clean up documentation on the baby fuzzer

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.

* Fix code snippet attributes for baby fuzzer

Specifically:
- Remove unnecessary `compile_fail` attribute
- Add `ignore` attribute to the snippets of the complete baby fuzzer. As
  explained in [#1290], it is expected for the baby fuzzer to return a
  non-0 exit code, so this should not trigger a failure during `mdbook
  test`.

* Fix CLI snippet language

For CLI snippets, the "language" should be set to `console`.

* Remove nested safe block in baby_fuzzer listings
  • Loading branch information
kokkonisd committed May 24, 2023
1 parent 5a6d683 commit 89876f2
Show file tree
Hide file tree
Showing 14 changed files with 522 additions and 210 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 <you@example.com>"]
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 <you@example.com>"]
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 <you@example.com>"]
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 <you@example.com>"]
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 <you@example.com>"]
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", &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 <you@example.com>"]
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 89876f2

Please sign in to comment.