diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index ff1e5f04ba..f0fc339f04 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -18,7 +18,6 @@ use crate::{ observers::ObserversTuple, serde_anymap::{SerdeAny, SerdeAnyMap}, stages::StagesTuple, - tuples::{tuple_list, tuple_list_type}, utils::{current_milliseconds, Rand}, AflError, }; @@ -37,7 +36,6 @@ pub trait StateMetadata: Debug { pub struct State where I: Input, - R: Rand, FT: FeedbacksTuple, { /// How many times the executor ran the harness/target @@ -49,7 +47,7 @@ where // additional_corpuses, maybe another TupleList? // Feedbacks used to evaluate an input feedbacks: FT, - phantom: PhantomData<(I, R)>, + phantom: PhantomData<(R, I)>, } #[cfg(feature = "std")] @@ -58,11 +56,11 @@ where R: Rand, FT: FeedbacksTuple, { - pub fn load_from_directory( + pub fn load_from_directory( &mut self, + executor: &mut E, corpus: &mut C, generator: &mut G, - engine: &mut Engine, manager: &mut EM, in_dir: &Path, ) -> Result<(), AflError> @@ -71,7 +69,6 @@ where C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, - ET: ExecutorsTuple, EM: EventManager, { for entry in fs::read_dir(in_dir)? { @@ -89,24 +86,23 @@ where println!("Loading file {:?} ...", &path); let bytes = fs::read(&path)?; let input = BytesInput::new(bytes); - let fitness = - self.evaluate_input(&input, engine.executor_mut(), corpus, manager)?; + let fitness = self.evaluate_input(&input, executor, corpus, manager)?; if self.add_if_interesting(corpus, input, fitness)?.is_none() { println!("File {:?} was not interesting, skipped.", &path); } } else if attr.is_dir() { - self.load_from_directory(corpus, generator, engine, manager, &path)?; + self.load_from_directory(executor, corpus, generator, manager, &path)?; } } Ok(()) } - pub fn load_initial_inputs( + pub fn load_initial_inputs( &mut self, + executor: &mut E, corpus: &mut C, generator: &mut G, - engine: &mut Engine, manager: &mut EM, in_dirs: &[PathBuf], ) -> Result<(), AflError> @@ -115,11 +111,10 @@ where C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, - ET: ExecutorsTuple, EM: EventManager, { for in_dir in in_dirs { - self.load_from_directory(corpus, generator, engine, manager, in_dir)?; + self.load_from_directory(executor, corpus, generator, manager, in_dir)?; } manager.log( 0, @@ -296,9 +291,9 @@ where pub fn generate_initial_inputs( &mut self, rand: &mut R, + executor: &mut E, corpus: &mut C, generator: &mut G, - engine: &mut Engine, manager: &mut EM, num: usize, ) -> Result<(), AflError> @@ -313,7 +308,7 @@ where let mut added = 0; for _ in 0..num { let input = generator.generate(rand)?; - let fitness = self.evaluate_input(&input, engine.executor_mut(), corpus, manager)?; + let fitness = self.evaluate_input(&input, executor, corpus, manager)?; if !self.add_if_interesting(corpus, input, fitness)?.is_none() { added += 1; } @@ -337,64 +332,6 @@ where } } -#[derive(Clone, Debug)] -pub struct Engine -where - E: Executor + HasObservers, - OT: ObserversTuple, - ET: ExecutorsTuple, - I: Input, -{ - main_executor: E, - additional_executors: ET, - phantom: PhantomData<(OT, I)>, -} - -impl Engine -where - E: Executor + HasObservers, - OT: ObserversTuple, - ET: ExecutorsTuple, - I: Input, -{ - /// Return the executor - pub fn executor(&self) -> &E { - &self.main_executor - } - - /// Return the executor (mutable) - pub fn executor_mut(&mut self) -> &mut E { - &mut self.main_executor - } - - pub fn additional_executors(&self) -> &ET { - &self.additional_executors - } - - pub fn additional_executors_mut(&mut self) -> &mut ET { - &mut self.additional_executors - } - - pub fn with_executors(main_executor: E, additional_executors: ET) -> Self { - Self { - main_executor: main_executor, - additional_executors: additional_executors, - phantom: PhantomData, - } - } -} - -impl Engine -where - E: Executor + HasObservers, - OT: ObserversTuple, - I: Input, -{ - pub fn new(main_executor: E) -> Self { - Self::with_executors(main_executor, tuple_list!()) - } -} - pub trait Fuzzer where ST: StagesTuple, @@ -414,15 +351,15 @@ where fn fuzz_one( &mut self, rand: &mut R, + executor: &mut E, state: &mut State, corpus: &mut C, - engine: &mut Engine, manager: &mut EM, ) -> Result { let (_, idx) = corpus.next(rand)?; self.stages_mut() - .perform_all(rand, state, corpus, engine, manager, idx)?; + .perform_all(rand, executor, state, corpus, manager, idx)?; manager.process(state, corpus)?; Ok(idx) @@ -431,14 +368,14 @@ where fn fuzz_loop( &mut self, rand: &mut R, + executor: &mut E, state: &mut State, corpus: &mut C, - engine: &mut Engine, manager: &mut EM, ) -> Result<(), AflError> { let mut last = current_milliseconds(); loop { - self.fuzz_one(rand, state, corpus, engine, manager)?; + self.fuzz_one(rand, executor, state, corpus, manager)?; let cur = current_milliseconds(); if cur - last > 60 * 100 { last = cur; @@ -514,7 +451,7 @@ mod tests { use crate::{ corpus::{Corpus, InMemoryCorpus, Testcase}, - engines::{Engine, Fuzzer, State, StdFuzzer}, + engines::{Fuzzer, State, StdFuzzer}, executors::{Executor, ExitKind, InMemoryExecutor}, inputs::{BytesInput, Input}, mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}, @@ -554,7 +491,6 @@ mod tests { &mut event_manager, ); - let mut engine = Engine::new(executor); let mut mutator = StdScheduledMutator::new(); mutator.add_mutation(mutation_bitflip); let stage = StdMutationalStage::new(mutator); @@ -564,9 +500,9 @@ mod tests { fuzzer .fuzz_one( &mut rand, + &mut executor, &mut state, &mut corpus, - &mut engine, &mut event_manager, ) .expect(&format!("Error in iter {}", i)); diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs index c5e142baaf..c5d2e928d4 100644 --- a/afl/src/mutators/mutations.rs +++ b/afl/src/mutators/mutations.rs @@ -729,23 +729,26 @@ where // Converts a hex u8 to its u8 value: 'A' -> 10 etc. fn from_hex(hex: u8) -> Result { - - if hex >= 48 && hex <= 57 { return Ok(hex - 48); } - if hex >= 65 && hex <= 70 { return Ok(hex - 55); } - if hex >= 97 && hex <= 102 { return Ok(hex - 87); } + if hex >= 48 && hex <= 57 { + return Ok(hex - 48); + } + if hex >= 65 && hex <= 70 { + return Ok(hex - 55); + } + if hex >= 97 && hex <= 102 { + return Ok(hex - 87); + } return Err(AflError::IllegalArgument("".to_owned())); - } /// Decodes a dictionary token: 'foo\x41\\and\"bar' -> 'fooA\and"bar' pub fn str_decode(item: &str) -> Result, AflError> { - - let mut token : Vec = Vec::new(); - let item : Vec = item.as_bytes().to_vec(); - let backslash : u8 = 92; // '\\' - let mut take_next : bool = false; - let mut take_next_two : u32 = 0; - let mut decoded : u8 = 0; + let mut token: Vec = Vec::new(); + let item: Vec = item.as_bytes().to_vec(); + let backslash: u8 = 92; // '\\' + let mut take_next: bool = false; + let mut take_next_two: u32 = 0; + let mut decoded: u8 = 0; for c in item { if take_next_two == 1 { @@ -770,30 +773,24 @@ pub fn str_decode(item: &str) -> Result, AflError> { } return Ok(token); - } - /// Adds a token to a dictionary, checking it is not a duplicate -pub fn add_token_to_dictionary(dict : &mut Vec>, token: &Vec) -> u32 { - - if dict.contains(token) { return 0; } +pub fn add_token_to_dictionary(dict: &mut Vec>, token: &Vec) -> u32 { + if dict.contains(token) { + return 0; + } dict.push(token.to_vec()); return 1; - } /// Read a dictionary file and return the number of entries read -pub fn read_dict_file( - f: &str, - dict : &mut Vec>, -) -> Result { - +pub fn read_dict_file(f: &str, dict: &mut Vec>) -> Result { let mut entries = 0; println!("Loading dictionary {:?} ...", &f); - let file = File::open(&f)?; // panic if not found + let file = File::open(&f)?; // panic if not found let reader = BufReader::new(file); for line in reader.lines() { @@ -802,46 +799,60 @@ pub fn read_dict_file( // we are only interested in '"..."', not prefixed 'foo = ' let start = line.chars().nth(0); - if line.len() == 0 || start == Some('#') { continue; } + if line.len() == 0 || start == Some('#') { + continue; + } let pos_quote = match line.find("\"") { Some(x) => x, - _ => return Err(AflError::IllegalArgument("Illegal line: ".to_owned() + line)), + _ => { + return Err(AflError::IllegalArgument( + "Illegal line: ".to_owned() + line, + )) + } }; if line.chars().nth(line.len() - 1) != Some('"') { - return Err(AflError::IllegalArgument("Illegal line: ".to_owned() + line)); + return Err(AflError::IllegalArgument( + "Illegal line: ".to_owned() + line, + )); } - // extract item - let item = match line.get(pos_quote + 1 .. line.len() - 1) { + // extract item + let item = match line.get(pos_quote + 1..line.len() - 1) { Some(x) => x, - _ => return Err(AflError::IllegalArgument("Illegal line: ".to_owned() + line)), + _ => { + return Err(AflError::IllegalArgument( + "Illegal line: ".to_owned() + line, + )) + } }; - if item.len() == 0 { continue; } - + if item.len() == 0 { + continue; + } + // decode let token: Vec = match str_decode(item) { Ok(val) => val, - Err(_) => return Err(AflError::IllegalArgument("Illegal line (hex decoding): ".to_owned() + line)), + Err(_) => { + return Err(AflError::IllegalArgument( + "Illegal line (hex decoding): ".to_owned() + line, + )) + } }; println!("Debug: {:?} -> {:?}", item, token); entries += add_token_to_dictionary(dict, &token); - } Ok(entries) - } #[cfg(test)] mod tests { - use crate::{ - mutators::{read_dict_file}, - }; + use crate::mutators::read_dict_file; #[test] fn test_read_dict() { println!("For this testcase to success create \"test.dic\"."); - let mut v : Vec> = Vec::new(); + let mut v: Vec> = Vec::new(); let res = read_dict_file(&"test.dic".to_string(), &mut v).unwrap(); #[cfg(feature = "std")] println!("Dictionary entries: {:?}", res); diff --git a/afl/src/stages/mod.rs b/afl/src/stages/mod.rs index 52ac8ff6b0..bc4fd8e9fd 100644 --- a/afl/src/stages/mod.rs +++ b/afl/src/stages/mod.rs @@ -3,7 +3,7 @@ pub use mutational::StdMutationalStage; use crate::{ corpus::Corpus, - engines::{Engine, State}, + engines::State, events::EventManager, executors::{Executor, ExecutorsTuple, HasObservers}, feedbacks::FeedbacksTuple, @@ -31,9 +31,9 @@ where fn perform( &mut self, rand: &mut R, + executor: &mut E, state: &mut State, corpus: &mut C, - engine: &mut Engine, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError>; @@ -53,9 +53,9 @@ where fn perform_all( &mut self, rand: &mut R, + executor: &mut E, state: &mut State, corpus: &mut C, - engine: &mut Engine, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError>; @@ -77,9 +77,9 @@ where fn perform_all( &mut self, _rand: &mut R, + _executor: &mut E, _state: &mut State, _corpus: &mut C, - _engine: &mut Engine, _manager: &mut EM, _corpus_idx: usize, ) -> Result<(), AflError> { @@ -106,16 +106,16 @@ where fn perform_all( &mut self, rand: &mut R, + executor: &mut E, state: &mut State, corpus: &mut C, - engine: &mut Engine, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError> { self.0 - .perform(rand, state, corpus, engine, manager, corpus_idx)?; + .perform(rand, executor, state, corpus, manager, corpus_idx)?; self.1 - .perform_all(rand, state, corpus, engine, manager, corpus_idx) + .perform_all(rand, executor, state, corpus, manager, corpus_idx) } fn for_each(&self, f: fn(&dyn Stage)) { diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index c836b0dea7..d67dfd23c3 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -9,7 +9,7 @@ use crate::{ mutators::Mutator, observers::ObserversTuple, stages::Corpus, - stages::{Engine, Stage}, + stages::Stage, utils::Rand, AflError, }; @@ -49,9 +49,9 @@ where fn perform_mutational( &mut self, rand: &mut R, + executor: &mut E, state: &mut State, corpus: &mut C, - engine: &mut Engine, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError> { @@ -61,13 +61,12 @@ where self.mutator_mut() .mutate(rand, corpus, &mut input_mut, i as i32)?; - let fitness = - state.evaluate_input(&input_mut, engine.executor_mut(), corpus, manager)?; + let fitness = state.evaluate_input(&input_mut, executor, corpus, manager)?; self.mutator_mut() .post_exec(fitness, &input_mut, i as i32)?; - let observers = engine.executor_mut().observers(); + let observers = executor.observers(); // put all this shit in some overridable function in engine maybe? or in corpus. // consider a corpus that strores new testcases in a temporary queue, for later processing @@ -148,13 +147,13 @@ where fn perform( &mut self, rand: &mut R, + executor: &mut E, state: &mut State, corpus: &mut C, - engine: &mut Engine, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError> { - self.perform_mutational(rand, state, corpus, engine, manager, corpus_idx) + self.perform_mutational(rand, executor, state, corpus, manager, corpus_idx) } } diff --git a/afl/src/utils.rs b/afl/src/utils.rs index 9eef956600..ed3bf1a02e 100644 --- a/afl/src/utils.rs +++ b/afl/src/utils.rs @@ -3,6 +3,7 @@ use alloc::vec::Vec; use core::{cell::RefCell, debug_assert, fmt::Debug, time}; use postcard; +use serde::{Deserialize, Serialize}; use xxhash_rust::xxh3::xxh3_64_with_seed; #[cfg(feature = "std")] @@ -110,7 +111,7 @@ where } /// Ways to get random around here -pub trait Rand: Debug { +pub trait Rand: Debug + Serialize { // Sets the seed of this Rand fn set_seed(&mut self, seed: u64); @@ -200,7 +201,7 @@ pub fn current_nanos() -> u64 { /// XXH3 Based, hopefully speedy, rnd implementation /// -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct Xoshiro256StarRand { rand_seed: [u64; 4], seeded: bool, @@ -255,7 +256,7 @@ impl Xoshiro256StarRand { /// XXH3 Based, hopefully speedy, rnd implementation /// -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct XorShift64Rand { rand_seed: u64, seeded: bool, @@ -296,7 +297,7 @@ impl XorShift64Rand { /// XXH3 Based, hopefully speedy, rnd implementation /// -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct Lehmer64Rand { rand_seed: u128, seeded: bool, @@ -333,7 +334,7 @@ impl Lehmer64Rand { /// Extremely quick rand implementation /// see https://arxiv.org/pdf/2002.11331.pdf -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct RomuTrioRand { x_state: u64, y_state: u64, @@ -375,7 +376,7 @@ impl Rand for RomuTrioRand { } /// see https://arxiv.org/pdf/2002.11331.pdf -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct RomuDuoJrRand { x_state: u64, y_state: u64, @@ -426,7 +427,7 @@ pub fn current_milliseconds() -> u64 { /// fake rand, for testing purposes #[cfg(test)] -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct XKCDRand { val: u64, } diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index 3f8896f351..7248bf12e8 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -1,13 +1,13 @@ #[macro_use] extern crate clap; -use clap::{App, Arg}; + use std::{env, path::PathBuf, process::Command}; use afl::{ corpus::{Corpus, InMemoryCorpus}, engines::{Engine, Fuzzer, State, StdFuzzer}, - events::{EventManager, LlmpEventManager, SimpleStats}, + events::{LlmpEventManager, SimpleStats}, executors::{inmemory::InMemoryExecutor, Executor, ExitKind}, feedbacks::MaxMapFeedback, generators::RandPrintablesGenerator, @@ -18,7 +18,7 @@ use afl::{ shmem::{AflShmem, ShMem}, stages::mutational::StdMutationalStage, tuples::tuple_list, - utils::{deserialize_state_corpus_mgr, serialize_state_corpus_mgr, StdRand}, + utils::{deserialize_state_corpus_mgr, StdRand}, AflError, };