new ondisk corpus

This commit is contained in:
Andrea Fioraldi 2021-02-22 15:19:35 +01:00
parent 3b0883721e
commit a5cc8313db
13 changed files with 260 additions and 223 deletions

View File

@ -5,10 +5,11 @@ use std::{env, path::PathBuf};
use libafl::{
bolts::{shmem::UnixShMem, tuples::tuple_list},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::setup_restarting_mgr,
executors::{inprocess::InProcessExecutor, Executor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::Input,
mutators::scheduled::HavocBytesMutator,
mutators::token_mutations::TokensMetadata,
@ -17,7 +18,7 @@ use libafl::{
state::{HasCorpus, HasMetadata, State},
stats::SimpleStats,
utils::{current_nanos, StdRand},
Error, Fuzzer, StdFuzzer,
Error,
};
/// The name of the coverage map observer, to find it again in the observer list
@ -69,13 +70,12 @@ pub fn main() {
/// The actual fuzzer
fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> {
let mut rand = StdRand::new(current_nanos());
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
let stats = SimpleStats::new(|s| println!("{}", s));
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) =
setup_restarting_mgr::<_, _, _, _, _, _, UnixShMem, _>(stats, broker_port)
setup_restarting_mgr::<_, _, UnixShMem, _>(stats, broker_port)
.expect("Failed to setup the restarter".into());
// Create an observation channel using the coverage map
@ -86,6 +86,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// If not restarting, create a State from scratch
let mut state = state.unwrap_or(State::new(
StdRand::new(current_nanos()),
InMemoryCorpus::new(),
tuple_list!(MaxMapFeedback::new_with_observer(
&NAME_COV_MAP,
@ -111,7 +112,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Setup a basic mutator with a mutational stage
let mutator = HavocBytesMutator::default();
let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
let fuzzer = StdFuzzer::new(RandCorpusScheduler::new(), tuple_list!(stage));
// Create the executor
let mut executor = InProcessExecutor::new(
@ -141,5 +142,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
println!("We imported {} inputs from disk.", state.corpus().count());
}
fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr)
fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?;
Ok(())
}

View File

@ -72,3 +72,15 @@ where
&mut self.current
}
}
impl<I> InMemoryCorpus<I>
where
I: Input,
{
pub fn new() -> Self {
Self {
entries: vec![],
current: None,
}
}
}

View File

@ -6,6 +6,11 @@ pub use testcase::Testcase;
pub mod inmemory;
pub use inmemory::InMemoryCorpus;
#[cfg(feature = "std")]
pub mod ondisk;
#[cfg(feature = "std")]
pub use ondisk::OnDiskCorpus;
pub mod queue;
pub use queue::QueueCorpusScheduler;
@ -110,4 +115,18 @@ where
}
}
impl<C, I, R, S> RandCorpusScheduler<C, I, R, S>
where
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
I: Input,
R: Rand,
{
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
pub type StdCorpusScheduler<C, I, R, S> = RandCorpusScheduler<C, I, R, S>;

View File

@ -1,104 +1,104 @@
//! The ondisk corpus stores unused testcases to disk.
use alloc::vec::Vec;
use core::{cell::RefCell, marker::PhantomData};
use core::cell::RefCell;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::path::PathBuf;
use crate::{
corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::Input, utils::Rand, Error,
};
use crate::{corpus::Corpus, corpus::Testcase, inputs::Input, Error};
/// A corpus able to store testcases to disk, and load them from disk, when they are being used.
#[cfg(feature = "std")]
#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct OnDiskCorpus<I, R>
pub struct OnDiskCorpus<I>
where
I: Input,
R: Rand,
{
entries: Vec<RefCell<Testcase<I>>>,
current: Option<usize>,
dir_path: PathBuf,
pos: usize,
phantom: PhantomData<R>,
}
#[cfg(feature = "std")]
impl<I, R> HasTestcaseVec<I> for OnDiskCorpus<I, R>
impl<I> Corpus<I> for OnDiskCorpus<I>
where
I: Input,
R: Rand,
{
/// Returns the number of elements
#[inline]
fn entries(&self) -> &[RefCell<Testcase<I>>] {
&self.entries
fn count(&self) -> usize {
self.entries.len()
}
#[inline]
fn entries_mut(&mut self) -> &mut Vec<RefCell<Testcase<I>>> {
&mut self.entries
}
}
#[cfg(feature = "std")]
impl<I, R> Corpus<I, R> for OnDiskCorpus<I, R>
where
I: Input,
R: Rand,
{
/// Add an entry and save it to disk
fn add(&mut self, mut entry: Testcase<I>) -> usize {
match entry.filename() {
/// Add an entry to the corpus and return its index
#[inline]
fn add(&mut self, mut testcase: Testcase<I>) -> Result<usize, Error> {
match testcase.filename() {
None => {
// TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL)
let filename = self.dir_path.join(format!("id_{}", &self.entries.len()));
let filename_str = filename.to_str().expect("Invalid Path");
entry.set_filename(filename_str.into());
testcase.set_filename(filename_str.into());
}
_ => {}
}
entry
testcase
.store_input()
.expect("Could not save testcase to disk".into());
self.entries.push(RefCell::new(entry));
self.entries.len() - 1
self.entries.push(RefCell::new(testcase));
Ok(self.entries.len() - 1)
}
/// Replaces the testcase at the given idx
#[inline]
fn current_testcase(&self) -> (&RefCell<Testcase<I>>, usize) {
(self.get(self.pos), self.pos)
fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), Error> {
if idx >= self.entries.len() {
return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx)));
}
self.entries[idx] = RefCell::new(testcase);
Ok(())
}
/// Gets the next entry
/// Removes an entry from the corpus, returning it if it was present.
#[inline]
fn next(&mut self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
if self.count() == 0 {
Err(Error::Empty("No entries in corpus".to_owned()))
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error> {
if idx >= self.entries.len() {
Ok(None)
} else {
let len = { self.entries().len() };
let id = rand.below(len as u64) as usize;
self.pos = id;
Ok((self.get(id), id))
Ok(Some(self.entries.remove(idx).into_inner()))
}
}
// TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus
/// Get by id
#[inline]
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
Ok(&self.entries[idx])
}
/// Current testcase scheduled
#[inline]
fn current(&self) -> &Option<usize> {
&self.current
}
/// Current testcase scheduled (mut)
#[inline]
fn current_mut(&mut self) -> &mut Option<usize> {
&mut self.current
}
}
#[cfg(feature = "std")]
impl<I, R> OnDiskCorpus<I, R>
impl<I> OnDiskCorpus<I>
where
I: Input,
R: Rand,
{
pub fn new(dir_path: PathBuf) -> Self {
Self {
dir_path: dir_path,
entries: vec![],
pos: 0,
phantom: PhantomData,
current: None,
dir_path: dir_path,
}
}
}

View File

@ -46,6 +46,19 @@ where
}
}
impl<C, I, S> QueueCorpusScheduler<C, I, S>
where
S: HasCorpus<C, I>,
C: Corpus<I>,
I: Input,
{
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/*
#[cfg(test)]
#[cfg(feature = "std")]

View File

@ -15,7 +15,6 @@ use crate::{
inputs::{HasTargetBytes, Input},
observers::ObserversTuple,
state::{HasObjectives, HasSolutions},
utils::Rand,
Error,
};
@ -124,7 +123,7 @@ where
/// * `name` - the name of this executor (to address it along the way)
/// * `harness_fn` - the harness, executiong the function
/// * `observers` - the observers observing the target during execution
pub fn new<EM, OC, OFT, R, S>(
pub fn new<EM, OC, OFT, S>(
name: &'static str,
harness_fn: HarnessFunction<Self>,
observers: OT,
@ -136,12 +135,11 @@ where
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
R: Rand,
{
#[cfg(feature = "std")]
#[cfg(unix)]
unsafe {
setup_crash_handlers::<EM, I, OC, OFT, OT, R, S>();
setup_crash_handlers::<EM, I, OC, OFT, OT, S>();
}
Self {
@ -179,7 +177,6 @@ pub mod unix_signals {
inputs::Input,
observers::ObserversTuple,
state::{HasObjectives, HasSolutions},
utils::Rand,
};
/// Let's get 8 mb for now.
const SIGNAL_STACK_SIZE: usize = 2 << 22;
@ -195,18 +192,14 @@ pub mod unix_signals {
/// This is needed for certain non-rust side effects, as well as unix signal handling.
static mut CURRENT_INPUT_PTR: *const c_void = ptr::null();
unsafe fn inmem_handle_crash<EM, I, OC, OFT, OT, R, S>(
_sig: c_int,
info: siginfo_t,
_void: c_void,
) where
unsafe fn inmem_handle_crash<EM, I, OC, OFT, OT, S>(_sig: c_int, info: siginfo_t, _void: c_void)
where
EM: EventManager<I, S>,
OT: ObserversTuple,
OC: Corpus<I>,
OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
I: Input,
R: Rand,
{
if CURRENT_INPUT_PTR == ptr::null() {
println!(
@ -271,7 +264,7 @@ pub mod unix_signals {
std::process::exit(1);
}
unsafe fn inmem_handle_timeout<EM, I, OC, OFT, OT, R, S>(
unsafe fn inmem_handle_timeout<EM, I, OC, OFT, OT, S>(
_sig: c_int,
_info: siginfo_t,
_void: c_void,
@ -282,7 +275,6 @@ pub mod unix_signals {
OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
I: Input,
R: Rand,
{
dbg!("TIMEOUT/SIGUSR2 received");
if CURRENT_INPUT_PTR.is_null() {
@ -350,7 +342,7 @@ pub mod unix_signals {
OBSERVERS_PTR = ptr::null();
}
pub unsafe fn setup_crash_handlers<EM, I, OC, OFT, OT, R, S>()
pub unsafe fn setup_crash_handlers<EM, I, OC, OFT, OT, S>()
where
EM: EventManager<I, S>,
OT: ObserversTuple,
@ -358,7 +350,6 @@ pub mod unix_signals {
OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
I: Input,
R: Rand,
{
// First, set up our own stack to be used during segfault handling. (and specify `SA_ONSTACK` in `sigaction`)
if SIGNAL_STACK_PTR.is_null() {
@ -375,7 +366,7 @@ pub mod unix_signals {
let mut sa: sigaction = mem::zeroed();
libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sa.sa_sigaction = inmem_handle_crash::<EM, I, OC, OFT, OT, R, S> as usize;
sa.sa_sigaction = inmem_handle_crash::<EM, I, OC, OFT, OT, S> as usize;
for (sig, msg) in &[
(SIGSEGV, "segfault"),
(SIGBUS, "sigbus"),
@ -389,7 +380,7 @@ pub mod unix_signals {
}
}
sa.sa_sigaction = inmem_handle_timeout::<EM, I, OC, OFT, OT, R, S> as usize;
sa.sa_sigaction = inmem_handle_timeout::<EM, I, OC, OFT, OT, S> as usize;
if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 {
panic!("Could not set up sigusr2 handler for timeouts");
}

View File

@ -12,9 +12,12 @@ use crate::{
use core::marker::PhantomData;
/// Holds a set of stages
pub trait HasStages<ST, E, EM, S>: Sized
pub trait HasStages<ST, E, EM, I, S>
where
ST: StagesTuple<E, EM, Self, S>,
ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input,
{
fn stages(&self) -> &ST;
@ -44,7 +47,9 @@ pub trait Fuzzer<E, EM, S> {
pub struct StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input,
{
scheduler: CS,
@ -52,10 +57,12 @@ where
phantom: PhantomData<(E, EM, I, OT, S)>,
}
impl<CS, ST, E, EM, I, OT, S> HasStages<ST, E, EM, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
impl<CS, ST, E, EM, I, OT, S> HasStages<ST, E, EM, I, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input,
{
fn stages(&self) -> &ST {
@ -70,7 +77,9 @@ where
impl<CS, ST, E, EM, I, OT, S> HasCorpusScheduler<CS, I, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input,
{
fn scheduler(&self) -> &CS {
@ -86,7 +95,7 @@ impl<CS, ST, E, EM, I, OT, S> Fuzzer<E, EM, S> for StdFuzzer<CS, ST, E, EM, I, O
where
CS: CorpusScheduler<I, S>,
S: HasExecutions,
ST: StagesTuple<E, EM, Self, S>,
ST: StagesTuple<E, EM, I, S>,
EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
@ -95,8 +104,7 @@ where
fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error> {
let idx = self.scheduler().next(state)?;
self.stages()
.perform_all(self, state, executor, manager, idx)?;
self.stages().perform_all(state, executor, manager, idx)?;
manager.process(state, executor)?;
Ok(idx)
@ -125,7 +133,9 @@ where
impl<CS, ST, E, EM, I, OT, S> StdFuzzer<CS, ST, E, EM, I, OT, S>
where
CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>,
ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input,
{
pub fn new(scheduler: CS, stages: ST) -> Self {

View File

@ -14,18 +14,16 @@ use crate::{inputs::Input, Error};
/// A mutator takes input, and mutates it.
/// Simple as that.
pub trait Mutator<F, I, S>
pub trait Mutator<I, S>
where
I: Input,
{
/// Mutate a given input
fn mutate(&self, fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32)
-> Result<(), Error>;
fn mutate(&self, state: &mut S, input: &mut I, stage_idx: i32) -> Result<(), Error>;
/// Post-process given the outcome of the execution
fn post_exec(
&self,
_fuzzer: &F,
_state: &mut S,
_is_interesting: u32,
_stage_idx: i32,

View File

@ -27,20 +27,20 @@ pub enum MutationResult {
// TODO maybe the mutator arg is not needed
/// The generic function type that identifies mutations
pub type MutationFunction<F, I, M, S> = fn(&M, &F, &mut S, &mut I) -> Result<MutationResult, Error>;
pub type MutationFunction<I, M, S> = fn(&M, &mut S, &mut I) -> Result<MutationResult, Error>;
pub trait ComposedByMutations<F, I, S>
pub trait ComposedByMutations<I, S>
where
I: Input,
{
/// Get a mutation by index
fn mutation_by_idx(&self, index: usize) -> MutationFunction<F, I, Self, S>;
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S>;
/// Get the number of mutations
fn mutations_count(&self) -> usize;
/// Add a mutation
fn add_mutation(&mut self, mutation: MutationFunction<F, I, Self, S>);
fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>);
}
/// Mem move in the own vec
@ -123,9 +123,9 @@ const INTERESTING_32: [i32; 27] = [
];
/// Bitflip mutation for inputs with a bytes vector
pub fn mutation_bitflip<F, I, M, R, S>(
pub fn mutation_bitflip<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -146,9 +146,9 @@ where
}
}
pub fn mutation_byteflip<F, I, M, R, S>(
pub fn mutation_byteflip<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -169,9 +169,9 @@ where
}
}
pub fn mutation_byteinc<F, I, M, R, S>(
pub fn mutation_byteinc<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -193,9 +193,9 @@ where
}
}
pub fn mutation_bytedec<F, I, M, R, S>(
pub fn mutation_bytedec<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -217,9 +217,9 @@ where
}
}
pub fn mutation_byteneg<F, I, M, R, S>(
pub fn mutation_byteneg<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -240,9 +240,9 @@ where
}
}
pub fn mutation_byterand<F, I, M, R, S>(
pub fn mutation_byterand<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -263,9 +263,9 @@ where
}
}
pub fn mutation_byteadd<F, I, M, R, S>(
pub fn mutation_byteadd<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -291,9 +291,9 @@ where
}
}
pub fn mutation_wordadd<F, I, M, R, S>(
pub fn mutation_wordadd<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -321,9 +321,9 @@ where
}
}
pub fn mutation_dwordadd<F, I, M, R, S>(
pub fn mutation_dwordadd<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -351,9 +351,9 @@ where
}
}
pub fn mutation_qwordadd<F, I, M, R, S>(
pub fn mutation_qwordadd<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -381,9 +381,9 @@ where
}
}
pub fn mutation_byteinteresting<F, I, M, R, S>(
pub fn mutation_byteinteresting<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -405,9 +405,9 @@ where
}
}
pub fn mutation_wordinteresting<F, I, M, R, S>(
pub fn mutation_wordinteresting<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -435,9 +435,9 @@ where
}
}
pub fn mutation_dwordinteresting<F, I, M, R, S>(
pub fn mutation_dwordinteresting<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -465,9 +465,9 @@ where
}
}
pub fn mutation_bytesdelete<F, I, M, R, S>(
pub fn mutation_bytesdelete<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -488,9 +488,9 @@ where
Ok(MutationResult::Mutated)
}
pub fn mutation_bytesexpand<F, I, M, R, S>(
pub fn mutation_bytesexpand<I, M, R, S>(
mutator: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -518,9 +518,9 @@ where
Ok(MutationResult::Mutated)
}
pub fn mutation_bytesinsert<F, I, M, R, S>(
pub fn mutation_bytesinsert<I, M, R, S>(
mutator: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -551,9 +551,9 @@ where
Ok(MutationResult::Mutated)
}
pub fn mutation_bytesrandinsert<F, I, M, R, S>(
pub fn mutation_bytesrandinsert<I, M, R, S>(
mutator: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -584,9 +584,9 @@ where
Ok(MutationResult::Mutated)
}
pub fn mutation_bytesset<F, I, M, R, S>(
pub fn mutation_bytesset<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -609,9 +609,9 @@ where
Ok(MutationResult::Mutated)
}
pub fn mutation_bytesrandset<F, I, M, R, S>(
pub fn mutation_bytesrandset<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -634,9 +634,9 @@ where
Ok(MutationResult::Mutated)
}
pub fn mutation_bytescopy<F, I, M, R, S>(
pub fn mutation_bytescopy<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -659,9 +659,9 @@ where
Ok(MutationResult::Mutated)
}
pub fn mutation_bytesswap<F, I, M, R, S>(
pub fn mutation_bytesswap<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -687,9 +687,9 @@ where
}
/// Crossover insert mutation
pub fn mutation_crossover_insert<C, F, I, M, R, S>(
pub fn mutation_crossover_insert<C, I, M, R, S>(
mutator: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -745,9 +745,9 @@ where
}
/// Crossover replace mutation
pub fn mutation_crossover_replace<C, F, I, M, R, S>(
pub fn mutation_crossover_replace<C, I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -808,9 +808,9 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
}
/// Splicing mutation from AFL
pub fn mutation_splice<C, F, I, M, R, S>(
pub fn mutation_splice<C, I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>

View File

@ -15,7 +15,7 @@ use crate::{
pub use crate::mutators::mutations::*;
pub use crate::mutators::token_mutations::*;
pub trait ScheduledMutator<F, I, S>: Mutator<F, I, S> + ComposedByMutations<F, I, S>
pub trait ScheduledMutator<I, S>: Mutator<I, S> + ComposedByMutations<I, S>
where
I: Input,
{
@ -27,34 +27,28 @@ where
/// New default implementation for mutate
/// Implementations must forward mutate() to this method
fn scheduled_mutate(
&self,
fuzzer: &F,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<(), Error> {
fn scheduled_mutate(&self, state: &mut S, input: &mut I, _stage_idx: i32) -> Result<(), Error> {
let num = self.iterations(state, input);
for _ in 0..num {
let idx = self.schedule(self.mutations_count(), state, input);
self.mutation_by_idx(idx)(self, fuzzer, state, input)?;
self.mutation_by_idx(idx)(self, state, input)?;
}
Ok(())
}
}
pub struct StdScheduledMutator<F, I, R, S>
pub struct StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
mutations: Vec<MutationFunction<F, I, Self, S>>,
mutations: Vec<MutationFunction<I, Self, S>>,
max_size: usize,
phantom: PhantomData<R>,
}
impl<F, I, R, S> Debug for StdScheduledMutator<F, I, R, S>
impl<I, R, S> Debug for StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
@ -71,31 +65,25 @@ where
}
}
impl<F, I, R, S> Mutator<F, I, S> for StdScheduledMutator<F, I, R, S>
impl<I, R, S> Mutator<I, S> for StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
fn mutate(
&self,
fuzzer: &F,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<(), Error> {
self.scheduled_mutate(fuzzer, state, input, _stage_idx)
fn mutate(&self, state: &mut S, input: &mut I, _stage_idx: i32) -> Result<(), Error> {
self.scheduled_mutate(state, input, _stage_idx)
}
}
impl<F, I, R, S> ComposedByMutations<F, I, S> for StdScheduledMutator<F, I, R, S>
impl<I, R, S> ComposedByMutations<I, S> for StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
#[inline]
fn mutation_by_idx(&self, index: usize) -> MutationFunction<F, I, Self, S> {
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S> {
self.mutations[index]
}
@ -105,12 +93,12 @@ where
}
#[inline]
fn add_mutation(&mut self, mutation: MutationFunction<F, I, Self, S>) {
fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>) {
self.mutations.push(mutation)
}
}
impl<F, I, R, S> ScheduledMutator<F, I, S> for StdScheduledMutator<F, I, R, S>
impl<I, R, S> ScheduledMutator<I, S> for StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
@ -128,7 +116,7 @@ where
}
}
impl<F, I, R, S> HasMaxSize for StdScheduledMutator<F, I, R, S>
impl<I, R, S> HasMaxSize for StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
@ -145,7 +133,7 @@ where
}
}
impl<F, I, R, S> StdScheduledMutator<F, I, R, S>
impl<I, R, S> StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
@ -161,7 +149,7 @@ where
}
/// Create a new StdScheduledMutator instance specifying mutations
pub fn with_mutations(mutations: Vec<MutationFunction<F, I, Self, S>>) -> Self {
pub fn with_mutations(mutations: Vec<MutationFunction<I, Self, S>>) -> Self {
StdScheduledMutator {
mutations: mutations,
max_size: DEFAULT_MAX_SIZE,
@ -172,35 +160,29 @@ where
/// Schedule some selected byte level mutations given a ScheduledMutator type
#[derive(Clone, Debug)]
pub struct HavocBytesMutator<C, F, I, R, S, SM>
pub struct HavocBytesMutator<C, I, R, S, SM>
where
SM: ScheduledMutator<F, I, S> + HasMaxSize,
SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>,
R: Rand,
{
scheduled: SM,
phantom: PhantomData<(C, F, I, R, S)>,
phantom: PhantomData<(C, I, R, S)>,
}
impl<C, F, I, R, S, SM> Mutator<F, I, S> for HavocBytesMutator<C, F, I, R, S, SM>
impl<C, I, R, S, SM> Mutator<I, S> for HavocBytesMutator<C, I, R, S, SM>
where
SM: ScheduledMutator<F, I, S> + HasMaxSize,
SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>,
R: Rand,
{
/// Mutate bytes
fn mutate(
&self,
fuzzer: &F,
state: &mut S,
input: &mut I,
stage_idx: i32,
) -> Result<(), Error> {
self.scheduled.mutate(fuzzer, state, input, stage_idx)?;
fn mutate(&self, state: &mut S, input: &mut I, stage_idx: i32) -> Result<(), Error> {
self.scheduled.mutate(state, input, stage_idx)?;
/*let num = self.scheduled.iterations(state, input);
for _ in 0..num {
let idx = self.scheduled.schedule(14, state, input);
@ -226,9 +208,9 @@ where
}
}
impl<C, F, I, R, S, SM> HasMaxSize for HavocBytesMutator<C, F, I, R, S, SM>
impl<C, I, R, S, SM> HasMaxSize for HavocBytesMutator<C, I, R, S, SM>
where
SM: ScheduledMutator<F, I, S> + HasMaxSize,
SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>,
@ -245,9 +227,9 @@ where
}
}
impl<C, F, I, R, S, SM> HavocBytesMutator<C, F, I, R, S, SM>
impl<C, I, R, S, SM> HavocBytesMutator<C, I, R, S, SM>
where
SM: ScheduledMutator<F, I, S> + HasMaxSize,
SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>,
@ -264,7 +246,7 @@ where
}
}
impl<C, F, I, R, S> Default for HavocBytesMutator<C, F, I, R, S, StdScheduledMutator<F, I, R, S>>
impl<C, I, R, S> Default for HavocBytesMutator<C, I, R, S, StdScheduledMutator<I, R, S>>
where
I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
@ -273,7 +255,7 @@ where
{
/// Create a new HavocBytesMutator instance wrapping StdScheduledMutator
fn default() -> Self {
let mut scheduled = StdScheduledMutator::<F, I, R, S>::new();
let mut scheduled = StdScheduledMutator::<I, R, S>::new();
scheduled.add_mutation(mutation_bitflip);
scheduled.add_mutation(mutation_byteflip);
scheduled.add_mutation(mutation_byteinc);

View File

@ -30,9 +30,8 @@ impl TokensMetadata {
}
/// Insert a dictionary token
pub fn mutation_tokeninsert<F, I, M, R, S>(
pub fn mutation_tokeninsert<I, M, R, S>(
mutator: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
@ -77,9 +76,8 @@ where
}
/// Overwrite with a dictionary token
pub fn mutation_tokenreplace<F, I, M, R, S>(
pub fn mutation_tokenreplace<I, M, R, S>(
_: &M,
_: &F,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>

View File

@ -1,15 +1,21 @@
pub mod mutational;
pub use mutational::StdMutationalStage;
use crate::{bolts::tuples::TupleList, Error};
use crate::{
bolts::tuples::TupleList, events::EventManager, executors::Executor, inputs::Input, Error,
};
/// A stage is one step in the fuzzing process.
/// Multiple stages will be scheduled one by one for each input.
pub trait Stage<E, EM, F, S> {
pub trait Stage<E, EM, I, S>
where
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{
/// Run the stage
fn perform(
&self,
fuzzer: &F,
state: &mut S,
executor: &mut E,
manager: &mut EM,
@ -17,10 +23,14 @@ pub trait Stage<E, EM, F, S> {
) -> Result<(), Error>;
}
pub trait StagesTuple<E, EM, F, S> {
pub trait StagesTuple<E, EM, I, S>
where
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{
fn perform_all(
&self,
fuzzer: &F,
state: &mut S,
executor: &mut E,
manager: &mut EM,
@ -28,28 +38,33 @@ pub trait StagesTuple<E, EM, F, S> {
) -> Result<(), Error>;
}
impl<E, EM, F, S> StagesTuple<E, EM, F, S> for () {
fn perform_all(&self, _: &F, _: &mut S, _: &mut E, _: &mut EM, _: usize) -> Result<(), Error> {
impl<E, EM, I, S> StagesTuple<E, EM, I, S> for ()
where
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{
fn perform_all(&self, _: &mut S, _: &mut E, _: &mut EM, _: usize) -> Result<(), Error> {
Ok(())
}
}
impl<Head, Tail, E, EM, F, S> StagesTuple<E, EM, F, S> for (Head, Tail)
impl<Head, Tail, E, EM, I, S> StagesTuple<E, EM, I, S> for (Head, Tail)
where
Head: Stage<E, EM, F, S>,
Tail: StagesTuple<E, EM, F, S> + TupleList,
Head: Stage<E, EM, I, S>,
Tail: StagesTuple<E, EM, I, S> + TupleList,
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{
fn perform_all(
&self,
fuzzer: &F,
state: &mut S,
executor: &mut E,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error> {
self.0
.perform(fuzzer, state, executor, manager, corpus_idx)?;
self.1
.perform_all(fuzzer, state, executor, manager, corpus_idx)
self.0.perform(state, executor, manager, corpus_idx)?;
self.1.perform_all(state, executor, manager, corpus_idx)
}
}

View File

@ -18,9 +18,9 @@ use crate::{
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
/// Mutational stages will usually have a range of mutations that are
/// being applied to the input one by one, between executions.
pub trait MutationalStage<C, E, EM, F, I, M, OT, S>: Stage<E, EM, F, S>
pub trait MutationalStage<C, E, EM, I, M, OT, S>: Stage<E, EM, I, S>
where
M: Mutator<F, I, S>,
M: Mutator<I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I>,
@ -40,7 +40,6 @@ where
/// Runs this (mutational) stage for the given testcase
fn perform_mutational(
&self,
fuzzer: &F,
state: &mut S,
executor: &mut E,
manager: &mut EM,
@ -54,12 +53,11 @@ where
.borrow_mut()
.load_input()?
.clone();
self.mutator()
.mutate(fuzzer, state, &mut input_mut, i as i32)?;
self.mutator().mutate(state, &mut input_mut, i as i32)?;
let fitness = state.evaluate_input(input_mut, executor, manager)?;
self.mutator().post_exec(fuzzer, state, fitness, i as i32)?;
self.mutator().post_exec(state, fitness, i as i32)?;
}
Ok(())
}
@ -69,9 +67,9 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
/// The default mutational stage
#[derive(Clone, Debug)]
pub struct StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
pub struct StdMutationalStage<C, E, EM, I, M, OT, R, S>
where
M: Mutator<F, I, S>,
M: Mutator<I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,
@ -81,13 +79,13 @@ where
R: Rand,
{
mutator: M,
phantom: PhantomData<(C, E, EM, F, I, OT, R, S)>,
phantom: PhantomData<(C, E, EM, I, OT, R, S)>,
}
impl<C, E, EM, F, I, M, OT, R, S> MutationalStage<C, E, EM, F, I, M, OT, S>
for StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
impl<C, E, EM, I, M, OT, R, S> MutationalStage<C, E, EM, I, M, OT, S>
for StdMutationalStage<C, E, EM, I, M, OT, R, S>
where
M: Mutator<F, I, S>,
M: Mutator<I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,
@ -114,10 +112,9 @@ where
}
}
impl<C, E, EM, F, I, M, OT, R, S> Stage<E, EM, F, S>
for StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
impl<C, E, EM, I, M, OT, R, S> Stage<E, EM, I, S> for StdMutationalStage<C, E, EM, I, M, OT, R, S>
where
M: Mutator<F, I, S>,
M: Mutator<I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,
@ -129,19 +126,18 @@ where
#[inline]
fn perform(
&self,
fuzzer: &F,
state: &mut S,
executor: &mut E,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), Error> {
self.perform_mutational(fuzzer, state, executor, manager, corpus_idx)
self.perform_mutational(state, executor, manager, corpus_idx)
}
}
impl<C, E, EM, F, I, M, OT, R, S> StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
impl<C, E, EM, I, M, OT, R, S> StdMutationalStage<C, E, EM, I, M, OT, R, S>
where
M: Mutator<F, I, S>,
M: Mutator<I, S>,
I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>,