From bc49d946169c3910aea6251339f7f027ba4a8b0d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 11 Feb 2021 15:44:24 +0100 Subject: [PATCH] libfuzzer_dummy --- fuzzers/libfuzzer_dummy/.gitignore | 1 + fuzzers/libfuzzer_dummy/Cargo.toml | 35 +++++++++ fuzzers/libfuzzer_dummy/corpus/test | 1 + fuzzers/libfuzzer_dummy/src/mod.rs | 110 ++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 fuzzers/libfuzzer_dummy/.gitignore create mode 100644 fuzzers/libfuzzer_dummy/Cargo.toml create mode 100644 fuzzers/libfuzzer_dummy/corpus/test create mode 100644 fuzzers/libfuzzer_dummy/src/mod.rs diff --git a/fuzzers/libfuzzer_dummy/.gitignore b/fuzzers/libfuzzer_dummy/.gitignore new file mode 100644 index 0000000000..a977a2ca5b --- /dev/null +++ b/fuzzers/libfuzzer_dummy/.gitignore @@ -0,0 +1 @@ +libpng-* \ No newline at end of file diff --git a/fuzzers/libfuzzer_dummy/Cargo.toml b/fuzzers/libfuzzer_dummy/Cargo.toml new file mode 100644 index 0000000000..3d05f303ca --- /dev/null +++ b/fuzzers/libfuzzer_dummy/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "libfuzzer_dummy" +version = "0.1.0" +authors = ["Andrea Fioraldi "] +edition = "2018" + +[workspace] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = ["std"] +std = [] + +[profile.release] +lto = true +codegen-units = 1 +opt-level = 3 +debug = true + +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +num_cpus = "1.0" + +[dependencies] +clap = "2.32.0" +serde = { version = "1.0", default-features = false, features = ["alloc"] } +postcard = { version = "0.5.1", features = ["alloc"] } +afl = { path = "../../afl/" } + +[[bin]] +name = "libfuzzer" +path = "./src/mod.rs" +test = false +bench = false diff --git a/fuzzers/libfuzzer_dummy/corpus/test b/fuzzers/libfuzzer_dummy/corpus/test new file mode 100644 index 0000000000..739d79706d --- /dev/null +++ b/fuzzers/libfuzzer_dummy/corpus/test @@ -0,0 +1 @@ +0000 diff --git a/fuzzers/libfuzzer_dummy/src/mod.rs b/fuzzers/libfuzzer_dummy/src/mod.rs new file mode 100644 index 0000000000..f2f9c944cf --- /dev/null +++ b/fuzzers/libfuzzer_dummy/src/mod.rs @@ -0,0 +1,110 @@ +//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts +//! The example harness is built for libpng. + +use std::{path::PathBuf}; + +use afl::{ + bolts::{tuples::tuple_list, shmem::AflShmem}, + corpus::{Corpus, InMemoryCorpus}, + events::setup_restarting_mgr, + events::{SimpleStats}, + executors::{inprocess::InProcessExecutor, Executor, ExitKind}, + feedbacks::MaxMapFeedback, + inputs::Input, + mutators::{scheduled::HavocBytesMutator, HasMaxSize}, + observers::StdMapObserver, + stages::mutational::StdMutationalStage, + state::{HasCorpus, State}, + utils::StdRand, + AflError, Fuzzer, StdFuzzer, +}; + +/// The name of the coverage map observer, to find it again in the observer list +const NAME_COV_MAP: &str = "cov_map"; + +static mut __lafl_edges_map: [u8; 32] = [0; 32]; +static __lafl_max_edges_size: u32 = 32; + +/// The wrapped harness function, calling out to the llvm-style libfuzzer harness +fn harness(_executor: &E, buf: &[u8]) -> ExitKind +where + E: Executor, + I: Input, +{ + println!("{:?}", buf); + + unsafe { + __lafl_edges_map[0] = 1; + if buf.len() > 0 && buf[0] == 'a' as u8 { + __lafl_edges_map[2] = 1; + if buf.len() > 1 && buf[1] == 'b' as u8 { + __lafl_edges_map[3] = 1; + std::process::abort(); + } + } + } + ExitKind::Ok +} + +/// The main fn, parsing parameters, and starting the fuzzer +pub fn main() { + fuzz(Some(vec![PathBuf::from("./corpus")]), 1337).expect("An error occurred while fuzzing"); +} + +/// The actual fuzzer +fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { + let mut rand = StdRand::new(0); + // 'While the stats are state, they are usually used in the broker - which is likely never restarted + let stats = SimpleStats::new(|s| println!("{}", s)); + + // The restarting state will spawn the same process again as child, then restartet it each time it crashes. + let (state_opt, mut restarting_mgr) = + setup_restarting_mgr::<_, _, _, _, AflShmem, _>(stats, broker_port).expect("Failed to setup the restarter".into()); + + let edges_observer = + StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { &mut __lafl_edges_map[0] as *mut u8 }, __lafl_max_edges_size as usize); + + let mut state = match state_opt { + Some(s) => s, + None => { + State::new( + InMemoryCorpus::new(), + tuple_list!(MaxMapFeedback::new_with_observer( + &NAME_COV_MAP, + &edges_observer + )), + ) + }, + }; + + println!("We're a client, let's fuzz :)"); + + let mut mutator = HavocBytesMutator::new_default(); + mutator.set_max_size(4096); + let stage = StdMutationalStage::new(mutator); + let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); + + // Create the executor + let mut executor = InProcessExecutor::new( + "Libfuzzer", + harness, + tuple_list!(edges_observer), + &mut state, + &mut restarting_mgr, + ); + + // The actual target run starts here. + + // in case the corpus is empty (on first run), reset + if state.corpus().count() < 1 { + match input { + Some(x) => state + .load_initial_inputs(&mut executor, &mut restarting_mgr, &x) + .expect(&format!("Failed to load initial corpus at {:?}", &x)), + None => (), + } + println!("We imported {} inputs from disk.", state.corpus().count()); + } + + fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr) +}