From d0f2507ab4bc4c412f754401fabf95fc218dc03a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 11 Nov 2020 14:18:59 +0100 Subject: [PATCH] fixed splicing mutator --- src/corpus/mod.rs | 5 ++++ src/mutators/scheduled.rs | 59 +++++++++++++++++++++++++++++++++----- src/utils.rs | 60 +++++++++++++++++++++++---------------- 3 files changed, 93 insertions(+), 31 deletions(-) diff --git a/src/corpus/mod.rs b/src/corpus/mod.rs index a5491a7559..de399d7970 100644 --- a/src/corpus/mod.rs +++ b/src/corpus/mod.rs @@ -38,6 +38,11 @@ where self.entries_mut().push(entry); } + /// Add an input to the corpus + fn add_input(&mut self, input: I) { + self.add(Testcase::new_rr(input)); + } + /// Removes an entry from the corpus, returning it if it was present. fn remove(&mut self, entry: &Testcase) -> Option>>> { let mut i: usize = 0; diff --git a/src/mutators/scheduled.rs b/src/mutators/scheduled.rs index a9b1bdc651..af7344cd62 100644 --- a/src/mutators/scheduled.rs +++ b/src/mutators/scheduled.rs @@ -162,7 +162,7 @@ pub fn mutation_bitflip( ) -> Result<(), AflError> where C: Corpus, - M: Mutator, + M: HasRand, I: Input + HasBytesVec, { let bit = mutator.rand_below(input.bytes().len() as u64) as usize; @@ -194,10 +194,28 @@ pub fn mutation_splice( ) -> Result<(), AflError> where C: Corpus, - M: Mutator, + M: HasRand, I: Input + HasBytesVec, { - let other_rr = corpus.random_entry()?; + let mut retry_count = 0; + // We don't want to use the testcase we're already using for splicing + let other_rr = loop { + let mut found = false; + let other_rr = corpus.random_entry()?.clone(); + match other_rr.try_borrow_mut() { + Ok(_) => found = true, + Err(_) => { + if retry_count == 20 { + return Err(AflError::Empty("No suitable testcase found for splicing".to_owned())); + } + retry_count += 1; + }, + }; + if found { + break other_rr; + } + }; + // This should work now, as we successfully try_borrow_mut'd before. let mut other_testcase = other_rr.borrow_mut(); let other = other_testcase.load_input()?; @@ -215,11 +233,12 @@ where let split_at = mutator.rand_between(first_diff as u64, last_diff as u64) as usize; - Err(AflError::NotImplemented(format!("TODO: fix Splice (would split at {})", split_at))) + let _: Vec<_> = input + .bytes_mut() + .splice(split_at.., other.bytes()[split_at..].iter().cloned()) + .collect(); - //input.bytes_mut().splice(split_at.., other.bytes()[split_at..]).collect(); - - //Ok(()) + Ok(()) } /// Schedule some selected byte level mutations given a ScheduledMutator type @@ -292,3 +311,29 @@ where } } } + +#[cfg(test)] +mod tests { + + use crate::corpus::{Corpus, InMemoryCorpus}; + use crate::inputs::BytesInput; + use crate::mutators::scheduled::mutation_splice; + use crate::utils::{Xoshiro256StarRand, DefaultHasRand}; + + #[test] + fn test_mut_splice() { + let rand = &Xoshiro256StarRand::new_rr(0); + let mut has_rand = DefaultHasRand::new(&rand); + let mut corpus = InMemoryCorpus::new(&rand); + corpus.add_input(BytesInput::new(vec!['a' as u8, 'b' as u8, 'c' as u8])); + corpus.add_input(BytesInput::new(vec!['d' as u8, 'e' as u8, 'f' as u8])); + + let testcase_rr = corpus.next().expect("Corpus did not contain entries"); + let mut testcase = testcase_rr.borrow_mut(); + let mut input = testcase.load_input().expect("No input in testcase").clone(); + + mutation_splice(&mut has_rand, &mut corpus, &mut input).unwrap() + + // TODO: Finish testcase + } +} diff --git a/src/utils.rs b/src/utils.rs index dd686fdaca..5cb2458298 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -136,6 +136,40 @@ impl Xoshiro256StarRand { } } +/// A very basic HasRand +pub struct DefaultHasRand +where + R: Rand, +{ + rand: Rc>, +} + +/// A very basic HasRand +impl HasRand for DefaultHasRand +where + R: Rand, +{ + type R = R; + + /// Get the rand rc refcell + fn rand(&self) -> &Rc> { + &self.rand + } +} + +/// A very basic HasRand +impl DefaultHasRand +where + R: Rand, +{ + /// Create a new DefaultHasRand, cloning the refcell + pub fn new(rand: &Rc>) -> Self { + Self { + rand: Rc::clone(rand), + } + } +} + /// Get the next higher power of two pub fn next_pow2(val: u64) -> u64 { let mut out = val.wrapping_sub(1); @@ -149,7 +183,7 @@ pub fn next_pow2(val: u64) -> u64 { #[cfg(test)] mod tests { - use crate::utils::{next_pow2, HasRand, Rand, Xoshiro256StarRand}; + use crate::utils::{next_pow2, DefaultHasRand, HasRand, Rand, Xoshiro256StarRand}; #[test] fn test_rand() { @@ -161,32 +195,10 @@ mod tests { assert!(rand.between(11, 20) > 10); } - use alloc::rc::Rc; - use core::cell::RefCell; - struct HasRandTest - where - R: Rand, - { - rand: Rc>, - } - - impl HasRand for HasRandTest - where - R: Rand, - { - type R = R; - - fn rand(&self) -> &Rc> { - &self.rand - } - } - #[test] fn test_has_rand() { let rand = Xoshiro256StarRand::preseeded_rr(); - let has_rand = HasRandTest { - rand: Rc::clone(&rand), - }; + let has_rand = DefaultHasRand::new(&rand); assert!(has_rand.rand_below(100) < 100); assert_eq!(has_rand.rand_below(1), 0);