From 7a75155e6bbe1c8000d2936ef6b032c33014ea8f Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 15 Feb 2021 10:55:05 +0100 Subject: [PATCH] objective corpus and feedbacks --- afl/src/events/llmp.rs | 61 +++++++++++++++++++++-------- afl/src/events/logger.rs | 19 ++++++--- afl/src/events/mod.rs | 37 ++++++++++++----- afl/src/executors/inprocess.rs | 54 +++++++++++++++++-------- afl/src/executors/mod.rs | 12 ++++-- afl/src/lib.rs | 52 ++++++++++++++++-------- afl/src/mutators/mutations.rs | 2 +- afl/src/mutators/scheduled.rs | 6 +-- afl/src/stages/mod.rs | 41 +++++++++++-------- afl/src/stages/mutational.rs | 41 ++++++++++++------- afl/src/state/mod.rs | 32 +++++++++++---- fuzzers/libfuzzer_libpng/src/mod.rs | 19 +++++++-- 12 files changed, 261 insertions(+), 115 deletions(-) diff --git a/afl/src/events/llmp.rs b/afl/src/events/llmp.rs index 75d3c92997..153db7e7cb 100644 --- a/afl/src/events/llmp.rs +++ b/afl/src/events/llmp.rs @@ -251,9 +251,9 @@ where } // Handle arriving events in the client - fn handle_in_client( + fn handle_in_client( &mut self, - state: &mut State, + state: &mut State, _sender_id: u32, event: Event, ) -> Result<(), AflError> @@ -261,6 +261,8 @@ where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { match event { Event::NewTestcase { @@ -306,11 +308,16 @@ where } } - fn process(&mut self, state: &mut State) -> Result + fn process( + &mut self, + state: &mut State, + ) -> Result where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { // TODO: Get around local event copy by moving handle_in_client let mut events = vec![]; @@ -339,9 +346,9 @@ where Ok(count) } - fn fire( + fn fire( &mut self, - _state: &mut State, + _state: &mut State, event: Event, ) -> Result<(), AflError> where @@ -349,6 +356,8 @@ where FT: FeedbacksTuple, I: Input, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { let serialized = postcard::to_allocvec(&event)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; @@ -359,8 +368,8 @@ where /// Serialize the current state and corpus during an executiont to bytes. /// On top, add the current llmp event manager instance to be restored /// This method is needed when the fuzzer run crashes and has to restart. -pub fn serialize_state_mgr( - state: &State, +pub fn serialize_state_mgr( + state: &State, mgr: &LlmpEventManager, ) -> Result, AflError> where @@ -368,6 +377,8 @@ where FT: FeedbacksTuple, I: Input, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, SH: ShMem, ST: Stats, { @@ -375,18 +386,20 @@ where } /// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)` -pub fn deserialize_state_mgr( +pub fn deserialize_state_mgr( state_corpus_serialized: &[u8], -) -> Result<(State, LlmpEventManager), AflError> +) -> Result<(State, LlmpEventManager), AflError> where C: Corpus, FT: FeedbacksTuple, I: Input, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, SH: ShMem, ST: Stats, { - let tuple: (State, _) = postcard::from_bytes(&state_corpus_serialized)?; + let tuple: (State, _) = postcard::from_bytes(&state_corpus_serialized)?; Ok(( tuple.0, LlmpEventManager::existing_client_from_description(&tuple.1)?, @@ -422,11 +435,16 @@ where } /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. - fn on_restart(&mut self, state: &mut State) -> Result<(), AflError> + fn on_restart( + &mut self, + state: &mut State, + ) -> Result<(), AflError> where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { // First, reset the page to 0 so the next iteration can read read from the beginning of this page unsafe { self.sender.reset() }; @@ -435,24 +453,31 @@ where .send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized) } - fn process(&mut self, state: &mut State) -> Result + fn process( + &mut self, + state: &mut State, + ) -> Result where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { self.llmp_mgr.process(state) } - fn fire( + fn fire( &mut self, - state: &mut State, + state: &mut State, event: Event, ) -> Result<(), AflError> where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { // Check if we are going to crash in the event, in which case we store our current state for the next runner self.llmp_mgr.fire(state, event) @@ -490,13 +515,13 @@ where /// A restarting state is a combination of restarter and runner, that can be used on systems without `fork`. /// The restarter will start a new process each time the child crashes or timeouts. #[cfg(feature = "std")] -pub fn setup_restarting_mgr( +pub fn setup_restarting_mgr( //mgr: &mut LlmpEventManager, stats: ST, broker_port: u16, ) -> Result< ( - Option>, + Option>, LlmpRestartingEventManager, ), AflError, @@ -506,6 +531,8 @@ where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, SH: ShMem, ST: Stats, { @@ -565,7 +592,7 @@ where // Restoring from a previous run, deserialize state and corpus. Some((_sender, _tag, msg)) => { println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); - let (state, mgr): (State, LlmpEventManager) = + let (state, mgr): (State, LlmpEventManager) = deserialize_state_mgr(&msg)?; (Some(state), LlmpRestartingEventManager::new(mgr, sender)) diff --git a/afl/src/events/logger.rs b/afl/src/events/logger.rs index 6d9fa1979d..2dad3c6041 100644 --- a/afl/src/events/logger.rs +++ b/afl/src/events/logger.rs @@ -31,11 +31,16 @@ where I: Input, ST: Stats, //CE: CustomEvent, { - fn process(&mut self, state: &mut State) -> Result + fn process( + &mut self, + state: &mut State, + ) -> Result where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { let count = self.events.len(); while self.events.len() > 0 { @@ -45,15 +50,17 @@ where Ok(count) } - fn fire( + fn fire( &mut self, - _state: &mut State, + _state: &mut State, event: Event, ) -> Result<(), AflError> where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { match Self::handle_in_broker(&mut self.stats, 0, &event)? { BrokerEventResult::Forward => self.events.push(event), @@ -125,9 +132,9 @@ where } // Handle arriving events in the client - fn handle_in_client( + fn handle_in_client( &mut self, - _state: &mut State, + _state: &mut State, _sender_id: u32, event: Event, ) -> Result<(), AflError> @@ -135,6 +142,8 @@ where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { match event { _ => Err(AflError::Unknown(format!( diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index 42ff3be62f..09969b56e9 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -162,11 +162,16 @@ where /// Lookup for incoming events and process them. /// Return the number of processes events or an error - fn process(&mut self, state: &mut State) -> Result + fn process( + &mut self, + state: &mut State, + ) -> Result where C: Corpus, FT: FeedbacksTuple, - R: Rand; + R: Rand, + OC: Corpus, + OFT: FeedbacksTuple; /// Serialize all observers for this type and manager fn serialize_observers(&mut self, observers: &OT) -> Result, AflError> @@ -186,11 +191,16 @@ where /// For restarting event managers, implement a way to forward state to their next peers. #[inline] - fn on_restart(&mut self, _state: &mut State) -> Result<(), AflError> + fn on_restart( + &mut self, + _state: &mut State, + ) -> Result<(), AflError> where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { Ok(()) } @@ -200,15 +210,17 @@ where fn await_restart_safe(&mut self) {} /// Send off an event to the broker - fn fire( + fn fire( &mut self, - _state: &mut State, + _state: &mut State, event: Event, ) -> Result<(), AflError> where C: Corpus, FT: FeedbacksTuple, - R: Rand; + R: Rand, + OC: Corpus, + OFT: FeedbacksTuple; } /// An eventmgr for tests, and as placeholder if you really don't need an event manager. @@ -220,24 +232,31 @@ impl EventManager for NopEventManager where I: Input, { - fn process(&mut self, _state: &mut State) -> Result + fn process( + &mut self, + _state: &mut State, + ) -> Result where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { Ok(0) } - fn fire( + fn fire( &mut self, - _state: &mut State, + _state: &mut State, _event: Event, ) -> Result<(), AflError> where C: Corpus, FT: FeedbacksTuple, R: Rand, + OC: Corpus, + OFT: FeedbacksTuple, { Ok(()) } diff --git a/afl/src/executors/inprocess.rs b/afl/src/executors/inprocess.rs index 2355e5d831..9662d9cced 100644 --- a/afl/src/executors/inprocess.rs +++ b/afl/src/executors/inprocess.rs @@ -54,30 +54,32 @@ where OT: ObserversTuple, { #[inline] - fn pre_exec( + fn pre_exec( &mut self, - _state: &mut State, + _state: &mut State, _event_mgr: &mut EM, _input: &I, ) -> Result<(), AflError> where R: Rand, FT: FeedbacksTuple, + OC: Corpus, + OFT: FeedbacksTuple, C: Corpus, EM: EventManager, { #[cfg(unix)] #[cfg(feature = "std")] unsafe { - set_oncrash_ptrs::(_state, _event_mgr, _input); + set_oncrash_ptrs::(_state, _event_mgr, _input); } Ok(()) } #[inline] - fn post_exec( + fn post_exec( &mut self, - _state: &State, + _state: &State, _event_mgr: &mut EM, _input: &I, ) -> Result<(), AflError> @@ -86,6 +88,8 @@ where FT: FeedbacksTuple, C: Corpus, EM: EventManager, + OC: Corpus, + OFT: FeedbacksTuple, { #[cfg(unix)] #[cfg(feature = "std")] @@ -142,23 +146,25 @@ where /// * `on_crash_fn` - When an in-mem harness crashes, it may safe some state to continue fuzzing later. /// Do that that in this function. The program will crash afterwards. /// * `observers` - the observers observing the target during execution - pub fn new( + pub fn new( name: &'static str, harness_fn: HarnessFunction, observers: OT, - _state: &mut State, + _state: &mut State, _event_mgr: &mut EM, ) -> Self where R: Rand, FT: FeedbacksTuple, + OC: Corpus, + OFT: FeedbacksTuple, C: Corpus, EM: EventManager, { #[cfg(feature = "std")] #[cfg(unix)] unsafe { - setup_crash_handlers::(); + setup_crash_handlers::(); } Self { @@ -229,7 +235,7 @@ pub mod unix_signals { /// This is neede for certain non-rust side effects, as well as unix signal handling. static mut CURRENT_INPUT_PTR: *const c_void = ptr::null(); - pub unsafe extern "C" fn libaflrs_executor_inmem_handle_crash( + pub unsafe extern "C" fn libaflrs_executor_inmem_handle_crash( _sig: c_int, info: siginfo_t, _void: c_void, @@ -237,6 +243,8 @@ pub mod unix_signals { EM: EventManager, C: Corpus, OT: ObserversTuple, + OC: Corpus, + OFT: FeedbacksTuple, FT: FeedbacksTuple, I: Input, R: Rand, @@ -263,7 +271,9 @@ pub mod unix_signals { let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap(); // Make sure we don't crash in the crash handler forever. CURRENT_INPUT_PTR = ptr::null(); - let state = (STATE_PTR as *mut State).as_mut().unwrap(); + let state = (STATE_PTR as *mut State) + .as_mut() + .unwrap(); let mgr = (EVENT_MGR_PTR as *mut EM).as_mut().unwrap(); mgr.fire( state, @@ -282,13 +292,15 @@ pub mod unix_signals { std::process::exit(1); } - pub unsafe extern "C" fn libaflrs_executor_inmem_handle_timeout( + pub unsafe extern "C" fn libaflrs_executor_inmem_handle_timeout( _sig: c_int, _info: siginfo_t, _void: c_void, ) where EM: EventManager, C: Corpus, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, I: Input, @@ -306,7 +318,9 @@ pub mod unix_signals { let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap(); // Make sure we don't crash in the crash handler forever. CURRENT_INPUT_PTR = ptr::null(); - let state = (STATE_PTR as *mut State).as_mut().unwrap(); + let state = (STATE_PTR as *mut State) + .as_mut() + .unwrap(); let mgr = (EVENT_MGR_PTR as *mut EM).as_mut().unwrap(); mgr.fire( @@ -325,13 +339,15 @@ pub mod unix_signals { } #[inline] - pub unsafe fn set_oncrash_ptrs( - state: &mut State, + pub unsafe fn set_oncrash_ptrs( + state: &mut State, event_mgr: &mut EM, input: &I, ) where EM: EventManager, C: Corpus, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, I: Input, @@ -350,10 +366,12 @@ pub mod unix_signals { } // TODO clearly state that manager should be static (maybe put the 'static lifetime?) - pub unsafe fn setup_crash_handlers() + pub unsafe fn setup_crash_handlers() where EM: EventManager, C: Corpus, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, I: Input, @@ -374,7 +392,8 @@ pub mod unix_signals { let mut sa: sigaction = mem::zeroed(); libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK; - sa.sa_sigaction = libaflrs_executor_inmem_handle_crash:: as usize; + sa.sa_sigaction = + libaflrs_executor_inmem_handle_crash:: as usize; for (sig, msg) in &[ (SIGSEGV, "segfault"), (SIGBUS, "sigbus"), @@ -388,7 +407,8 @@ pub mod unix_signals { } } - sa.sa_sigaction = libaflrs_executor_inmem_handle_timeout:: as usize; + sa.sa_sigaction = + libaflrs_executor_inmem_handle_timeout:: as usize; if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 { panic!("Could not set up sigusr2 handler for timeouts"); } diff --git a/afl/src/executors/mod.rs b/afl/src/executors/mod.rs index 4980e43062..5335d89648 100644 --- a/afl/src/executors/mod.rs +++ b/afl/src/executors/mod.rs @@ -82,9 +82,9 @@ where { #[inline] /// Called right before exexution starts - fn pre_exec( + fn pre_exec( &mut self, - _state: &mut State, + _state: &mut State, _event_mgr: &mut EM, _input: &I, ) -> Result<(), AflError> @@ -92,6 +92,8 @@ where R: Rand, FT: FeedbacksTuple, C: Corpus, + OC: Corpus, + OFT: FeedbacksTuple, EM: EventManager, { Ok(()) @@ -99,9 +101,9 @@ where #[inline] /// Called right after execution finished. - fn post_exec( + fn post_exec( &mut self, - _state: &State, + _state: &State, _event_mgr: &mut EM, _input: &I, ) -> Result<(), AflError> @@ -109,6 +111,8 @@ where R: Rand, FT: FeedbacksTuple, C: Corpus, + OC: Corpus, + OFT: FeedbacksTuple, EM: EventManager, { Ok(()) diff --git a/afl/src/lib.rs b/afl/src/lib.rs index 6ef9c35389..069d9971c3 100644 --- a/afl/src/lib.rs +++ b/afl/src/lib.rs @@ -39,11 +39,13 @@ use utils::{current_milliseconds, current_time, Rand}; use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error}; /// The main fuzzer trait. -pub trait Fuzzer +pub trait Fuzzer where - ST: StagesTuple, + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -58,7 +60,7 @@ where &mut self, rand: &mut R, executor: &mut E, - state: &mut State, + state: &mut State, manager: &mut EM, ) -> Result { let (_, idx) = state.corpus_mut().next(rand)?; @@ -74,7 +76,7 @@ where &mut self, rand: &mut R, executor: &mut E, - state: &mut State, + state: &mut State, manager: &mut EM, ) -> Result<(), AflError> { let mut last = current_milliseconds(); @@ -98,11 +100,13 @@ where /// Your default fuzzer instance, for everyday use. #[derive(Clone, Debug)] -pub struct StdFuzzer +pub struct StdFuzzer where - ST: StagesTuple, + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -110,15 +114,17 @@ where R: Rand, { stages: ST, - phantom: PhantomData<(EM, E, OT, FT, C, I, R)>, + phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>, } -impl Fuzzer - for StdFuzzer +impl Fuzzer + for StdFuzzer where - ST: StagesTuple, + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -134,11 +140,13 @@ where } } -impl StdFuzzer +impl StdFuzzer where - ST: StagesTuple, + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -248,12 +256,13 @@ mod tests { mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}, stages::StdMutationalStage, state::{HasCorpus, State}, + stats::SimpleStats, utils::StdRand, Fuzzer, StdFuzzer, }; #[cfg(feature = "std")] - use crate::events::{LoggerEventManager, SimpleStats}; + use crate::events::LoggerEventManager; fn harness, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind { ExitKind::Ok @@ -267,7 +276,12 @@ mod tests { let testcase = Testcase::new(vec![0; 4]).into(); corpus.add(testcase); - let mut state = State::new(corpus, tuple_list!()); + let mut state = State::new( + corpus, + tuple_list!(), + InMemoryCorpus::::new(), + tuple_list!(), + ); let stats = SimpleStats::new(|s| { println!("{}", s); @@ -295,8 +309,14 @@ mod tests { } let state_serialized = postcard::to_allocvec(&state).unwrap(); - let state_deserialized: State, (), BytesInput, StdRand> = - postcard::from_bytes(state_serialized.as_slice()).unwrap(); + let state_deserialized: State< + InMemoryCorpus, + (), + BytesInput, + InMemoryCorpus, + (), + 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(); diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs index c960e97dea..d01ead16e6 100644 --- a/afl/src/mutators/mutations.rs +++ b/afl/src/mutators/mutations.rs @@ -999,7 +999,7 @@ token2="B" corpus.add(BytesInput::new(vec![0x42; 0x1337]).into()); - let mut state = State::new(corpus, ()); + let mut state = State::new(corpus, (), InMemoryCorpus::new(), ()); let mut mutations: Vec> = vec![]; diff --git a/afl/src/mutators/scheduled.rs b/afl/src/mutators/scheduled.rs index fb0901626b..483becef6e 100644 --- a/afl/src/mutators/scheduled.rs +++ b/afl/src/mutators/scheduled.rs @@ -343,7 +343,7 @@ mod tests { .expect("Corpus did not contain entries"); let mut input = testcase.borrow_mut().load_input().unwrap().clone(); - let mut state = State::new(corpus, ()); + let mut state = State::new(corpus, (), InMemoryCorpus::new(), ()); rand.set_seed(5); @@ -351,7 +351,7 @@ mod tests { InMemoryCorpus, _, _, - State<_, (), _, _>, + State<_, (), _, InMemoryCorpus, (), _>, >::new(); mutation_splice(&mut mutator, &mut rand, &mut state, &mut input).unwrap(); @@ -378,7 +378,7 @@ mod tests { let mut input = testcase.borrow_mut().load_input().unwrap().clone(); let input_prior = input.clone(); - let mut state = State::new(corpus, ()); + let mut state = State::new(corpus, (), InMemoryCorpus::new(), ()); let mut havoc = HavocBytesMutator::new(StdScheduledMutator::new()); diff --git a/afl/src/stages/mod.rs b/afl/src/stages/mod.rs index 4031f75b36..78185d75ef 100644 --- a/afl/src/stages/mod.rs +++ b/afl/src/stages/mod.rs @@ -16,10 +16,12 @@ use crate::{ /// A stage is one step in the fuzzing process. /// Multiple stages will be scheduled one by one for each input. -pub trait Stage +pub trait Stage where EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -31,16 +33,18 @@ where &mut self, rand: &mut R, executor: &mut E, - state: &mut State, + state: &mut State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError>; } -pub trait StagesTuple +pub trait StagesTuple where EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -51,18 +55,20 @@ where &mut self, rand: &mut R, executor: &mut E, - state: &mut State, + state: &mut State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError>; - fn for_each(&self, f: fn(&dyn Stage)); - fn for_each_mut(&mut self, f: fn(&mut dyn Stage)); + fn for_each(&self, f: fn(&dyn Stage)); + fn for_each_mut(&mut self, f: fn(&mut dyn Stage)); } -impl StagesTuple for () +impl StagesTuple for () where EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -73,22 +79,25 @@ where &mut self, _rand: &mut R, _executor: &mut E, - _state: &mut State, + _state: &mut State, _manager: &mut EM, _corpus_idx: usize, ) -> Result<(), AflError> { Ok(()) } - fn for_each(&self, _f: fn(&dyn Stage)) {} - fn for_each_mut(&mut self, _f: fn(&mut dyn Stage)) {} + fn for_each(&self, _f: fn(&dyn Stage)) {} + fn for_each_mut(&mut self, _f: fn(&mut dyn Stage)) {} } -impl StagesTuple for (Head, Tail) +impl StagesTuple + for (Head, Tail) where - Head: Stage, - Tail: StagesTuple + TupleList, + Head: Stage, + Tail: StagesTuple + TupleList, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -99,7 +108,7 @@ where &mut self, rand: &mut R, executor: &mut E, - state: &mut State, + state: &mut State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError> { @@ -108,12 +117,12 @@ where .perform_all(rand, executor, state, manager, corpus_idx) } - fn for_each(&self, f: fn(&dyn Stage)) { + fn for_each(&self, f: fn(&dyn Stage)) { f(&self.0); self.1.for_each(f) } - fn for_each_mut(&mut self, f: fn(&mut dyn Stage)) { + fn for_each_mut(&mut self, f: fn(&mut dyn Stage)) { f(&mut self.0); self.1.for_each_mut(f) } diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index f779f4029b..f4f737bad1 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -19,11 +19,14 @@ use crate::{ /// A Mutational stage is the stage in a fuzzing run that mutates inputs. /// Mutational stages will usually have a range of mutations that are /// being applied to the input one by one, between executions. -pub trait MutationalStage: Stage +pub trait MutationalStage: + Stage where - M: Mutator>, + M: Mutator>, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -48,7 +51,7 @@ where &mut self, rand: &mut R, executor: &mut E, - state: &mut State, + state: &mut State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError> { @@ -102,30 +105,34 @@ where #[derive(Clone, Debug)] /// The default mutational stage -pub struct StdMutationalStage +pub struct StdMutationalStage where C: Corpus, E: Executor + HasObservers, EM: EventManager, FT: FeedbacksTuple, I: Input, - M: Mutator>, + M: Mutator>, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, R: Rand, { mutator: M, - phantom: PhantomData<(EM, E, OT, FT, C, I, R)>, + phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>, } -impl MutationalStage - for StdMutationalStage +impl MutationalStage + for StdMutationalStage where C: Corpus, E: Executor + HasObservers, EM: EventManager, FT: FeedbacksTuple, I: Input, - M: Mutator>, + M: Mutator>, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, R: Rand, { @@ -142,12 +149,14 @@ where } } -impl Stage - for StdMutationalStage +impl Stage + for StdMutationalStage where - M: Mutator>, + M: Mutator>, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, @@ -159,7 +168,7 @@ where &mut self, rand: &mut R, executor: &mut E, - state: &mut State, + state: &mut State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError> { @@ -167,11 +176,13 @@ where } } -impl StdMutationalStage +impl StdMutationalStage where - M: Mutator>, + M: Mutator>, EM: EventManager, E: Executor + HasObservers, + OC: Corpus, + OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, C: Corpus, diff --git a/afl/src/state/mod.rs b/afl/src/state/mod.rs index 5ae936ca42..4472177014 100644 --- a/afl/src/state/mod.rs +++ b/afl/src/state/mod.rs @@ -57,12 +57,14 @@ pub trait HasMetadata { /// The state a fuzz run. #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "FT: serde::de::DeserializeOwned")] -pub struct State +pub struct State where C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, + OC: Corpus, + OFT: FeedbacksTuple, { /// How many times the executor ran the harness/target executions: usize, @@ -73,18 +75,24 @@ where start_time: u64, /// Metadata stored for this state by one of the components metadata: SerdeAnyMap, - // additional_corpuses, maybe another TupleList? - // Feedbacks used to evaluate an input + /// Feedbacks used to evaluate an input feedbacks: FT, + // Objective corpus + objective_corpus: OC, + /// Objective Feedbacks + objective_feedbacks: OFT, + phantom: PhantomData<(R, I)>, } #[cfg(feature = "std")] -impl State +impl State where C: Corpus, R: Rand, FT: FeedbacksTuple, + OC: Corpus, + OFT: FeedbacksTuple, { pub fn load_from_directory( &mut self, @@ -153,12 +161,14 @@ where } } -impl HasCorpus for State +impl HasCorpus for State where C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, + OC: Corpus, + OFT: FeedbacksTuple, { /// Returns the corpus fn corpus(&self) -> &C { @@ -172,12 +182,14 @@ where } /// Trait for elements offering metadata -impl HasMetadata for State +impl HasMetadata for State where C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, + OC: Corpus, + OFT: FeedbacksTuple, { /// Get all the metadata into an HashMap #[inline] @@ -192,12 +204,14 @@ where } } -impl State +impl State where C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, + OC: Corpus, + OFT: FeedbacksTuple, { /// Get executions #[inline] @@ -349,13 +363,15 @@ where Ok(()) } - pub fn new(corpus: C, feedbacks: FT) -> Self { + pub fn new(corpus: C, feedbacks: FT, objective_corpus: OC, objective_feedbacks: OFT) -> Self { Self { corpus, executions: 0, start_time: current_milliseconds(), metadata: SerdeAnyMap::default(), feedbacks: feedbacks, + objective_corpus: objective_corpus, + objective_feedbacks: objective_feedbacks, phantom: PhantomData, } } diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index d299bebf02..fdcaa9bd6a 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -5,7 +5,7 @@ use std::{env, path::PathBuf}; use afl::{ bolts::{serdeany::RegistryBuilder, shmem::AflShmem, tuples::tuple_list}, - corpus::{Corpus, InMemoryCorpus}, + corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, events::setup_restarting_mgr, executors::{inprocess::InProcessExecutor, Executor, ExitKind}, feedbacks::MaxMapFeedback, @@ -59,18 +59,27 @@ pub fn main() { "Workdir: {:?}", env::current_dir().unwrap().to_string_lossy().to_string() ); - fuzz(vec![PathBuf::from("./corpus")], 1337).expect("An error occurred while fuzzing"); + fuzz( + vec![PathBuf::from("./corpus")], + PathBuf::from("./crashes"), + 1337, + ) + .expect("An error occurred while fuzzing"); } /// The actual fuzzer -fn fuzz(corpus_dirs: Vec, broker_port: u16) -> Result<(), AflError> { +fn fuzz( + corpus_dirs: Vec, + objective_dir: PathBuf, + 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 restarted it each time it crashes. let (state, mut restarting_mgr) = - setup_restarting_mgr::<_, _, _, _, AflShmem, _>(stats, broker_port) + setup_restarting_mgr::<_, _, _, _, _, _, AflShmem, _>(stats, broker_port) .expect("Failed to setup the restarter".into()); // Create an observation channel using the coverage map @@ -86,6 +95,8 @@ fn fuzz(corpus_dirs: Vec, broker_port: u16) -> Result<(), AflError> { &NAME_COV_MAP, &edges_observer )), + OnDiskCorpus::new(objective_dir), + tuple_list!(), )); println!("We're a client, let's fuzz :)");