moved fuzzer

This commit is contained in:
Dominik Maier 2021-02-05 01:06:07 +01:00
parent 21235e846e
commit 08a6196f6c
5 changed files with 213 additions and 193 deletions

View File

@ -28,8 +28,125 @@ pub mod utils;
use alloc::string::String;
use core::fmt;
use corpus::Corpus;
use events::EventManager;
use executors::{Executor, HasObservers};
use feedbacks::FeedbacksTuple;
use inputs::Input;
use observers::ObserversTuple;
use stages::StagesTuple;
use state::{HasCorpus, State};
use std::marker::PhantomData;
#[cfg(feature = "std")]
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};
use utils::{current_milliseconds, Rand};
/// The main fuzzer trait.
pub trait Fuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
fn stages(&self) -> &ST;
fn stages_mut(&mut self) -> &mut ST;
fn fuzz_one(
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, I, R, FT>,
manager: &mut EM,
) -> Result<usize, AflError> {
let (_, idx) = state.corpus_mut().next(rand)?;
self.stages_mut()
.perform_all(rand, executor, state, manager, idx)?;
manager.process(state)?;
Ok(idx)
}
fn fuzz_loop(
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, I, R, FT>,
manager: &mut EM,
) -> Result<(), AflError> {
let mut last = current_milliseconds();
loop {
self.fuzz_one(rand, executor, state, manager)?;
let cur = current_milliseconds();
if cur - last > 60 * 100 {
last = cur;
manager.update_stats(state.executions(), state.executions_over_seconds())?;
}
}
}
}
#[derive(Clone, Debug)]
pub struct StdFuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
stages: ST,
phantom: PhantomData<(EM, E, OT, FT, C, I, R)>,
}
impl<ST, EM, E, OT, FT, C, I, R> Fuzzer<ST, EM, E, OT, FT, C, I, R>
for StdFuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
fn stages(&self) -> &ST {
&self.stages
}
fn stages_mut(&mut self) -> &mut ST {
&mut self.stages
}
}
impl<ST, EM, E, OT, FT, C, I, R> StdFuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
pub fn new(stages: ST) -> Self {
Self {
stages: stages,
phantom: PhantomData,
}
}
}
/// Main error struct for AFL
#[derive(Debug)]
@ -112,3 +229,73 @@ impl From<ParseIntError> for AflError {
Self::Unknown(format!("Failed to parse Int: {:?}", err))
}
}
// TODO: no_std test
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use crate::{
corpus::{Corpus, InMemoryCorpus, Testcase},
executors::{Executor, ExitKind, InMemoryExecutor},
inputs::{BytesInput, Input},
mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator},
stages::StdMutationalStage,
state::{HasCorpus, State},
tuples::tuple_list,
utils::StdRand,
Fuzzer, StdFuzzer,
};
#[cfg(feature = "std")]
use crate::events::{LoggerEventManager, SimpleStats};
fn harness<E: Executor<I>, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind {
ExitKind::Ok
}
#[test]
fn test_fuzzer() {
let mut rand = StdRand::new(0);
let mut corpus = InMemoryCorpus::<BytesInput, StdRand>::new();
let testcase = Testcase::new(vec![0; 4]).into();
corpus.add(testcase);
let mut state = State::new(corpus, tuple_list!());
let mut event_manager = LoggerEventManager::new(SimpleStats::new(|s| {
println!("{}", s);
}));
let mut executor = InMemoryExecutor::new(
"main",
harness,
tuple_list!(),
//Box::new(|_, _, _, _, _| ()),
&mut state,
&mut event_manager,
);
let mut mutator = StdScheduledMutator::new();
mutator.add_mutation(mutation_bitflip);
let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
for i in 0..1000 {
fuzzer
.fuzz_one(&mut rand, &mut executor, &mut state, &mut event_manager)
.expect(&format!("Error in iter {}", i));
}
let state_serialized = postcard::to_allocvec(&state).unwrap();
let state_deserialized: State<InMemoryCorpus<BytesInput, _>, BytesInput, StdRand, ()> =
postcard::from_bytes(state_serialized.as_slice()).unwrap();
assert_eq!(state.executions(), state_deserialized.executions());
let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap();
let corpus_deserialized: InMemoryCorpus<BytesInput, StdRand> =
postcard::from_bytes(corpus_serialized.as_slice()).unwrap();
assert_eq!(state.corpus().count(), corpus_deserialized.count());
}
}

