RandT generic for corpus and mutator

This commit is contained in:
Andrea Fioraldi 2020-11-01 11:58:18 +01:00
parent 2e8c3fa725
commit e42f13bba6
6 changed files with 225 additions and 132 deletions

View File

@ -1,55 +1,37 @@
pub mod testcase; pub mod testcase;
pub use testcase::{Testcase, SimpleTestcase}; pub use testcase::Testcase;
use crate::utils::Rand; use crate::utils::{Rand, HasRand};
use crate::inputs::Input;
use crate::AflError; use crate::AflError;
use std::path::PathBuf; use std::path::PathBuf;
pub trait HasEntriesVec<InputT: Input> {
/// Get the entries vector field
fn entries(&self) -> &Vec<Box<Testcase<InputT>>>;
/// Get the entries vector field (mutable)
fn entries_mut(&mut self) -> &mut Vec<Box<Testcase<InputT>>>;
}
/// Corpus with all current testcases /// Corpus with all current testcases
pub trait Corpus { pub trait Corpus<InputT: Input, RandT: Rand> : HasEntriesVec<InputT> + HasRand<RandT> {
/// Returns the number of elements
fn count(&self) -> usize;
fn add(&mut self, entry: Box<dyn Testcase>);
/// Removes an entry from the corpus, returning it if it was present.
fn remove(&mut self, entry: &dyn Testcase) -> Option<Box<dyn Testcase>>;
/// Gets a random entry
fn random_entry(&mut self) -> Result<&Box<dyn Testcase>, AflError>;
/// Gets the next entry
fn get(&mut self) -> Result<&Box<dyn Testcase>, AflError>;
}
pub struct BaseCorpus<'a, RandT: Rand> {
rand: &'a mut RandT,
entries: Vec<Box<dyn Testcase>>,
dir_path: PathBuf,
}
impl<RandT: Rand> Corpus for BaseCorpus<'_, RandT> {
/// Returns the number of elements /// Returns the number of elements
fn count(&self) -> usize { fn count(&self) -> usize {
self.entries.len() self.entries().len()
} }
fn add(&mut self, mut entry: Box<dyn Testcase>) { /// Add an entry to the corpus
if entry.get_filename() == None { fn add(&mut self, mut entry: Box<Testcase<InputT>>) {
// TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL) self.entries_mut().push(entry);
let filename = &(String::from("id:") + &self.entries.len().to_string());
let filename = self.dir_path.join(filename);
entry.set_filename(filename);
}
self.entries.push(entry);
} }
/// Removes an entry from the corpus, returning it if it was present. /// Removes an entry from the corpus, returning it if it was present.
fn remove(&mut self, entry: &dyn Testcase) -> Option<Box<dyn Testcase>> { fn remove(&mut self, entry: &Testcase<InputT>) -> Option<Box<Testcase<InputT>>> {
let mut i: usize = 0; let mut i: usize = 0;
let mut found = false; let mut found = false;
for x in &self.entries { for x in self.entries() {
i = i + 1; i = i + 1;
if x.as_ref() as *const _ == entry as *const _ { if x.as_ref() as *const _ == entry as *const _ {
found = true; found = true;
@ -59,24 +41,99 @@ impl<RandT: Rand> Corpus for BaseCorpus<'_, RandT> {
if !found { if !found {
return None; return None;
} }
Some(self.entries.remove(i)) Some(self.entries_mut().remove(i))
} }
/// Gets a random entry /// Gets a random entry
fn random_entry(&mut self) -> Result<&Box<dyn Testcase>, AflError> { fn random_entry(&mut self) -> Result<&Box<Testcase<InputT>>, AflError> {
let id = self.rand.below(self.entries.len() as u64) as usize; let id = self.rand_mut().below(self.entries().len() as u64) as usize;
Ok(self.entries.get_mut(id).unwrap()) Ok(self.entries_mut().get_mut(id).unwrap())
} }
/// Gets the next entry /// Gets the next entry (random by default)
fn get(&mut self) -> Result<&Box<dyn Testcase>, AflError> { fn get(&mut self) -> Result<&Box<Testcase<InputT>>, AflError> {
self.random_entry() self.random_entry()
} }
} }
impl<RandT: Rand> BaseCorpus<'_, RandT> { pub struct InMemoryCorpus<'a, InputT: Input, RandT: Rand> {
pub fn new<'a>(rand: &'a mut RandT, dir_path: PathBuf) -> BaseCorpus<'a, RandT> { rand: &'a mut RandT,
BaseCorpus { entries: Vec<Box<Testcase<InputT>>>,
}
impl<InputT: Input, RandT: Rand> HasEntriesVec<InputT> for InMemoryCorpus<'_, InputT, RandT> {
fn entries(&self) -> &Vec<Box<Testcase<InputT>>> {
&self.entries
}
fn entries_mut(&mut self) -> &mut Vec<Box<Testcase<InputT>>>{
&mut self.entries
}
}
impl<InputT: Input, RandT: Rand> HasRand<RandT> for InMemoryCorpus<'_, InputT, RandT> {
fn rand(&self) -> &Box<dyn Rand> {
&self.rand
}
fn rand_mut(&mut self) -> &mut Box<dyn Rand> {
&mut self.rand
}
}
impl<InputT: Input, RandT: Rand> Corpus<InputT, RandT> for InMemoryCorpus<'_, InputT, RandT> {
// Just use the default implementation
}
impl<InputT: Input, RandT: Rand> InMemoryCorpus<'_, InputT, RandT> {
pub fn new<'a>(rand: &'a mut RandT) -> Self {
InMemoryCorpus {
rand: rand,
entries: vec![],
}
}
}
pub struct OnDiskCorpus<'a, InputT: Input, RandT: Rand> {
rand: &'a mut RandT,
entries: Vec<Box<Testcase<InputT>>>,
dir_path: PathBuf,
}
impl<InputT: Input, RandT: Rand> HasEntriesVec<InputT> for OnDiskCorpus<'_, InputT, RandT> {
fn entries(&self) -> &Vec<Box<Testcase<InputT>>> {
&self.entries
}
fn entries_mut(&mut self) -> &mut Vec<Box<Testcase<InputT>>>{
&mut self.entries
}
}
impl<InputT: Input, RandT: Rand> HasRand<RandT> for OnDiskCorpus<'_, InputT, RandT> {
fn rand(&self) -> &Box<dyn Rand> {
&self.rand
}
fn rand_mut(&mut self) -> &mut Box<dyn Rand> {
&mut self.rand
}
}
impl<InputT: Input, RandT: Rand> Corpus<InputT, RandT> for OnDiskCorpus<'_, InputT, RandT> {
/// Add an entry and save it to disk
fn add(&mut self, mut entry: Box<Testcase<InputT>>) {
if entry.filename() == None {
// TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL)
let filename = &(String::from("id:") + &self.entries.len().to_string());
let filename = self.dir_path.join(filename);
entry.filename_mut() = filename;
}
self.entries.push(entry);
}
// TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus
}
impl<InputT: Input, RandT: Rand> OnDiskCorpus<'_, InputT, RandT> {
pub fn new<'a>(rand: &'a mut RandT, dir_path: PathBuf) -> Self {
OnDiskCorpus {
dir_path: dir_path, dir_path: dir_path,
entries: vec![], entries: vec![],
rand: rand, rand: rand,
@ -84,35 +141,35 @@ impl<RandT: Rand> BaseCorpus<'_, RandT> {
} }
} }
/// A queue-like corpus /// A Queue-like corpus, wrapping an existing Corpus instance
pub struct QueueCorpus<'a, RandT: Rand> { pub struct QueueCorpus<'a, InputT: Input, RandT: Rand, CorpusT: Corpus<InputT, RandT>> {
base: BaseCorpus<'a, RandT>, corpus: CorpusT,
pos: usize, pos: usize,
cycles: u64, cycles: u64,
} }
impl<RandT: Rand> Corpus for QueueCorpus<'_, RandT> { impl<'a, InputT: Input, RandT: Rand, CorpusT: Corpus<InputT, RandT>> Corpus<InputT, RandT> for QueueCorpus<'_, InputT, RandT, CorpusT> {
/// Returns the number of elements /// Returns the number of elements
fn count(&self) -> usize { fn count(&self) -> usize {
self.base.count() self.corpus.count()
} }
fn add(&mut self, entry: Box<dyn Testcase>) { fn add(&mut self, entry: Box<Testcase<InputT>>) {
self.base.add(entry); self.corpus.add(entry);
} }
/// Removes an entry from the corpus, returning it if it was present. /// Removes an entry from the corpus, returning it if it was present.
fn remove(&mut self, entry: &dyn Testcase) -> Option<Box<dyn Testcase>> { fn remove(&mut self, entry: &Testcase<InputT>) -> Option<Box<Testcase<InputT>>> {
self.base.remove(entry) self.corpus.remove(entry)
} }
/// Gets a random entry /// Gets a random entry
fn random_entry(&mut self) -> Result<&Box<dyn Testcase>, AflError> { fn random_entry(&mut self) -> Result<&Box<Testcase<InputT>>, AflError> {
self.base.random_entry() self.corpus.random_entry()
} }
/// Gets the next entry /// Gets the next entry
fn get(&mut self) -> Result<&Box<dyn Testcase>, AflError> { fn get(&mut self) -> Result<&Box<Testcase<InputT>>, AflError> {
if self.count() == 0 { if self.count() == 0 {
return Err(AflError::Empty("Testcases".to_string())); return Err(AflError::Empty("Testcases".to_string()));
} }
@ -121,24 +178,24 @@ impl<RandT: Rand> Corpus for QueueCorpus<'_, RandT> {
self.cycles = self.cycles + 1; self.cycles = self.cycles + 1;
self.pos = 0; self.pos = 0;
} }
Ok(self.base.entries.get_mut(self.pos).unwrap()) Ok(self.corpus.entries.get_mut(self.pos).unwrap())
} }
} }
impl<RandT: Rand> QueueCorpus<'_, RandT> { impl<'a, InputT: Input, RandT: Rand, CorpusT: Corpus<InputT, RandT>> QueueCorpus<'_, InputT, RandT, CorpusT> {
pub fn new<'a>(rand: &'a mut RandT, dir_path: PathBuf) -> QueueCorpus<'a, RandT> { pub fn new(corpus: CorpusT) -> Self {
QueueCorpus { QueueCorpus {
base: BaseCorpus::new(rand, dir_path), corpus: corpus,
cycles: 0, cycles: 0,
pos: 0, pos: 0,
} }
} }
pub fn get_cycles(&self) -> u64 { pub fn cycles(&self) -> u64 {
self.cycles self.cycles
} }
pub fn get_pos(&self) -> usize { pub fn pos(&self) -> usize {
self.pos self.pos
} }
} }
@ -146,8 +203,7 @@ impl<RandT: Rand> QueueCorpus<'_, RandT> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::corpus::Corpus; use crate::corpus::Corpus;
use crate::corpus::QueueCorpus; use crate::corpus::{QueueCorpus, OnDiskCorpus};
use crate::corpus::SimpleTestcase;
use crate::corpus::Testcase; use crate::corpus::Testcase;
use crate::inputs::bytes::BytesInput; use crate::inputs::bytes::BytesInput;
use crate::utils::Xoshiro256StarRand; use crate::utils::Xoshiro256StarRand;
@ -158,13 +214,13 @@ mod tests {
fn test_queuecorpus() { fn test_queuecorpus() {
let mut rand = Xoshiro256StarRand::new(); let mut rand = Xoshiro256StarRand::new();
let mut q = QueueCorpus::new(&mut rand, PathBuf::from("fancy/path")); let mut q = QueueCorpus::new(OnDiskCorpus::new(&mut rand, PathBuf::from("fancy/path")));
let i = Box::new(BytesInput::new(vec![0; 4])); let i = Box::new(BytesInput::new(vec![0; 4]));
let mut t = Box::new(SimpleTestcase::new(i)); let mut t = Box::new(Testcase::new(i));
t.set_filename(PathBuf::from("fancyfile")); t.set_filename(PathBuf::from("fancyfile"));
q.add(t); q.add(t);
let filename = q.get().unwrap().get_filename().unwrap().to_owned(); let filename = q.get().unwrap().get_filename().unwrap().to_owned();
assert_eq!(filename, q.get().unwrap().get_filename().unwrap().to_owned()); assert_eq!(filename, q.get().unwrap().get_filename().unwrap().to_owned());
assert_eq!(filename, PathBuf::from("fancyfile")); assert_eq!(filename, PathBuf::from("fancy/path/fancyfile"));
} }
} }

