diff --git a/afl/src/corpus/testcase.rs b/afl/src/corpus/testcase.rs index 424cb8138f..1512233e47 100644 --- a/afl/src/corpus/testcase.rs +++ b/afl/src/corpus/testcase.rs @@ -24,119 +24,6 @@ pub trait TestcaseMetadata { fn name(&self) -> &'static str; } -pub trait TestcaseTraitTODO -where - I: Input, - T: TestcaseMetadata, -{ - /// The input associated with this testcase - fn input(&self) -> &Option; - - /// The input associated with this testcase (mutable) - fn input_mut(&mut self) -> &mut Option; - - /// Filename, if this testcase is backed by a file in the filesystem - fn filename(&self) -> &Option; - - /// Map of metadatas associated with this testcase - fn metadatas(&self) -> &HashMap<&'static str, Box>; - - /// Map of metadatas associated with this testcase - fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box>; -} - -#[cfg(feature = "std")] -pub enum FileBackedTestcase { - /// A testcase on disk, not yet loaded - Stored { filename: P }, - - /// A testcase that has been loaded, and not yet dirtied. - /// The input should be equal to the on-disk state. - Loaded { - input: I, - filename: P, - //metadatas: HashMap<&'static str, Box>, - }, - - /// A testcase that has been mutated, but not yet written to disk - Dirty { - input: I, - filename: P, - //metadatas: HashMap<&'static str, Box>, - }, -} - -#[cfg(feature = "std")] -impl FileBackedTestcase -where - I: Input, - P: AsRef, -{ - /// Load a testcase from disk if it is not already loaded. - /// - /// # Errors - /// Errors if the testcase is [Dirty](FileBackedTestcase::Dirty) - pub fn load(self) -> Result { - match self { - Self::Stored { filename } => { - let input = I::from_file(&filename)?; - Ok(Self::Loaded { filename, input }) - } - Self::Loaded { - input: _, - filename: _, - } => Ok(self), - _ => Err(AflError::IllegalState( - "Attempted load on dirty testcase".into(), - )), - } - } - - /// Make sure that the in-memory state is syncd to disk, and load it from disk if - /// Nece - pub fn refresh(self) -> Result { - match self { - Self::Dirty { - input: _, - filename: _, - } => self.save(), - other => other.load(), - } - } - - /// Writes changes to disk - pub fn save(self) -> Result { - match self { - Self::Loaded { - input: _, - filename: _, - } => Ok(self), - Self::Dirty { input, filename } => { - let mut file = File::create(&filename)?; - file.write_all(input.serialize()?)?; - - Ok(Self::Loaded { input, filename }) - } - Self::Stored { filename } => Err(AflError::IllegalState(format!( - "Tried to store to {:?} without input (in stored state)", - filename.as_ref() - ))), - } - } - - // Removes contents of this testcase from memory - pub fn unload(self) -> Result { - match self { - Self::Loaded { input: _, filename } => Ok(Self::Stored { filename }), - Self::Stored { filename: _ } => Ok(self), - Self::Dirty { - filename: _, - input: _, - } => self.save(), - } - } -} - /// An entry in the Testcase Corpus #[derive(Default)] pub struct Testcase @@ -147,6 +34,8 @@ where input: Option, /// Filename, if this testcase is backed by a file in the filesystem filename: Option, + /// Accumulated fitness from all the feedbacks + fitness: u32, /// Map of metadatas associated with this testcase metadatas: HashMap<&'static str, Box>, } @@ -186,22 +75,41 @@ where pub fn input_mut(&mut self) -> &mut Option { &mut self.input } + /// Set the input + pub fn set_input(&mut self, input: I) { + self.input = Some(input); + } /// Get the filename, if any pub fn filename(&self) -> &Option { &self.filename } - /// Get the filename, if any (mutable) pub fn filename_mut(&mut self) -> &mut Option { &mut self.filename } + /// Set the filename + pub fn set_filename(&mut self, filename: String) { + self.filename = Some(filename); + } + + /// Get the fitness + pub fn fitness(&self) -> u32 { + self.fitness + } + /// Get the fitness (mutable) + pub fn fitness_mut(&mut self) -> &mut u32 { + &mut self.fitness + } + /// Set the fitness + pub fn set_fitness(&mut self, fitness: u32) { + self.fitness = fitness; + } /// Get all the metadatas into an HashMap (mutable) pub fn metadatas(&mut self) -> &mut HashMap<&'static str, Box> { &mut self.metadatas } - /// Add a metadata pub fn add_metadata(&mut self, meta: Box) { self.metadatas.insert(meta.name(), meta); @@ -215,6 +123,7 @@ where Testcase { input: Some(input.into()), filename: None, + fitness: 0, metadatas: HashMap::default(), } } @@ -224,6 +133,7 @@ where Testcase { input: Some(input), filename: Some(filename), + fitness: 0, metadatas: HashMap::default(), } } @@ -232,6 +142,7 @@ where Testcase { input: None, filename: None, + fitness: 0, metadatas: HashMap::default(), } } diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index e6adadc5af..e5faeffe12 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -13,6 +13,7 @@ use crate::corpus::{Corpus, HasCorpus, Testcase}; use crate::events::EventManager; use crate::executors::Executor; use crate::feedbacks::Feedback; +use crate::generators::Generator; use crate::inputs::Input; use crate::observers::Observer; use crate::stages::Stage; @@ -95,30 +96,68 @@ where fn executor_mut(&mut self) -> &mut E; /// Runs the input and triggers observers and feedback - fn evaluate_input(&mut self, input: &I) -> Result { + fn evaluate_input( + &mut self, + input: I, + ) -> Result<(bool, Option>>>), AflError> { self.reset_observers()?; - self.executor_mut().run_target(input)?; + self.executor_mut().run_target(&input)?; self.set_executions(self.executions() + 1); self.post_exec_observers()?; - let mut rate_acc = 0; + let mut fitness = 0; for feedback in self.feedbacks_mut() { - rate_acc += feedback.is_interesting(input)?; + fitness += feedback.is_interesting(&input)?; } - if rate_acc >= 25 { - let testcase = Rc::new(RefCell::new(Testcase::new(input.clone()))); + if fitness >= 25 { + let testcase: Rc> = Testcase::new(input).into(); for feedback in self.feedbacks_mut() { feedback.append_metadata(testcase.clone())?; } - Ok(true) + testcase.borrow_mut().set_fitness(fitness); + self.corpus_mut().add(testcase.clone()); + Ok((true, Some(testcase))) } else { for feedback in self.feedbacks_mut() { feedback.discard_metadata()?; } - Ok(false) + Ok((false, None)) } } + + fn load_initial_input(&mut self, input: I) -> Result<(), AflError> { + // Inefficent clone, but who cares this is done once at init + let (_, testcase) = self.evaluate_input(input.clone())?; + if testcase.is_none() { + let testcase = Testcase::new(input).into(); + self.corpus_mut().add(testcase); + } + Ok(()) + } +} + +pub fn generate_initial_inputs( + rand: &mut R, + state: &mut S, + generator: &mut G, + _events: &mut EM, + num: usize, +) -> Result<(), AflError> +where + S: State, + G: Generator, + C: Corpus, + E: Executor, + I: Input, + R: Rand, + EM: EventManager, +{ + for _ in 0..num { + let input = generator.generate(rand)?; + state.load_initial_input(input)?; + } + Ok(()) } pub struct StdState @@ -247,12 +286,17 @@ where events: &mut EM, ) -> Result { let (testcase, idx) = state.corpus_mut().next(rand)?; - println!("Cur entry: {}\tExecutions: {}", idx, state.executions()); for stage in self.stages_mut() { stage.perform(rand, state, events, testcase.clone())?; } Ok(idx) } + + fn fuzz_loop(&mut self, rand: &mut R, state: &mut S, events: &mut EM) -> Result<(), AflError> { + loop { + self.fuzz_one(rand, state, events)?; + } + } } pub struct StdEngine diff --git a/afl/src/mutators/mod.rs b/afl/src/mutators/mod.rs index 9f4d235db6..24c195239a 100644 --- a/afl/src/mutators/mod.rs +++ b/afl/src/mutators/mod.rs @@ -5,10 +5,14 @@ pub use scheduled::ScheduledMutator; pub use scheduled::StdScheduledMutator; use crate::corpus::Corpus; +use crate::corpus::Testcase; use crate::inputs::Input; use crate::utils::Rand; use crate::AflError; +use alloc::rc::Rc; +use core::cell::RefCell; + pub trait Mutator where C: Corpus, @@ -25,7 +29,12 @@ where ) -> Result<(), AflError>; /// Post-process given the outcome of the execution - fn post_exec(&mut self, _is_interesting: bool, _stage_idx: i32) -> Result<(), AflError> { + fn post_exec( + &mut self, + _is_interesting: bool, + _new_testcase: Option>>>, + _stage_idx: i32, + ) -> Result<(), AflError> { Ok(()) } } diff --git a/afl/src/mutators/scheduled.rs b/afl/src/mutators/scheduled.rs index b1678b1810..5d15f8fc6e 100644 --- a/afl/src/mutators/scheduled.rs +++ b/afl/src/mutators/scheduled.rs @@ -156,7 +156,7 @@ where /// Bitflip mutation for inputs with a bytes vector pub fn mutation_bitflip( - mutator: &mut M, + _mutator: &mut M, rand: &mut R, _corpus: &mut C, input: &mut I, @@ -190,7 +190,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { /// Splicing mutator pub fn mutation_splice( - mutator: &mut M, + _mutator: &mut M, rand: &mut R, corpus: &mut C, input: &mut I, diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index 2beaf82ace..65f5021448 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -46,20 +46,15 @@ where testcase: Rc>>, ) -> Result<(), AflError> { let num = self.iterations(rand); - let input = testcase.borrow_mut().load_input()?.clone(); - for i in 0..num { - let mut input_tmp = input.clone(); + let mut input = testcase.borrow_mut().load_input()?.clone(); self.mutator_mut() - .mutate(rand, state.corpus_mut(), &mut input_tmp, i as i32)?; + .mutate(rand, state.corpus_mut(), &mut input, i as i32)?; - let interesting = state.evaluate_input(&input_tmp)?; + let (interesting, new_testcase) = state.evaluate_input(input)?; - self.mutator_mut().post_exec(interesting, i as i32)?; - - if interesting { - state.corpus_mut().add(Testcase::new(input_tmp).into()); - } + self.mutator_mut() + .post_exec(interesting, new_testcase, i as i32)?; } Ok(()) } diff --git a/fuzzers/libfuzzer/src/lib.rs b/fuzzers/libfuzzer/src/lib.rs index 90d717fbdd..4c366ebff3 100644 --- a/fuzzers/libfuzzer/src/lib.rs +++ b/fuzzers/libfuzzer/src/lib.rs @@ -8,11 +8,12 @@ use alloc::rc::Rc; use core::cell::RefCell; use afl::corpus::{Corpus, InMemoryCorpus, Testcase}; -use afl::engines::{Engine, State, StdEngine, StdState}; +use afl::engines::{generate_initial_inputs, Engine, State, StdEngine, StdState}; use afl::events::LoggerEventManager; use afl::executors::inmemory::InMemoryExecutor; use afl::executors::{Executor, ExitKind}; use afl::feedbacks::{create_history_map, MaxMapFeedback}; +use afl::generators::{Generator, RandPrintablesGenerator}; use afl::inputs::bytes::BytesInput; use afl::mutators::scheduled::HavocBytesMutator; use afl::observers::StdMapObserver; @@ -42,9 +43,9 @@ fn harness(_executor: &dyn Executor, buf: &[u8]) -> ExitKind { pub extern "C" fn afl_libfuzzer_main() { let mut rand = StdRand::new(0); - let mut corpus = InMemoryCorpus::new(); - let testcase = Testcase::new(vec![0; 4]).into(); - corpus.add(testcase); + let corpus = InMemoryCorpus::new(); + let mut generator = RandPrintablesGenerator::new(4096); + let mut events = LoggerEventManager::new(); let edges_observer = Rc::new(RefCell::new(StdMapObserver::new_from_ptr( unsafe { __lafl_edges_map }, @@ -53,23 +54,22 @@ pub extern "C" fn afl_libfuzzer_main() { let edges_history_map = create_history_map::(MAP_SIZE); let edges_feedback = MaxMapFeedback::new(edges_observer.clone(), edges_history_map); - let executor = InMemoryExecutor::::new(harness); + let executor = InMemoryExecutor::new(harness); let mut state = StdState::new(corpus, executor); state.add_observer(edges_observer); state.add_feedback(Box::new(edges_feedback)); + generate_initial_inputs(&mut rand, &mut state, &mut generator, &mut events, 4) + .expect("Failed to load initial inputs"); + let mut engine = StdEngine::new(); let mutator = HavocBytesMutator::new_default(); let stage = StdMutationalStage::new(mutator); engine.add_stage(Box::new(stage)); - let mut events = LoggerEventManager::new(); - - for i in 0..1000 { - engine - .fuzz_one(&mut rand, &mut state, &mut events) - .expect(&format!("Error in iter {}", i)); - } + engine + .fuzz_loop(&mut rand, &mut state, &mut events) + .expect("Fuzzer fatal error"); #[cfg(feature = "std")] println!("OK"); } diff --git a/fuzzers/libfuzzer/test/test.c b/fuzzers/libfuzzer/test/test.c index ec6674b498..cca0f8e78c 100755 --- a/fuzzers/libfuzzer/test/test.c +++ b/fuzzers/libfuzzer/test/test.c @@ -3,11 +3,11 @@ int target_func(const uint8_t *buf, size_t size) { - printf("BUF (%ld): ", size); + /*printf("BUF (%ld): ", size); for (int i = 0; i < size; i++) { printf("%02X", buf[i]); } - printf("\n"); + printf("\n");*/ switch (buf[0]) {