View File

@ -482,27 +482,34 @@ where
Ok(MutationResult::Mutated)
}
/*
// Insert a dictionary token
/* TODO
/// Insert a dictionary token
pub fn mutation_tokeninsert<I, M, R, S>(
mutator: &mut M,
rand: &mut R,
_: &mut S,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, AflError>
where
M: HasMaxSize,
I: Input + HasBytesVec,
R: Rand,
S: HasMetadata,
{
if mutator.tokens.size() == 0 { return Ok(MutationResult::Skipped); }
let tokens: Vec<Vec<u8>> = state.metadata().get().unwrap();
if mutator.tokens.size() == 0 {
return Ok(MutationResult::Skipped);
}
let token = &mutator.tokens[rand.below(token.size())];
let token_len = token.size();
let size = input.bytes().len();
let off = if size == 0 {
0
} else {
rand.below(core::cmp::min(size, (mutator.max_size() - token_len) as u64)) as usize
rand.below(core::cmp::min(
size,
(mutator.max_size() - token_len) as u64,
)) as usize
} as usize;
input.bytes_mut().resize(size + token_len, 0);
@ -510,27 +517,29 @@ where
Ok(MutationResult::Mutated)
}
// Overwrite with a dictionary token
pub fn mutation_tokenreplace<M, C, I, R>(
/// Overwrite with a dictionary token
pub fn mutation_tokenreplace<I, M, R, S>(
mutator: &mut M,
rand: &mut R,
_: &C,
state: &S,
input: &mut I,
) -> Result<MutationResult, AflError>
where
M: HasMaxSize,
I: Input + HasBytesVec,
R: Rand,
S: HasMetadata,
{
if mutator.tokens.size() > len || !len { return Ok(MutationResult::Skipped); }
if mutator.tokens.size() > len || !len {
return Ok(MutationResult::Skipped);
}
let token = &mutator.tokens[rand.below(token.size())];
let token_len = token.size();
let size = input.bytes().len();
let off rand.below((mutator.max_size() - token_len) as u64)) as usize;
let off = rand.below((mutator.max_size() - token_len) as u64) as usize;
mem_move(input.bytes_mut(), token, 0, off, len);
Ok(MutationResult::Mutated)
}
*/
pub fn mutation_bytesinsert<I, M, R, S>(

View File

@ -303,8 +303,10 @@ where
scheduled.add_mutation(mutation_bytescopy);
scheduled.add_mutation(mutation_bytesswap);
/*scheduled.add_mutation(mutation_tokeninsert);
scheduled.add_mutation(mutation_tokenreplace);*/
/* TODO
scheduled.add_mutation(mutation_tokeninsert);
scheduled.add_mutation(mutation_tokenreplace);
*/
// TODO: custom dictionary (redqueen etc.)

View File

@ -17,7 +17,6 @@ use crate::{
inputs::Input,
observers::ObserversTuple,
serde_anymap::{SerdeAny, SerdeAnyMap},
stages::StagesTuple,
utils::{current_milliseconds, Rand},
AflError,
};
@ -370,180 +369,3 @@ where
}
}
}
pub trait Fuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
fn stages(&self) -> &ST;
fn stages_mut(&mut self) -> &mut ST;
fn fuzz_one(
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, I, R, FT>,
manager: &mut EM,
) -> Result<usize, AflError> {
let (_, idx) = state.corpus_mut().next(rand)?;
self.stages_mut()
.perform_all(rand, executor, state, manager, idx)?;
manager.process(state)?;
Ok(idx)
}
fn fuzz_loop(
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, I, R, FT>,
manager: &mut EM,
) -> Result<(), AflError> {
let mut last = current_milliseconds();
loop {
self.fuzz_one(rand, executor, state, manager)?;
let cur = current_milliseconds();
if cur - last > 60 * 100 {
last = cur;
manager.update_stats(state.executions(), state.executions_over_seconds())?;
}
}
}
}
#[derive(Clone, Debug)]
pub struct StdFuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
stages: ST,
phantom: PhantomData<(EM, E, OT, FT, C, I, R)>,
}
impl<ST, EM, E, OT, FT, C, I, R> Fuzzer<ST, EM, E, OT, FT, C, I, R>
for StdFuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
fn stages(&self) -> &ST {
&self.stages
}
fn stages_mut(&mut self) -> &mut ST {
&mut self.stages
}
}
impl<ST, EM, E, OT, FT, C, I, R> StdFuzzer<ST, EM, E, OT, FT, C, I, R>
where
ST: StagesTuple<EM, E, OT, FT, C, I, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
I: Input,
R: Rand,
{
pub fn new(stages: ST) -> Self {
Self {
stages: stages,
phantom: PhantomData,
}
}
}
// TODO: no_std test
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use crate::{
corpus::{Corpus, InMemoryCorpus, Testcase},
executors::{Executor, ExitKind, InMemoryExecutor},
inputs::{BytesInput, Input},
mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator},
stages::StdMutationalStage,
state::{Fuzzer, State, StdFuzzer},
tuples::tuple_list,
utils::StdRand,
};
#[cfg(feature = "std")]
use crate::events::{LoggerEventManager, SimpleStats};
use super::HasCorpus;
fn harness<E: Executor<I>, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind {
ExitKind::Ok
}
#[test]
fn test_fuzzer() {
let mut rand = StdRand::new(0);
let mut corpus = InMemoryCorpus::<BytesInput, StdRand>::new();
let testcase = Testcase::new(vec![0; 4]).into();
corpus.add(testcase);
let mut state = State::new(corpus, tuple_list!());
let mut event_manager = LoggerEventManager::new(SimpleStats::new(|s| {
println!("{}", s);
}));
let mut executor = InMemoryExecutor::new(
"main",
harness,
tuple_list!(),
//Box::new(|_, _, _, _, _| ()),
&mut state,
&mut event_manager,
);
let mut mutator = StdScheduledMutator::new();
mutator.add_mutation(mutation_bitflip);
let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
for i in 0..1000 {
fuzzer
.fuzz_one(&mut rand, &mut executor, &mut state, &mut event_manager)
.expect(&format!("Error in iter {}", i));
}
let state_serialized = postcard::to_allocvec(&state).unwrap();
let state_deserialized: State<InMemoryCorpus<BytesInput, _>, BytesInput, StdRand, ()> =
postcard::from_bytes(state_serialized.as_slice()).unwrap();
assert_eq!(state.executions, state_deserialized.executions);
let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap();
let corpus_deserialized: InMemoryCorpus<BytesInput, StdRand> =
postcard::from_bytes(corpus_serialized.as_slice()).unwrap();
assert_eq!(state.corpus().count(), corpus_deserialized.count());
}
}

View File

@ -16,10 +16,10 @@ use afl::{
observers::StdMapObserver,
shmem::{AflShmem, ShMem},
stages::mutational::StdMutationalStage,
state::{Fuzzer, HasCorpus, State, StdFuzzer},
state::{HasCorpus, State},
tuples::tuple_list,
utils::{deserialize_state_corpus_mgr, StdRand},
AflError,
AflError, Fuzzer, StdFuzzer,
};
/// The llmp connection from the actual fuzzer to the process supervising it