diff --git a/fuzzers/fuzzbench/src/lib.rs b/fuzzers/fuzzbench/src/lib.rs index a2d23561ba..06134eafc2 100644 --- a/fuzzers/fuzzbench/src/lib.rs +++ b/fuzzers/fuzzbench/src/lib.rs @@ -304,11 +304,12 @@ fn fuzz( 5, )?; - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( &mut state, + &edges_observer, Some(PowerSchedule::EXPLORE), )); diff --git a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs index a5cc74f787..616aae9b33 100644 --- a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs @@ -292,11 +292,12 @@ fn fuzz( 5, )?; - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( &mut state, + &edges_observer, PowerSchedule::FAST, )); diff --git a/fuzzers/fuzzbench_forkserver/src/main.rs b/fuzzers/fuzzbench_forkserver/src/main.rs index efd275581f..fdaf05173b 100644 --- a/fuzzers/fuzzbench_forkserver/src/main.rs +++ b/fuzzers/fuzzbench_forkserver/src/main.rs @@ -294,11 +294,12 @@ fn fuzz( 5, )?; - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( &mut state, + &edges_observer, Some(PowerSchedule::EXPLORE), )); diff --git a/fuzzers/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_qemu/src/fuzzer.rs index c4d28ea577..622bc4bf6c 100644 --- a/fuzzers/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_qemu/src/fuzzer.rs @@ -304,11 +304,12 @@ fn fuzz( 5, )?; - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( &mut state, + &edges_observer, PowerSchedule::FAST, )); diff --git a/fuzzers/fuzzbench_text/src/lib.rs b/fuzzers/fuzzbench_text/src/lib.rs index a4d90d9a4c..0f785ffb79 100644 --- a/fuzzers/fuzzbench_text/src/lib.rs +++ b/fuzzers/fuzzbench_text/src/lib.rs @@ -365,11 +365,12 @@ fn fuzz_binary( 5, )?; - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( &mut state, + &edges_observer, Some(PowerSchedule::EXPLORE), )); @@ -568,7 +569,7 @@ fn fuzz_text( 5, )?; - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); let grimoire_mutator = StdScheduledMutator::with_max_stack_pow( tuple_list!( @@ -586,6 +587,7 @@ fn fuzz_text( // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( &mut state, + &edges_observer, Some(PowerSchedule::EXPLORE), )); diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index 64fa1a9374..7e2653c102 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -142,13 +142,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( &mut state, + &edges_observer, Some(PowerSchedule::FAST), )); diff --git a/fuzzers/libfuzzer_libpng_cmin/src/lib.rs b/fuzzers/libfuzzer_libpng_cmin/src/lib.rs index a6111911d8..ffdec2643d 100644 --- a/fuzzers/libfuzzer_libpng_cmin/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_cmin/src/lib.rs @@ -141,13 +141,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( &mut state, + &edges_observer, Some(PowerSchedule::FAST), )); diff --git a/fuzzers/libfuzzer_windows_asan/src/lib.rs b/fuzzers/libfuzzer_windows_asan/src/lib.rs index e2b0c4f899..66db4f2352 100644 --- a/fuzzers/libfuzzer_windows_asan/src/lib.rs +++ b/fuzzers/libfuzzer_windows_asan/src/lib.rs @@ -107,13 +107,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( &mut state, + &edges_observer, Some(PowerSchedule::FAST), )); diff --git a/fuzzers/tutorial/src/lib.rs b/fuzzers/tutorial/src/lib.rs index c971ca3bd6..8688ea9e8a 100644 --- a/fuzzers/tutorial/src/lib.rs +++ b/fuzzers/tutorial/src/lib.rs @@ -127,13 +127,16 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // Setup a lain mutator with a mutational stage let mutator = LainMutator::new(); - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus - let scheduler = - PacketLenMinimizerScheduler::new(PowerQueueScheduler::new(&mut state, PowerSchedule::FAST)); + let scheduler = PacketLenMinimizerScheduler::new(PowerQueueScheduler::new( + &mut state, + &edges_observer, + PowerSchedule::FAST, + )); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/libafl/src/corpus/testcase.rs b/libafl/src/corpus/testcase.rs index adb200036a..24e2bfb829 100644 --- a/libafl/src/corpus/testcase.rs +++ b/libafl/src/corpus/testcase.rs @@ -300,6 +300,18 @@ impl SchedulerTestcaseMetaData { } } + /// Create new [`struct@SchedulerTestcaseMetaData`] given `n_fuzz_entry` + #[must_use] + pub fn with_n_fuzz_entry(depth: u64, n_fuzz_entry: usize) -> Self { + Self { + bitmap_size: 0, + handicap: 0, + depth, + n_fuzz_entry, + cycle_and_time: (Duration::default(), 0), + } + } + /// Get the bitmap size #[inline] #[must_use] diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index e7ab9a8cb1..4143481e69 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -460,6 +460,9 @@ where { let exit_kind = self.execute_input(state, executor, manager, &input)?; let observers = executor.observers(); + + self.scheduler.on_evaluation(state, &input, observers)?; + self.process_execution(state, manager, input, observers, &exit_kind, send_events) } } diff --git a/libafl/src/schedulers/accounting.rs b/libafl/src/schedulers/accounting.rs index 643175348b..e6b26b5b7b 100644 --- a/libafl/src/schedulers/accounting.rs +++ b/libafl/src/schedulers/accounting.rs @@ -125,13 +125,13 @@ where CS::State: HasCorpus + HasMetadata + HasRand + Debug, ::Input: HasLen, { - fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { + fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { self.update_accounting_score(state, idx)?; self.inner.on_add(state, idx) } fn on_replace( - &self, + &mut self, state: &mut Self::State, idx: CorpusId, testcase: &Testcase<::Input>, @@ -140,7 +140,7 @@ where } fn on_remove( - &self, + &mut self, state: &mut Self::State, idx: CorpusId, testcase: &Option::Input>>, @@ -148,7 +148,7 @@ where self.inner.on_remove(state, idx, testcase) } - fn next(&self, state: &mut Self::State) -> Result { + fn next(&mut self, state: &mut Self::State) -> Result { if state .metadata() .get::() @@ -158,7 +158,7 @@ where } else { self.inner.cull(state)?; } - let mut idx = self.inner.base().next(state)?; + let mut idx = self.inner.base_mut().next(state)?; while { let has = !state .corpus() @@ -168,7 +168,7 @@ where has } && state.rand_mut().below(100) < self.skip_non_favored_prob { - idx = self.inner.base().next(state)?; + idx = self.inner.base_mut().next(state)?; } Ok(idx) } diff --git a/libafl/src/schedulers/minimizer.rs b/libafl/src/schedulers/minimizer.rs index b190482640..5f57a7e27b 100644 --- a/libafl/src/schedulers/minimizer.rs +++ b/libafl/src/schedulers/minimizer.rs @@ -82,14 +82,14 @@ where CS::State: HasCorpus + HasMetadata + HasRand, { /// Add an entry to the corpus and return its index - fn on_add(&self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> { + fn on_add(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> { self.base.on_add(state, idx)?; self.update_score(state, idx) } /// Replaces the testcase at the given idx fn on_replace( - &self, + &mut self, state: &mut CS::State, idx: CorpusId, testcase: &Testcase<::Input>, @@ -100,7 +100,7 @@ where /// Removes an entry from the corpus, returning M if M was present. fn on_remove( - &self, + &mut self, state: &mut CS::State, idx: CorpusId, testcase: &Option::Input>>, @@ -163,7 +163,7 @@ where } /// Gets the next entry - fn next(&self, state: &mut CS::State) -> Result { + fn next(&mut self, state: &mut CS::State) -> Result { self.cull(state)?; let mut idx = self.base.next(state)?; while { @@ -295,6 +295,11 @@ where &self.base } + /// Get a reference to the base scheduler (mut) + pub fn base_mut(&mut self) -> &mut CS { + &mut self.base + } + /// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`] /// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. pub fn new(base: CS) -> Self { diff --git a/libafl/src/schedulers/mod.rs b/libafl/src/schedulers/mod.rs index 2a0a96ea99..b3f72a337f 100644 --- a/libafl/src/schedulers/mod.rs +++ b/libafl/src/schedulers/mod.rs @@ -33,6 +33,7 @@ use crate::{ bolts::rands::Rand, corpus::{Corpus, CorpusId, Testcase}, inputs::UsesInput, + observers::ObserversTuple, random_corpus_id, state::{HasCorpus, HasRand, UsesState}, Error, @@ -42,13 +43,13 @@ use crate::{ /// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data. pub trait Scheduler: UsesState { /// Added an entry to the corpus at the given index - fn on_add(&self, _state: &mut Self::State, _idx: CorpusId) -> Result<(), Error> { + fn on_add(&mut self, _state: &mut Self::State, _idx: CorpusId) -> Result<(), Error> { Ok(()) } /// Replaced the given testcase at the given idx fn on_replace( - &self, + &mut self, _state: &mut Self::State, _idx: CorpusId, _prev: &Testcase<::Input>, @@ -58,7 +59,7 @@ pub trait Scheduler: UsesState { /// Removed the given entry from the corpus at the given index fn on_remove( - &self, + &mut self, _state: &mut Self::State, _idx: CorpusId, _testcase: &Option::Input>>, @@ -66,8 +67,21 @@ pub trait Scheduler: UsesState { Ok(()) } + /// An input has been evaluated + fn on_evaluation( + &mut self, + _state: &mut Self::State, + _input: &::Input, + _observers: &OT, + ) -> Result<(), Error> + where + OT: ObserversTuple, + { + Ok(()) + } + /// Gets the next entry - fn next(&self, state: &mut Self::State) -> Result; + fn next(&mut self, state: &mut Self::State) -> Result; } /// Feed the fuzzer simply with a random testcase on request @@ -88,7 +102,7 @@ where S: HasCorpus + HasRand, { /// Gets the next entry at random - fn next(&self, state: &mut Self::State) -> Result { + fn next(&mut self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty("No entries in corpus".to_owned())) } else { diff --git a/libafl/src/schedulers/powersched.rs b/libafl/src/schedulers/powersched.rs index 442feb8f5c..4ab65b1a6c 100644 --- a/libafl/src/schedulers/powersched.rs +++ b/libafl/src/schedulers/powersched.rs @@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::{ corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase}, inputs::UsesInput, + observers::{MapObserver, ObserversTuple}, schedulers::Scheduler, state::{HasCorpus, HasMetadata, UsesState}, Error, @@ -163,24 +164,27 @@ pub enum PowerSchedule { /// A corpus scheduler using power schedules #[derive(Clone, Debug)] -pub struct PowerQueueScheduler { +pub struct PowerQueueScheduler { strat: PowerSchedule, - phantom: PhantomData, + map_observer_name: String, + last_hash: usize, + phantom: PhantomData<(O, S)>, } -impl UsesState for PowerQueueScheduler +impl UsesState for PowerQueueScheduler where S: UsesInput, { type State = S; } -impl Scheduler for PowerQueueScheduler +impl Scheduler for PowerQueueScheduler where S: HasCorpus + HasMetadata, + O: MapObserver, { /// Add an entry to the corpus and return its index - fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { + fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { let current_idx = *state.corpus().current(); let mut depth = match current_idx { @@ -199,17 +203,15 @@ where // Attach a `SchedulerTestcaseMetaData` to the queue entry. depth += 1; - state - .corpus() - .get(idx)? - .borrow_mut() - .add_metadata(SchedulerTestcaseMetaData::new(depth)); + state.corpus().get(idx)?.borrow_mut().add_metadata( + SchedulerTestcaseMetaData::with_n_fuzz_entry(depth, self.last_hash), + ); Ok(()) } #[allow(clippy::cast_precision_loss)] fn on_replace( - &self, + &mut self, state: &mut Self::State, idx: CorpusId, prev: &Testcase<::Input>, @@ -251,7 +253,7 @@ where #[allow(clippy::cast_precision_loss)] fn on_remove( - &self, + &mut self, state: &mut Self::State, _idx: CorpusId, prev: &Option::Input>>, @@ -288,7 +290,36 @@ where Ok(()) } - fn next(&self, state: &mut Self::State) -> Result { + fn on_evaluation( + &mut self, + state: &mut Self::State, + _input: &::Input, + observers: &OT, + ) -> Result<(), Error> + where + OT: ObserversTuple, + { + let observer = observers + .match_name::(&self.map_observer_name) + .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; + + let mut hash = observer.hash() as usize; + + let psmeta = state + .metadata_mut() + .get_mut::() + .ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?; + + hash %= psmeta.n_fuzz().len(); + // Update the path frequency + psmeta.n_fuzz_mut()[hash] = psmeta.n_fuzz()[hash].saturating_add(1); + + self.last_hash = hash; + + Ok(()) + } + + fn next(&mut self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty(String::from("No entries in corpus"))) } else { @@ -331,18 +362,21 @@ where } } -impl PowerQueueScheduler +impl PowerQueueScheduler where S: HasMetadata, + O: MapObserver, { /// Create a new [`PowerQueueScheduler`] #[must_use] - pub fn new(state: &mut S, strat: PowerSchedule) -> Self { + pub fn new(state: &mut S, map_observer: &O, strat: PowerSchedule) -> Self { if !state.has_metadata::() { state.add_metadata::(SchedulerMetadata::new(Some(strat))); } PowerQueueScheduler { strat, + map_observer_name: map_observer.name().to_string(), + last_hash: 0, phantom: PhantomData, } } diff --git a/libafl/src/schedulers/probabilistic_sampling.rs b/libafl/src/schedulers/probabilistic_sampling.rs index aaacc9f847..8c20e05c46 100644 --- a/libafl/src/schedulers/probabilistic_sampling.rs +++ b/libafl/src/schedulers/probabilistic_sampling.rs @@ -99,7 +99,7 @@ where F: TestcaseScore, S: HasCorpus + HasMetadata + HasRand, { - fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { + fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { if state.metadata().get::().is_none() { state.add_metadata(ProbabilityMetadata::new()); } @@ -108,7 +108,7 @@ where /// Gets the next entry #[allow(clippy::cast_precision_loss)] - fn next(&self, state: &mut Self::State) -> Result { + fn next(&mut self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty(String::from("No entries in corpus"))) } else { @@ -182,7 +182,7 @@ mod tests { // the first 3 probabilities will be .69, .86, .44 let rand = StdRand::with_seed(12); - let scheduler = UniformProbabilitySamplingScheduler::new(); + let mut scheduler = UniformProbabilitySamplingScheduler::new(); let mut feedback = ConstFeedback::new(false); let mut objective = ConstFeedback::new(false); diff --git a/libafl/src/schedulers/queue.rs b/libafl/src/schedulers/queue.rs index f0190c0b93..116791dda8 100644 --- a/libafl/src/schedulers/queue.rs +++ b/libafl/src/schedulers/queue.rs @@ -29,7 +29,7 @@ where S: HasCorpus, { /// Gets the next entry in the queue - fn next(&self, state: &mut Self::State) -> Result { + fn next(&mut self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty("No entries in corpus".to_owned())) } else { @@ -79,7 +79,7 @@ mod tests { #[test] fn test_queuecorpus() { let rand = StdRand::with_seed(4); - let scheduler = QueueScheduler::new(); + let mut scheduler = QueueScheduler::new(); let mut q = OnDiskCorpus::::new(PathBuf::from("target/.test/fancy/path")).unwrap(); diff --git a/libafl/src/schedulers/tuneable.rs b/libafl/src/schedulers/tuneable.rs index cc3a0a1fa5..c6340f98bd 100644 --- a/libafl/src/schedulers/tuneable.rs +++ b/libafl/src/schedulers/tuneable.rs @@ -93,7 +93,7 @@ where S: HasCorpus + HasMetadata, { /// Gets the next entry in the queue - fn next(&self, state: &mut Self::State) -> Result { + fn next(&mut self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { return Err(Error::empty("No entries in corpus".to_owned())); } diff --git a/libafl/src/schedulers/weighted.rs b/libafl/src/schedulers/weighted.rs index 88a2a05f28..50fc4d4f7e 100644 --- a/libafl/src/schedulers/weighted.rs +++ b/libafl/src/schedulers/weighted.rs @@ -11,6 +11,7 @@ use crate::{ bolts::rands::Rand, corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData, Testcase}, inputs::UsesInput, + observers::{MapObserver, ObserversTuple}, random_corpus_id, schedulers::{ powersched::{PowerSchedule, SchedulerMetadata}, @@ -88,25 +89,28 @@ crate::impl_serdeany!(WeightedScheduleMetadata); /// A corpus scheduler using power schedules with weighted queue item selection algo. #[derive(Clone, Debug)] -pub struct WeightedScheduler { +pub struct WeightedScheduler { strat: Option, - phantom: PhantomData<(F, S)>, + map_observer_name: String, + last_hash: usize, + phantom: PhantomData<(F, O, S)>, } -impl WeightedScheduler +impl WeightedScheduler where F: TestcaseScore, + O: MapObserver, S: HasCorpus + HasMetadata + HasRand, { /// Create a new [`WeightedScheduler`] without any power schedule #[must_use] - pub fn new(state: &mut S) -> Self { - Self::with_schedule(state, None) + pub fn new(state: &mut S, map_observer: &O) -> Self { + Self::with_schedule(state, map_observer, None) } /// Create a new [`WeightedScheduler`] #[must_use] - pub fn with_schedule(state: &mut S, strat: Option) -> Self { + pub fn with_schedule(state: &mut S, map_observer: &O, strat: Option) -> Self { if !state.has_metadata::() { state.add_metadata(SchedulerMetadata::new(strat)); } @@ -116,6 +120,8 @@ where } Self { strat, + map_observer_name: map_observer.name().to_string(), + last_hash: 0, phantom: PhantomData, } } @@ -216,20 +222,21 @@ where } } -impl UsesState for WeightedScheduler +impl UsesState for WeightedScheduler where S: UsesInput, { type State = S; } -impl Scheduler for WeightedScheduler +impl Scheduler for WeightedScheduler where F: TestcaseScore, + O: MapObserver, S: HasCorpus + HasMetadata + HasRand, { /// Add an entry to the corpus and return its index - fn on_add(&self, state: &mut S, idx: CorpusId) -> Result<(), Error> { + fn on_add(&mut self, state: &mut S, idx: CorpusId) -> Result<(), Error> { let current_idx = *state.corpus().current(); let mut depth = match current_idx { @@ -248,11 +255,9 @@ where // Attach a `SchedulerTestcaseMetaData` to the queue entry. depth += 1; - state - .corpus() - .get(idx)? - .borrow_mut() - .add_metadata(SchedulerTestcaseMetaData::new(depth)); + state.corpus().get(idx)?.borrow_mut().add_metadata( + SchedulerTestcaseMetaData::with_n_fuzz_entry(depth, self.last_hash), + ); // Recreate the alias table self.create_alias_table(state)?; @@ -260,7 +265,7 @@ where } fn on_replace( - &self, + &mut self, state: &mut S, idx: CorpusId, _testcase: &Testcase, @@ -270,7 +275,7 @@ where } fn on_remove( - &self, + &mut self, state: &mut S, _idx: CorpusId, _testcase: &Option>, @@ -280,8 +285,37 @@ where Ok(()) } + fn on_evaluation( + &mut self, + state: &mut Self::State, + _input: &::Input, + observers: &OT, + ) -> Result<(), Error> + where + OT: ObserversTuple, + { + let observer = observers + .match_name::(&self.map_observer_name) + .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; + + let mut hash = observer.hash() as usize; + + let psmeta = state + .metadata_mut() + .get_mut::() + .ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?; + + hash %= psmeta.n_fuzz().len(); + // Update the path frequency + psmeta.n_fuzz_mut()[hash] = psmeta.n_fuzz()[hash].saturating_add(1); + + self.last_hash = hash; + + Ok(()) + } + #[allow(clippy::similar_names, clippy::cast_precision_loss)] - fn next(&self, state: &mut S) -> Result { + fn next(&mut self, state: &mut S) -> Result { let corpus_counts = state.corpus().count(); if corpus_counts == 0 { Err(Error::empty(String::from("No entries in corpus"))) @@ -345,4 +379,4 @@ where } /// The standard corpus weight, same as aflpp -pub type StdWeightedScheduler = WeightedScheduler, S>; +pub type StdWeightedScheduler = WeightedScheduler, O, S>; diff --git a/libafl/src/stages/power.rs b/libafl/src/stages/power.rs index 78fba0efe5..308750822e 100644 --- a/libafl/src/stages/power.rs +++ b/libafl/src/stages/power.rs @@ -1,50 +1,39 @@ //! The power schedules. This stage should be invoked after the calibration stage. -use alloc::string::{String, ToString}; use core::{fmt::Debug, marker::PhantomData}; use crate::{ - bolts::tuples::MatchName, - corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData}, + corpus::{Corpus, CorpusId}, executors::{Executor, HasObservers}, fuzzer::Evaluator, mutators::Mutator, - observers::MapObserver, - schedulers::{ - powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore, - }, - stages::{ - mutational::{MutatedTransform, MutatedTransformPost}, - MutationalStage, Stage, - }, + schedulers::{testcase_score::CorpusPowerTestcaseScore, TestcaseScore}, + stages::{mutational::MutatedTransform, MutationalStage, Stage}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; /// The mutational stage using power schedules #[derive(Clone, Debug)] -pub struct PowerMutationalStage { - map_observer_name: String, +pub struct PowerMutationalStage { mutator: M, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, F, EM, I, O, Z)>, + phantom: PhantomData<(E, F, EM, I, Z)>, } -impl UsesState for PowerMutationalStage +impl UsesState for PowerMutationalStage where E: UsesState, { type State = E::State; } -impl MutationalStage - for PowerMutationalStage +impl MutationalStage for PowerMutationalStage where E: Executor + HasObservers, EM: UsesState, F: TestcaseScore, M: Mutator, - O: MapObserver, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, Z: Evaluator, I: MutatedTransform + Clone, @@ -70,74 +59,14 @@ where Ok(score) } - - #[allow(clippy::cast_possible_wrap)] - fn perform_mutational( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut E::State, - manager: &mut EM, - corpus_idx: CorpusId, - ) -> Result<(), Error> { - let num = self.iterations(state, corpus_idx)?; - - let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut(); - let Ok(input) = I::try_transform_from(&mut testcase, state, corpus_idx) else { return Ok(()); }; - drop(testcase); - - for i in 0..num { - let mut input = input.clone(); - - self.mutator_mut().mutate(state, &mut input, i as i32)?; - - let (untransformed, post) = input.try_transform_into(state)?; - let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; - - let observer = executor - .observers() - .match_name::(&self.map_observer_name) - .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; - - let mut hash = observer.hash() as usize; - - let psmeta = state - .metadata_mut() - .get_mut::() - .ok_or_else(|| Error::key_not_found("SchedulerMetadata not found".to_string()))?; - - hash %= psmeta.n_fuzz().len(); - // Update the path frequency - psmeta.n_fuzz_mut()[hash] = psmeta.n_fuzz()[hash].saturating_add(1); - - if let Some(idx) = corpus_idx { - state - .corpus() - .get(idx)? - .borrow_mut() - .metadata_mut() - .get_mut::() - .ok_or_else(|| { - Error::key_not_found("SchedulerTestcaseMetaData not found".to_string()) - })? - .set_n_fuzz_entry(hash); - } - - self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; - post.post_exec(state, i as i32, corpus_idx)?; - } - - Ok(()) - } } -impl Stage for PowerMutationalStage +impl Stage for PowerMutationalStage where E: Executor + HasObservers, EM: UsesState, F: TestcaseScore, M: Mutator, - O: MapObserver, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, Z: Evaluator, I: MutatedTransform + Clone, @@ -157,36 +86,33 @@ where } } -impl PowerMutationalStage +impl PowerMutationalStage where E: Executor + HasObservers, EM: UsesState, F: TestcaseScore, M: Mutator, - O: MapObserver, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, Z: Evaluator, { /// Creates a new [`PowerMutationalStage`] - pub fn new(mutator: M, map_observer_name: &O) -> Self { - Self::transforming(mutator, map_observer_name) + pub fn new(mutator: M) -> Self { + Self::transforming(mutator) } } -impl PowerMutationalStage +impl PowerMutationalStage where E: Executor + HasObservers, EM: UsesState, F: TestcaseScore, M: Mutator, - O: MapObserver, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, Z: Evaluator, { /// Creates a new transforming [`PowerMutationalStage`] - pub fn transforming(mutator: M, map_observer_name: &O) -> Self { + pub fn transforming(mutator: M) -> Self { Self { - map_observer_name: map_observer_name.name().to_string(), mutator, phantom: PhantomData, } @@ -194,5 +120,5 @@ where } /// The standard powerscheduling stage -pub type StdPowerMutationalStage = - PowerMutationalStage::State>, EM, I, M, O, Z>; +pub type StdPowerMutationalStage = + PowerMutationalStage::State>, EM, I, M, Z>; diff --git a/libafl/src/stages/push/mutational.rs b/libafl/src/stages/push/mutational.rs index b437a6f264..bd352d6c2e 100644 --- a/libafl/src/stages/push/mutational.rs +++ b/libafl/src/stages/push/mutational.rs @@ -116,7 +116,7 @@ where self.current_corpus_idx = Some(if let Some(corpus_idx) = self.current_corpus_idx { corpus_idx } else { - fuzzer.scheduler().next(state)? + fuzzer.scheduler_mut().next(state)? }); self.testcases_to_do = self.iterations(state, self.current_corpus_idx.unwrap())?; diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index ec98fa0816..facb61a095 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -8,7 +8,7 @@ use which::which; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -const QEMU_REVISION: &str = "f6a2e732e8e225ebb8d1a9399561af7330af31b3"; +const QEMU_REVISION: &str = "0dc52ed6f3915f727aaec8648706760f278f0571"; fn build_dep_check(tools: &[&str]) { for tool in tools { @@ -249,7 +249,6 @@ pub fn build( .arg("--disable-vhost-vdpa") .arg("--disable-virglrenderer") .arg("--disable-virtfs") - .arg("--disable-virtiofsd") .arg("--disable-vmnet") .arg("--disable-vnc") .arg("--disable-vnc-jpeg")