From 08a6196f6c4b8e377d159f8624cdf0425f5d1d6d Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 5 Feb 2021 01:06:07 +0100 Subject: [PATCH] moved fuzzer --- afl/src/lib.rs | 187 ++++++++++++++++++++++++++++ afl/src/mutators/mutations.rs | 31 +++-- afl/src/mutators/scheduled.rs | 6 +- afl/src/state/mod.rs | 178 -------------------------- fuzzers/libfuzzer_libpng/src/mod.rs | 4 +- 5 files changed, 213 insertions(+), 193 deletions(-) diff --git a/afl/src/lib.rs b/afl/src/lib.rs index 69335e9c47..fd2bce8418 100644 --- a/afl/src/lib.rs +++ b/afl/src/lib.rs @@ -28,8 +28,125 @@ pub mod utils; use alloc::string::String; use core::fmt; +use corpus::Corpus; +use events::EventManager; +use executors::{Executor, HasObservers}; +use feedbacks::FeedbacksTuple; +use inputs::Input; +use observers::ObserversTuple; +use stages::StagesTuple; +use state::{HasCorpus, State}; +use std::marker::PhantomData; #[cfg(feature = "std")] use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error}; +use utils::{current_milliseconds, Rand}; + +/// The main fuzzer trait. +pub trait Fuzzer +where + ST: StagesTuple, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, + C: Corpus, + I: Input, + R: Rand, +{ + fn stages(&self) -> &ST; + + fn stages_mut(&mut self) -> &mut ST; + + fn fuzz_one( + &mut self, + rand: &mut R, + executor: &mut E, + state: &mut State, + manager: &mut EM, + ) -> Result { + let (_, idx) = state.corpus_mut().next(rand)?; + + self.stages_mut() + .perform_all(rand, executor, state, manager, idx)?; + + manager.process(state)?; + Ok(idx) + } + + fn fuzz_loop( + &mut self, + rand: &mut R, + executor: &mut E, + state: &mut State, + manager: &mut EM, + ) -> Result<(), AflError> { + let mut last = current_milliseconds(); + loop { + self.fuzz_one(rand, executor, state, manager)?; + let cur = current_milliseconds(); + if cur - last > 60 * 100 { + last = cur; + manager.update_stats(state.executions(), state.executions_over_seconds())?; + } + } + } +} + +#[derive(Clone, Debug)] +pub struct StdFuzzer +where + ST: StagesTuple, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, + C: Corpus, + I: Input, + R: Rand, +{ + stages: ST, + phantom: PhantomData<(EM, E, OT, FT, C, I, R)>, +} + +impl Fuzzer + for StdFuzzer +where + ST: StagesTuple, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, + C: Corpus, + I: Input, + R: Rand, +{ + fn stages(&self) -> &ST { + &self.stages + } + + fn stages_mut(&mut self) -> &mut ST { + &mut self.stages + } +} + +impl StdFuzzer +where + ST: StagesTuple, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, + C: Corpus, + I: Input, + R: Rand, +{ + pub fn new(stages: ST) -> Self { + Self { + stages: stages, + phantom: PhantomData, + } + } +} /// Main error struct for AFL #[derive(Debug)] @@ -112,3 +229,73 @@ impl From for AflError { Self::Unknown(format!("Failed to parse Int: {:?}", err)) } } + +// TODO: no_std test +#[cfg(feature = "std")] +#[cfg(test)] +mod tests { + + use crate::{ + corpus::{Corpus, InMemoryCorpus, Testcase}, + executors::{Executor, ExitKind, InMemoryExecutor}, + inputs::{BytesInput, Input}, + mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}, + stages::StdMutationalStage, + state::{HasCorpus, State}, + tuples::tuple_list, + utils::StdRand, + Fuzzer, StdFuzzer, + }; + + #[cfg(feature = "std")] + use crate::events::{LoggerEventManager, SimpleStats}; + + fn harness, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind { + ExitKind::Ok + } + + #[test] + fn test_fuzzer() { + let mut rand = StdRand::new(0); + + let mut corpus = InMemoryCorpus::::new(); + let testcase = Testcase::new(vec![0; 4]).into(); + corpus.add(testcase); + + let mut state = State::new(corpus, tuple_list!()); + + let mut event_manager = LoggerEventManager::new(SimpleStats::new(|s| { + println!("{}", s); + })); + + let mut executor = InMemoryExecutor::new( + "main", + harness, + tuple_list!(), + //Box::new(|_, _, _, _, _| ()), + &mut state, + &mut event_manager, + ); + + let mut mutator = StdScheduledMutator::new(); + mutator.add_mutation(mutation_bitflip); + let stage = StdMutationalStage::new(mutator); + let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); + + for i in 0..1000 { + fuzzer + .fuzz_one(&mut rand, &mut executor, &mut state, &mut event_manager) + .expect(&format!("Error in iter {}", i)); + } + + let state_serialized = postcard::to_allocvec(&state).unwrap(); + let state_deserialized: State, BytesInput, StdRand, ()> = + postcard::from_bytes(state_serialized.as_slice()).unwrap(); + assert_eq!(state.executions(), state_deserialized.executions()); + + let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap(); + let corpus_deserialized: InMemoryCorpus = + postcard::from_bytes(corpus_serialized.as_slice()).unwrap(); + assert_eq!(state.corpus().count(), corpus_deserialized.count()); + } +} diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs index aa8093a71a..7c23e9824e 100644 --- a/afl/src/mutators/mutations.rs +++ b/afl/src/mutators/mutations.rs @@ -482,27 +482,34 @@ where Ok(MutationResult::Mutated) } -/* -// Insert a dictionary token +/* TODO +/// Insert a dictionary token pub fn mutation_tokeninsert( mutator: &mut M, rand: &mut R, - _: &mut S, + state: &mut S, input: &mut I, ) -> Result where M: HasMaxSize, I: Input + HasBytesVec, R: Rand, + S: HasMetadata, { - if mutator.tokens.size() == 0 { return Ok(MutationResult::Skipped); } + let tokens: Vec> = state.metadata().get().unwrap(); + if mutator.tokens.size() == 0 { + return Ok(MutationResult::Skipped); + } let token = &mutator.tokens[rand.below(token.size())]; let token_len = token.size(); let size = input.bytes().len(); let off = if size == 0 { 0 } else { - rand.below(core::cmp::min(size, (mutator.max_size() - token_len) as u64)) as usize + rand.below(core::cmp::min( + size, + (mutator.max_size() - token_len) as u64, + )) as usize } as usize; input.bytes_mut().resize(size + token_len, 0); @@ -510,27 +517,29 @@ where Ok(MutationResult::Mutated) } -// Overwrite with a dictionary token -pub fn mutation_tokenreplace( +/// Overwrite with a dictionary token +pub fn mutation_tokenreplace( mutator: &mut M, rand: &mut R, - _: &C, + state: &S, input: &mut I, ) -> Result where M: HasMaxSize, I: Input + HasBytesVec, R: Rand, + S: HasMetadata, { - if mutator.tokens.size() > len || !len { return Ok(MutationResult::Skipped); } + if mutator.tokens.size() > len || !len { + return Ok(MutationResult::Skipped); + } let token = &mutator.tokens[rand.below(token.size())]; let token_len = token.size(); let size = input.bytes().len(); - let off rand.below((mutator.max_size() - token_len) as u64)) as usize; + let off = rand.below((mutator.max_size() - token_len) as u64) as usize; mem_move(input.bytes_mut(), token, 0, off, len); Ok(MutationResult::Mutated) } - */ pub fn mutation_bytesinsert( diff --git a/afl/src/mutators/scheduled.rs b/afl/src/mutators/scheduled.rs index e42eaaaa2b..9d0cfbe3e2 100644 --- a/afl/src/mutators/scheduled.rs +++ b/afl/src/mutators/scheduled.rs @@ -303,8 +303,10 @@ where scheduled.add_mutation(mutation_bytescopy); scheduled.add_mutation(mutation_bytesswap); - /*scheduled.add_mutation(mutation_tokeninsert); - scheduled.add_mutation(mutation_tokenreplace);*/ + /* TODO + scheduled.add_mutation(mutation_tokeninsert); + scheduled.add_mutation(mutation_tokenreplace); + */ // TODO: custom dictionary (redqueen etc.) diff --git a/afl/src/state/mod.rs b/afl/src/state/mod.rs index 9f6ce208e4..5cc8f52cd5 100644 --- a/afl/src/state/mod.rs +++ b/afl/src/state/mod.rs @@ -17,7 +17,6 @@ use crate::{ inputs::Input, observers::ObserversTuple, serde_anymap::{SerdeAny, SerdeAnyMap}, - stages::StagesTuple, utils::{current_milliseconds, Rand}, AflError, }; @@ -370,180 +369,3 @@ where } } } - -pub trait Fuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - fn stages(&self) -> &ST; - - fn stages_mut(&mut self) -> &mut ST; - - fn fuzz_one( - &mut self, - rand: &mut R, - executor: &mut E, - state: &mut State, - manager: &mut EM, - ) -> Result { - let (_, idx) = state.corpus_mut().next(rand)?; - - self.stages_mut() - .perform_all(rand, executor, state, manager, idx)?; - - manager.process(state)?; - Ok(idx) - } - - fn fuzz_loop( - &mut self, - rand: &mut R, - executor: &mut E, - state: &mut State, - manager: &mut EM, - ) -> Result<(), AflError> { - let mut last = current_milliseconds(); - loop { - self.fuzz_one(rand, executor, state, manager)?; - let cur = current_milliseconds(); - if cur - last > 60 * 100 { - last = cur; - manager.update_stats(state.executions(), state.executions_over_seconds())?; - } - } - } -} - -#[derive(Clone, Debug)] -pub struct StdFuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - stages: ST, - phantom: PhantomData<(EM, E, OT, FT, C, I, R)>, -} - -impl Fuzzer - for StdFuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - fn stages(&self) -> &ST { - &self.stages - } - - fn stages_mut(&mut self) -> &mut ST { - &mut self.stages - } -} - -impl StdFuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - pub fn new(stages: ST) -> Self { - Self { - stages: stages, - phantom: PhantomData, - } - } -} - -// TODO: no_std test -#[cfg(feature = "std")] -#[cfg(test)] -mod tests { - - use crate::{ - corpus::{Corpus, InMemoryCorpus, Testcase}, - executors::{Executor, ExitKind, InMemoryExecutor}, - inputs::{BytesInput, Input}, - mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}, - stages::StdMutationalStage, - state::{Fuzzer, State, StdFuzzer}, - tuples::tuple_list, - utils::StdRand, - }; - - #[cfg(feature = "std")] - use crate::events::{LoggerEventManager, SimpleStats}; - - use super::HasCorpus; - - fn harness, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind { - ExitKind::Ok - } - - #[test] - fn test_fuzzer() { - let mut rand = StdRand::new(0); - - let mut corpus = InMemoryCorpus::::new(); - let testcase = Testcase::new(vec![0; 4]).into(); - corpus.add(testcase); - - let mut state = State::new(corpus, tuple_list!()); - - let mut event_manager = LoggerEventManager::new(SimpleStats::new(|s| { - println!("{}", s); - })); - - let mut executor = InMemoryExecutor::new( - "main", - harness, - tuple_list!(), - //Box::new(|_, _, _, _, _| ()), - &mut state, - &mut event_manager, - ); - - let mut mutator = StdScheduledMutator::new(); - mutator.add_mutation(mutation_bitflip); - let stage = StdMutationalStage::new(mutator); - let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); - - for i in 0..1000 { - fuzzer - .fuzz_one(&mut rand, &mut executor, &mut state, &mut event_manager) - .expect(&format!("Error in iter {}", i)); - } - - let state_serialized = postcard::to_allocvec(&state).unwrap(); - let state_deserialized: State, BytesInput, StdRand, ()> = - postcard::from_bytes(state_serialized.as_slice()).unwrap(); - assert_eq!(state.executions, state_deserialized.executions); - - let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap(); - let corpus_deserialized: InMemoryCorpus = - postcard::from_bytes(corpus_serialized.as_slice()).unwrap(); - assert_eq!(state.corpus().count(), corpus_deserialized.count()); - } -} diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index 84eaeae9e1..e9b15a7e41 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -16,10 +16,10 @@ use afl::{ observers::StdMapObserver, shmem::{AflShmem, ShMem}, stages::mutational::StdMutationalStage, - state::{Fuzzer, HasCorpus, State, StdFuzzer}, + state::{HasCorpus, State}, tuples::tuple_list, utils::{deserialize_state_corpus_mgr, StdRand}, - AflError, + AflError, Fuzzer, StdFuzzer, }; /// The llmp connection from the actual fuzzer to the process supervising it