View File

@ -6,63 +6,82 @@ use std::path::PathBuf;
pub trait TestcaseMetadata {} pub trait TestcaseMetadata {}
pub trait Testcase { /*
pub trait TestcaseTrait<InputT: Input> {
/// Make sure to return a valid input instance loading it from disk if not in memory
fn load_input(&mut self) -> Result<&Box<InputT>, AflError>;
fn load_input(&mut self) -> Result<&Box<dyn Input>, AflError>; /// Get the input, if any
fn input(&self) -> &Option<Box<InputT>>;
fn get_input(&self) -> Option<& Box<dyn Input>>; /// Get the input, if any (mutable)
fn input_mut(&mut self) -> &mut Option<Box<InputT>>;
fn is_on_disk(&self) -> bool; /// Get the filename, if any
fn filename(&self) -> &Option<PathBuf>;
fn get_filename(&self) -> Option<& PathBuf>; /// Get the filename, if any (mutable)
fn filename_mut(&mut self, filename: PathBuf) -> &mut &Option<PathBuf>;
fn set_filename(&mut self, filename: PathBuf);
fn get_metadatas(&mut self) -> &mut HashMap<String, Box<dyn TestcaseMetadata>>;
/// Get all the metadatas into an HashMap
fn metadatas(&mut self) -> &mut HashMap<String, Box<dyn TestcaseMetadata>>;
} }
*/
#[derive(Default)] #[derive(Default)]
pub struct SimpleTestcase { pub struct Testcase<InputT: Input> {
input: Option<Box<dyn Input>>, input: Option<Box<InputT>>,
// is_on_disk: bool, // not needed, look at the Option
filename: Option<PathBuf>, filename: Option<PathBuf>,
metadatas: HashMap<String, Box<dyn TestcaseMetadata>>, metadatas: HashMap<String, Box<dyn TestcaseMetadata>>,
} }
impl Testcase for SimpleTestcase { impl<InputT: Input> Testcase<InputT> {
fn load_input(&mut self) -> Result<&Box<dyn Input>, AflError> { /// Make sure to return a valid input instance loading it from disk if not in memory
pub fn load_input(&mut self) -> Result<&Box<InputT>, AflError> {
// TODO: Implement cache to disk // TODO: Implement cache to disk
self.input.as_ref().ok_or(AflError::NotImplemented("load_input".to_string())) self.input.as_ref().ok_or(AflError::NotImplemented("load_input".to_string()))
} }
fn get_input(&self) -> Option<& Box<dyn Input>> { /// Get the input, if any
self.input.as_ref() pub fn input(&self) -> &Option<Box<InputT>> {
&self.input
} }
fn is_on_disk(&self) -> bool { /// Get the input, if any (mutable)
!self.input.is_some() && self.filename.is_some() pub fn input_mut(&mut self) -> &mut Option<Box<InputT>> {
&mut self.input
} }
fn get_filename(&self) -> Option<& PathBuf> { /// Get the filename, if any
self.filename.as_ref() pub fn filename(&self) -> &Option<PathBuf> {
&self.filename
} }
fn set_filename(&mut self, filename: PathBuf) { /// Get the filename, if any (mutable)
self.filename = Some(filename) pub fn filename_mut(&mut self, filename: PathBuf) -> &mut Option<PathBuf> {
&mut self.filename
} }
fn get_metadatas(&mut self) -> &mut HashMap<String, Box<dyn TestcaseMetadata>> { /// Get all the metadatas into an HashMap
pub fn metadatas(&mut self) -> &mut HashMap<String, Box<dyn TestcaseMetadata>> {
&mut self.metadatas &mut self.metadatas
} }
}
impl SimpleTestcase { /// Create a new DefaultTestcase instace given an input
pub fn new(input: Box<dyn Input>) -> Self { pub fn new(input: Box<InputT>) -> Self {
SimpleTestcase { Testcase {
input: Some(input), input: Some(input),
filename: None, filename: None,
metadatas: HashMap::default(), metadatas: HashMap::default(),
} }
} }
/// Create a new DefaultTestcase instace given an input and a filename
pub fn new_with_filename(input: Box<InputT>, filename: &PathBuf) -> Self {
Testcase {
input: Some(input),
filename: filename,
metadatas: HashMap::default(),
}
}
} }

View File

@ -1,21 +1,20 @@
use crate::inputs::Input; use crate::inputs::Input;
use crate::utils::Rand; use crate::utils::{Rand, HasRand};
use crate::corpus::Corpus; use crate::corpus::Corpus;
use crate::AflError; use crate::AflError;
pub mod scheduled; pub mod scheduled;
pub use scheduled::ScheduledMutator; pub use scheduled::{ComposedByMutations, ScheduledMutator, HavocBytesMutator};
pub trait Mutator<InputT : Input> {
fn rand(&mut self) -> &mut Box<dyn Rand>;
pub trait Mutator<InputT : Input, RandT: Rand> : HasRand<RandT> {
/// Mutate a given input
fn mutate(&mut self, input: &mut InputT, stage_idx: i32) -> Result<(), AflError>; fn mutate(&mut self, input: &mut InputT, stage_idx: i32) -> 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, _stage_idx: i32) -> Result<(), AflError> {
Ok(()) Ok(())
} }
fn corpus(&mut self) -> &mut Option<Box<dyn Corpus>>; /// Get the associated corpus, if any
fn corpus(&mut self) -> &mut Option<Box<dyn Corpus<InputT, RandT>>>;
} }

View File

@ -1,5 +1,5 @@
use crate::mutators::Mutator; use crate::mutators::Mutator;
use crate::utils::Rand; use crate::utils::{Rand, HasRand};
use crate::corpus::Corpus; use crate::corpus::Corpus;
use crate::inputs::{Input, HasBytesVec}; use crate::inputs::{Input, HasBytesVec};
use crate::AflError; use crate::AflError;
@ -20,10 +20,10 @@ pub trait ComposedByMutations<InputT : Input> {
fn add_mutation(&mut self, mutation: MutationFunction<Self, InputT>); fn add_mutation(&mut self, mutation: MutationFunction<Self, InputT>);
} }
pub trait ScheduledMutator<InputT : Input>: Mutator<InputT> + ComposedByMutations<InputT> { pub trait ScheduledMutator<InputT : Input, RandT: Rand>: Mutator<InputT, RandT> + ComposedByMutations<InputT> {
/// Computer the number of iterations used to apply stacked mutations /// Computer the number of iterations used to apply stacked mutations
fn iterations(&mut self, _input: &InputT) -> u64 { fn iterations(&mut self, _input: &InputT) -> u64 {
1 << (1 + self.rand().below(7)) 1 << (1 + self.rand_mut().below(7))
} }
/// Get the next mutation to apply /// Get the next mutation to apply
@ -34,7 +34,7 @@ pub trait ScheduledMutator<InputT : Input>: Mutator<InputT> + ComposedByMutation
} }
let idx; let idx;
{ {
idx = self.rand().below(count) as usize; idx = self.rand_mut().below(count) as usize;
} }
self.mutation_by_idx(idx) self.mutation_by_idx(idx)
} }
@ -50,13 +50,22 @@ pub trait ScheduledMutator<InputT : Input>: Mutator<InputT> + ComposedByMutation
} }
} }
pub struct DefaultScheduledMutator<InputT : Input> { pub struct DefaultScheduledMutator<InputT : Input, RandT: Rand> {
rand: Box<dyn Rand>, rand: Box<RandT>,
corpus: Option<Box<dyn Corpus>>, corpus: Option<Box<dyn Corpus<InputT, RandT>>>,
mutations: Vec<MutationFunction<Self, InputT>> mutations: Vec<MutationFunction<Self, InputT>>
} }
impl<InputT : Input> ComposedByMutations<InputT> for DefaultScheduledMutator<InputT> { impl<InputT : Input, RandT: Rand> HasRand<RandT> for DefaultScheduledMutator<InputT, RandT> {
fn rand(&self) -> &Box<dyn Rand> {
&self.rand
}
fn rand_mut(&mut self) -> &mut Box<dyn Rand> {
&mut self.rand
}
}
impl<InputT : Input, RandT: Rand> ComposedByMutations<InputT> for DefaultScheduledMutator<InputT, RandT> {
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, InputT>, AflError> { fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, InputT>, AflError> {
if index >= self.mutations.len() { if index >= self.mutations.len() {
return Err(AflError::Unknown("oob".to_string())); return Err(AflError::Unknown("oob".to_string()));
@ -73,15 +82,11 @@ impl<InputT : Input> ComposedByMutations<InputT> for DefaultScheduledMutator<Inp
} }
} }
impl<InputT : Input> ScheduledMutator<InputT> for DefaultScheduledMutator<InputT> { impl<InputT : Input, RandT: Rand> ScheduledMutator<InputT> for DefaultScheduledMutator<InputT, RandT> {
// Just use the default methods // Just use the default methods
} }
impl<InputT : Input> Mutator<InputT> for DefaultScheduledMutator<InputT> { impl<InputT : Input, RandT: Rand> Mutator<InputT, RandT> for DefaultScheduledMutator<InputT, RandT> {
fn rand(&mut self) -> &mut Box<dyn Rand> {
&mut self.rand
}
fn mutate(&mut self, input: &mut InputT, _stage_idx: i32) -> Result<(), AflError> { fn mutate(&mut self, input: &mut InputT, _stage_idx: i32) -> Result<(), AflError> {
self.scheduled_mutate(input, _stage_idx) self.scheduled_mutate(input, _stage_idx)
} }
@ -91,9 +96,9 @@ impl<InputT : Input> Mutator<InputT> for DefaultScheduledMutator<InputT> {
} }
} }
impl<InputT : Input> DefaultScheduledMutator<InputT> { impl<InputT : Input, RandT: Rand> DefaultScheduledMutator<InputT> {
/// Create a new DefaultScheduledMutator instance without mutations and corpus /// Create a new DefaultScheduledMutator instance without mutations and corpus
pub fn new(rand: Box<dyn Rand>) -> Self { pub fn new(rand: Box<RandT>) -> Self {
DefaultScheduledMutator { DefaultScheduledMutator {
rand: rand, rand: rand,
corpus: None, corpus: None,
@ -102,7 +107,7 @@ impl<InputT : Input> DefaultScheduledMutator<InputT> {
} }
/// Create a new DefaultScheduledMutator instance specifying mutations and corpus too /// Create a new DefaultScheduledMutator instance specifying mutations and corpus too
pub fn new_all(rand: Box<dyn Rand>, corpus: Option<Box<dyn Corpus>>, mutations: Vec<MutationFunction<Self, InputT>>) -> Self { pub fn new_all(rand: Box<RandT>, corpus: Option<Box<dyn Corpus>>, mutations: Vec<MutationFunction<Self, InputT>>) -> Self {
DefaultScheduledMutator { DefaultScheduledMutator {
rand: rand, rand: rand,
corpus: corpus, corpus: corpus,
@ -112,23 +117,19 @@ impl<InputT : Input> DefaultScheduledMutator<InputT> {
} }
/// Bitflip mutation for inputs with a bytes vector /// Bitflip mutation for inputs with a bytes vector
pub fn mutation_bitflip<MutatorT: Mutator<InputT>, InputT: Input + HasBytesVec>(mutator: &mut MutatorT, input: &mut InputT) -> Result<(), AflError> { pub fn mutation_bitflip<MutatorT: Mutator<InputT, RandT>, InputT: Input + HasBytesVec, RandT: Rand>(mutator: &mut MutatorT, input: &mut InputT) -> Result<(), AflError> {
let bit = mutator.rand().below(input.bytes().len() as u64) as usize; let bit = mutator.rand_mut().below(input.bytes().len() as u64) as usize;
input.bytes_mut()[bit >> 3] ^= (128 >> (bit & 7)) as u8; input.bytes_mut()[bit >> 3] ^= (128 >> (bit & 7)) as u8;
Ok(()) Ok(())
} }
/// Schedule some selected byte level mutations given a ScheduledMutator type /// Schedule some selected byte level mutations given a ScheduledMutator type
pub struct HavocBytesMutator<ScheduledMutatorT: ScheduledMutator<InputT>, InputT: Input + HasBytesVec> { pub struct HavocBytesMutator<InputT: Input + HasBytesVec, RandT: Rand, ScheduledMutatorT: ScheduledMutator<InputT, RandT>> {
scheduled: ScheduledMutatorT, scheduled: ScheduledMutatorT,
_phantom: PhantomData<InputT> _phantom: PhantomData<InputT>
} }
impl<ScheduledMutatorT: ScheduledMutator<InputT>, InputT: Input + HasBytesVec> Mutator<InputT> for HavocBytesMutator<ScheduledMutatorT, InputT> { impl<InputT: Input + HasBytesVec, RandT: Rand, ScheduledMutatorT: ScheduledMutator<InputT, RandT>> Mutator<InputT, RandT> for HavocBytesMutator<InputT, RandT, ScheduledMutatorT> {
fn rand(&mut self) -> &mut Box<dyn Rand> {
self.scheduled.rand()
}
fn mutate(&mut self, input: &mut InputT, stage_idx: i32) -> Result<(), AflError> { fn mutate(&mut self, input: &mut InputT, stage_idx: i32) -> Result<(), AflError> {
self.scheduled.mutate(input, stage_idx) self.scheduled.mutate(input, stage_idx)
} }
@ -138,7 +139,16 @@ impl<ScheduledMutatorT: ScheduledMutator<InputT>, InputT: Input + HasBytesVec> M
} }
} }
impl<ScheduledMutatorT: ScheduledMutator<InputT>, InputT: Input + HasBytesVec> HavocBytesMutator<ScheduledMutatorT, InputT> { impl<InputT: Input + HasBytesVec, RandT: Rand, ScheduledMutatorT: ScheduledMutator<InputT, RandT>> HasRand<RandT> for HavocBytesMutator<InputT, RandT, ScheduledMutatorT> {
fn rand(&self) -> &Box<dyn Rand> {
self.scheduled.rand()
}
fn rand_mut(&mut self) -> &mut Box<dyn Rand> {
self.scheduled.rand_mut()
}
}
impl<InputT: Input + HasBytesVec, RandT: Rand, ScheduledMutatorT: ScheduledMutator<InputT, RandT>> HavocBytesMutator<InputT, RandT, ScheduledMutatorT> {
/// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap /// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap
pub fn new(mut scheduled: ScheduledMutatorT) -> Self { pub fn new(mut scheduled: ScheduledMutatorT) -> Self {
scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);
@ -149,9 +159,9 @@ impl<ScheduledMutatorT: ScheduledMutator<InputT>, InputT: Input + HasBytesVec> H
} }
} }
impl<InputT: Input + HasBytesVec> HavocBytesMutator<DefaultScheduledMutator<InputT>, InputT> { impl<InputT: Input + HasBytesVec, RandT: Rand> HavocBytesMutator<InputT, RandT, DefaultScheduledMutator<InputT, RandT>> {
/// Create a new HavocBytesMutator instance wrapping DefaultScheduledMutator /// Create a new HavocBytesMutator instance wrapping DefaultScheduledMutator
pub fn new_default(rand: Box<dyn Rand>) -> Self { pub fn new_default(rand: Box<RandT>) -> Self {
let mut scheduled = DefaultScheduledMutator::new(rand); let mut scheduled = DefaultScheduledMutator::new(rand);
scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);
HavocBytesMutator { HavocBytesMutator {

View File

@ -3,5 +3,5 @@ use crate::inputs::Input;
use crate::AflError; use crate::AflError;
/// Stages /// Stages
pub trait Stage { pub trait Stage {
fn perform(&mut self, input: &dyn Input, entry: &mut dyn Testcase) -> Result<(), AflError>; fn perform(&mut self, input: &dyn Input, entry: &mut Testcase) -> Result<(), AflError>;
} }

View File

@ -39,6 +39,15 @@ pub trait Rand: Debug {
} }
} }
/// Has a Rand box field
pub trait HasRand<RandT: Rand> {
/// Get the hold Rand instance
fn rand(&self) -> &Box<RandT>;
/// Get the hold Rand instance (mutable)
fn rand_mut(&mut self) -> &mut Box<RandT>;
}
const HASH_CONST: u64 = 0xa5b35705; const HASH_CONST: u64 = 0xa5b35705;
/// XXH3 Based, hopefully speedy, rnd implementation /// XXH3 Based, hopefully speedy, rnd implementation