scozz
This commit is contained in:
parent
1585645972
commit
c411fec271
@ -1,9 +1,9 @@
|
|||||||
//! Compare the speed of rand implementations
|
//! Compare the speed of rand implementations
|
||||||
|
|
||||||
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
use libafl::utils::{
|
use libafl::utils::{
|
||||||
Lehmer64Rand, Rand, RomuDuoJrRand, RomuTrioRand, XorShift64Rand, Xoshiro256StarRand,
|
Lehmer64Rand, Rand, RomuDuoJrRand, RomuTrioRand, XorShift64Rand, Xoshiro256StarRand,
|
||||||
};
|
};
|
||||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
||||||
|
|
||||||
fn criterion_benchmark(c: &mut Criterion) {
|
fn criterion_benchmark(c: &mut Criterion) {
|
||||||
let mut xorshift = XorShift64Rand::new(1);
|
let mut xorshift = XorShift64Rand::new(1);
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
#[cfg(target_os = "windows")]
|
windows::build!(
|
||||||
windows::build!(
|
windows::win32::system_services::HANDLE,
|
||||||
windows::win32::system_services::HANDLE,
|
windows::win32::windows_programming::CloseHandle,
|
||||||
windows::win32::windows_programming::CloseHandle,
|
// API needed for the shared memory
|
||||||
// API needed for the shared memory
|
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
|
||||||
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
|
);
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Bolts are no conceptual fuzzing elements, but they keep libafl-based fuzzers together.
|
//! Bolts are no conceptual fuzzing elements, but they keep libafl-based fuzzers together.
|
||||||
|
|
||||||
|
pub mod bindings;
|
||||||
pub mod llmp;
|
pub mod llmp;
|
||||||
pub mod ownedref;
|
pub mod ownedref;
|
||||||
pub mod serdeany;
|
pub mod serdeany;
|
||||||
pub mod shmem;
|
pub mod shmem;
|
||||||
pub mod tuples;
|
pub mod tuples;
|
||||||
pub mod bindings;
|
|
||||||
|
@ -330,8 +330,8 @@ pub mod shmem {
|
|||||||
use core::{mem::size_of, slice};
|
use core::{mem::size_of, slice};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use crate::Error;
|
|
||||||
use super::ShMem;
|
use super::ShMem;
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
/// The default Sharedmap impl for windows using shmctl & shmget
|
/// The default Sharedmap impl for windows using shmctl & shmget
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -343,7 +343,6 @@ pub mod shmem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO complete
|
// TODO complete
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -190,7 +190,7 @@ macro_rules! tuple_for_each {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ForEach for () {
|
impl ForEach for () {
|
||||||
fn for_each(&self) { }
|
fn for_each(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail> ForEach for (Head, Tail)
|
impl<Head, Tail> ForEach for (Head, Tail)
|
||||||
@ -221,7 +221,7 @@ macro_rules! tuple_for_each_mut {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ForEachMut for () {
|
impl ForEachMut for () {
|
||||||
fn for_each_mut(&mut self) { }
|
fn for_each_mut(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail> ForEachMut for (Head, Tail)
|
impl<Head, Tail> ForEachMut for (Head, Tail)
|
||||||
|
@ -7,12 +7,7 @@ use alloc::vec::Vec;
|
|||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{inputs::Input, Error};
|
||||||
inputs::Input,
|
|
||||||
state::{HasCorpus, HasRand},
|
|
||||||
utils::Rand,
|
|
||||||
Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Corpus with all current testcases
|
/// Corpus with all current testcases
|
||||||
pub trait Corpus<I>: serde::Serialize + serde::de::DeserializeOwned
|
pub trait Corpus<I>: serde::Serialize + serde::de::DeserializeOwned
|
||||||
@ -33,65 +28,41 @@ where
|
|||||||
|
|
||||||
/// Get by id
|
/// Get by id
|
||||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error>;
|
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error>;
|
||||||
|
|
||||||
|
/// Current testcase scheduled
|
||||||
|
fn current(&self) -> &Option<usize>;
|
||||||
|
|
||||||
|
/// Current testcase scheduled (mut)
|
||||||
|
fn current_mut(&mut self) -> &mut Option<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CorpusScheduler {
|
pub trait CorpusScheduler<I, S>
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
fn on_add<C, I, R, S>(
|
fn on_add(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
|
||||||
&self,
|
|
||||||
state: &mut S,
|
|
||||||
idx: usize,
|
|
||||||
testcase: &Testcase<I>,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
S: HasCorpus<C, I> + HasRand<R>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces the testcase at the given idx
|
/// Replaces the testcase at the given idx
|
||||||
fn on_replace<C, I, R, S>(
|
fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
|
||||||
&self,
|
|
||||||
state: &mut S,
|
|
||||||
idx: usize,
|
|
||||||
testcase: &Testcase<I>,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
S: HasCorpus<C, I> + HasRand<R>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 on_remove<C, I, R, S>(
|
fn on_remove(
|
||||||
&self,
|
&self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
testcase: &Option<Testcase<I>>,
|
testcase: &Option<Testcase<I>>,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error> {
|
||||||
where
|
|
||||||
S: HasCorpus<C, I> + HasRand<R>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: IntoIter
|
// TODO: IntoIter
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
fn next<C, I, R, S>(&self, state: &mut S) -> Result<usize, Error>
|
fn next(&self, state: &mut S) -> Result<usize, Error>;
|
||||||
where
|
|
||||||
S: HasCorpus<C, I> + HasRand<R>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -124,6 +95,7 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
entries: Vec<RefCell<Testcase<I>>>,
|
entries: Vec<RefCell<Testcase<I>>>,
|
||||||
|
current: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> Corpus<I> for InMemoryCorpus<I>
|
impl<I> Corpus<I> for InMemoryCorpus<I>
|
||||||
@ -168,4 +140,14 @@ where
|
|||||||
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
|
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
|
||||||
Ok(&self.entries[idx])
|
Ok(&self.entries[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Current testcase scheduled
|
||||||
|
fn current(&self) -> &Option<usize> {
|
||||||
|
&self.current
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current testcase scheduled (mut)
|
||||||
|
fn current_mut(&mut self) -> &mut Option<usize> {
|
||||||
|
&mut self.current
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,23 +39,25 @@ const _LLMP_TAG_RESTART: llmp::Tag = 0x8357A87;
|
|||||||
const _LLMP_TAG_NO_RESTART: llmp::Tag = 0x57A7EE71;
|
const _LLMP_TAG_NO_RESTART: llmp::Tag = 0x57A7EE71;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LlmpEventManager<I, SH, ST>
|
pub struct LlmpEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
//CE: CustomEvent<I>,
|
//CE: CustomEvent<I>,
|
||||||
{
|
{
|
||||||
stats: Option<ST>,
|
stats: Option<ST>,
|
||||||
llmp: llmp::LlmpConnection<SH>,
|
llmp: llmp::LlmpConnection<SH>,
|
||||||
phantom: PhantomData<I>,
|
phantom: PhantomData<(I, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl<I, ST> LlmpEventManager<I, UnixShMem, ST>
|
impl<I, S, ST> LlmpEventManager<I, S, UnixShMem, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I>,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
{
|
{
|
||||||
/// Create llmp on a port
|
/// Create llmp on a port
|
||||||
@ -78,9 +80,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, SH, ST> Drop for LlmpEventManager<I, SH, ST>
|
impl<I, S, SH, ST> Drop for LlmpEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
{
|
{
|
||||||
@ -90,9 +93,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, SH, ST> LlmpEventManager<I, SH, ST>
|
impl<I, S, SH, ST> LlmpEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
{
|
{
|
||||||
@ -248,7 +252,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle arriving events in the client
|
// Handle arriving events in the client
|
||||||
fn handle_in_client<E, OT, S>(
|
fn handle_in_client<E, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
sender_id: u32,
|
sender_id: u32,
|
||||||
@ -258,7 +262,6 @@ where
|
|||||||
where
|
where
|
||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
S: IfInteresting<I>,
|
|
||||||
{
|
{
|
||||||
match event {
|
match event {
|
||||||
Event::NewTestcase {
|
Event::NewTestcase {
|
||||||
@ -293,9 +296,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, SH, ST> EventManager<E, I, S> for LlmpEventManager<I, SH, ST>
|
impl<I, S, SH, ST> EventManager<I, S> for LlmpEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats, //CE: CustomEvent<I>,
|
ST: Stats, //CE: CustomEvent<I>,
|
||||||
{
|
{
|
||||||
@ -311,11 +315,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process<E, OT, S>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
|
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
|
||||||
where
|
where
|
||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
S: IfInteresting<I>,
|
|
||||||
{
|
{
|
||||||
// TODO: Get around local event copy by moving handle_in_client
|
// TODO: Get around local event copy by moving handle_in_client
|
||||||
let mut events = vec![];
|
let mut events = vec![];
|
||||||
@ -344,7 +347,7 @@ where
|
|||||||
Ok(count)
|
Ok(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fire<S>(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
|
fn fire(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> {
|
||||||
let serialized = postcard::to_allocvec(&event)?;
|
let serialized = postcard::to_allocvec(&event)?;
|
||||||
self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?;
|
self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -356,11 +359,11 @@ where
|
|||||||
/// This method is needed when the fuzzer run crashes and has to restart.
|
/// This method is needed when the fuzzer run crashes and has to restart.
|
||||||
pub fn serialize_state_mgr<I, S, SH, ST>(
|
pub fn serialize_state_mgr<I, S, SH, ST>(
|
||||||
state: &S,
|
state: &S,
|
||||||
mgr: &LlmpEventManager<I, SH, ST>,
|
mgr: &LlmpEventManager<I, S, SH, ST>,
|
||||||
) -> Result<Vec<u8>, Error>
|
) -> Result<Vec<u8>, Error>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
S: Serialize,
|
S: Serialize + IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
{
|
{
|
||||||
@ -370,10 +373,10 @@ where
|
|||||||
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
|
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
|
||||||
pub fn deserialize_state_mgr<I, S, SH, ST>(
|
pub fn deserialize_state_mgr<I, S, SH, ST>(
|
||||||
state_corpus_serialized: &[u8],
|
state_corpus_serialized: &[u8],
|
||||||
) -> Result<(S, LlmpEventManager<I, SH, ST>), Error>
|
) -> Result<(S, LlmpEventManager<I, S, SH, ST>), Error>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
S: DeserializeOwned,
|
S: DeserializeOwned + IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
{
|
{
|
||||||
@ -386,22 +389,24 @@ where
|
|||||||
|
|
||||||
/// A manager that can restart on the fly, storing states in-between (in `on_resatrt`)
|
/// A manager that can restart on the fly, storing states in-between (in `on_resatrt`)
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LlmpRestartingEventManager<I, SH, ST>
|
pub struct LlmpRestartingEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
//CE: CustomEvent<I>,
|
//CE: CustomEvent<I>,
|
||||||
{
|
{
|
||||||
/// The embedded llmp event manager
|
/// The embedded llmp event manager
|
||||||
llmp_mgr: LlmpEventManager<I, SH, ST>,
|
llmp_mgr: LlmpEventManager<I, S, SH, ST>,
|
||||||
/// The sender to serialize the state for the next runner
|
/// The sender to serialize the state for the next runner
|
||||||
sender: LlmpSender<SH>,
|
sender: LlmpSender<SH>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, SH, ST> EventManager<E, I, S> for LlmpRestartingEventManager<I, SH, ST>
|
impl<I, S, SH, ST> EventManager<I, S> for LlmpRestartingEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I> + Serialize,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats, //CE: CustomEvent<I>,
|
ST: Stats, //CE: CustomEvent<I>,
|
||||||
{
|
{
|
||||||
@ -413,10 +418,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner.
|
/// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner.
|
||||||
fn on_restart<S>(&mut self, state: &mut S) -> Result<(), Error>
|
fn on_restart(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
where
|
|
||||||
S: Serialize,
|
|
||||||
{
|
|
||||||
// First, reset the page to 0 so the next iteration can read read from the beginning of this page
|
// First, reset the page to 0 so the next iteration can read read from the beginning of this page
|
||||||
unsafe { self.sender.reset() };
|
unsafe { self.sender.reset() };
|
||||||
let state_corpus_serialized = serialize_state_mgr(state, &self.llmp_mgr)?;
|
let state_corpus_serialized = serialize_state_mgr(state, &self.llmp_mgr)?;
|
||||||
@ -424,16 +426,15 @@ where
|
|||||||
.send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized)
|
.send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process<E, OT, S>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
|
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
|
||||||
where
|
where
|
||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
S: IfInteresting<I>,
|
|
||||||
{
|
{
|
||||||
self.llmp_mgr.process(state, executor)
|
self.llmp_mgr.process(state, executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fire<S>(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
|
fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
|
||||||
// Check if we are going to crash in the event, in which case we store our current state for the next runner
|
// Check if we are going to crash in the event, in which case we store our current state for the next runner
|
||||||
self.llmp_mgr.fire(state, event)
|
self.llmp_mgr.fire(state, event)
|
||||||
}
|
}
|
||||||
@ -445,14 +446,15 @@ const _ENV_FUZZER_RECEIVER: &str = &"_AFL_ENV_FUZZER_RECEIVER";
|
|||||||
/// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages)
|
/// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages)
|
||||||
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = &"_AFL_ENV_FUZZER_BROKER_CLIENT";
|
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = &"_AFL_ENV_FUZZER_BROKER_CLIENT";
|
||||||
|
|
||||||
impl<I, SH, ST> LlmpRestartingEventManager<I, SH, ST>
|
impl<I, S, SH, ST> LlmpRestartingEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats, //CE: CustomEvent<I>,
|
ST: Stats, //CE: CustomEvent<I>,
|
||||||
{
|
{
|
||||||
/// Create a new runner, the executed child doing the actual fuzzing.
|
/// Create a new runner, the executed child doing the actual fuzzing.
|
||||||
pub fn new(llmp_mgr: LlmpEventManager<I, SH, ST>, sender: LlmpSender<SH>) -> Self {
|
pub fn new(llmp_mgr: LlmpEventManager<I, S, SH, ST>, sender: LlmpSender<SH>) -> Self {
|
||||||
Self { llmp_mgr, sender }
|
Self { llmp_mgr, sender }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,13 +473,13 @@ where
|
|||||||
/// The restarter will start a new process each time the child crashes or timeouts.
|
/// The restarter will start a new process each time the child crashes or timeouts.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn setup_restarting_mgr<I, S, SH, ST>(
|
pub fn setup_restarting_mgr<I, S, SH, ST>(
|
||||||
//mgr: &mut LlmpEventManager<I, SH, ST>,
|
//mgr: &mut LlmpEventManager<I, S, SH, ST>,
|
||||||
stats: ST,
|
stats: ST,
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
) -> Result<(Option<S>, LlmpRestartingEventManager<I, SH, ST>), Error>
|
) -> Result<(Option<S>, LlmpRestartingEventManager<I, S, SH, ST>), Error>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
S: DeserializeOwned,
|
S: DeserializeOwned + IfInteresting<I>,
|
||||||
SH: ShMem,
|
SH: ShMem,
|
||||||
ST: Stats,
|
ST: Stats,
|
||||||
{
|
{
|
||||||
@ -485,7 +487,7 @@ where
|
|||||||
|
|
||||||
// We start ourself as child process to actually fuzz
|
// We start ourself as child process to actually fuzz
|
||||||
if std::env::var(_ENV_FUZZER_SENDER).is_err() {
|
if std::env::var(_ENV_FUZZER_SENDER).is_err() {
|
||||||
mgr = LlmpEventManager::<I, SH, ST>::new_on_port(stats, broker_port)?;
|
mgr = LlmpEventManager::<I, S, SH, ST>::new_on_port(stats, broker_port)?;
|
||||||
if mgr.is_broker() {
|
if mgr.is_broker() {
|
||||||
// Yep, broker. Just loop here.
|
// Yep, broker. Just loop here.
|
||||||
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
|
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
|
||||||
@ -528,7 +530,7 @@ where
|
|||||||
None => {
|
None => {
|
||||||
println!("First run. Let's set it all up");
|
println!("First run. Let's set it all up");
|
||||||
// Mgr to send and receive msgs from/to all other fuzzer instances
|
// Mgr to send and receive msgs from/to all other fuzzer instances
|
||||||
let client_mgr = LlmpEventManager::<I, SH, ST>::existing_client_from_env(
|
let client_mgr = LlmpEventManager::<I, S, SH, ST>::existing_client_from_env(
|
||||||
_ENV_FUZZER_BROKER_CLIENT_INITIAL,
|
_ENV_FUZZER_BROKER_CLIENT_INITIAL,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -537,7 +539,7 @@ where
|
|||||||
// Restoring from a previous run, deserialize state and corpus.
|
// Restoring from a previous run, deserialize state and corpus.
|
||||||
Some((_sender, _tag, msg)) => {
|
Some((_sender, _tag, msg)) => {
|
||||||
println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len());
|
println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len());
|
||||||
let (state, mgr): (S, LlmpEventManager<I, SH, ST>) = deserialize_state_mgr(&msg)?;
|
let (state, mgr): (S, LlmpEventManager<I, S, SH, ST>) = deserialize_state_mgr(&msg)?;
|
||||||
|
|
||||||
(Some(state), LlmpRestartingEventManager::new(mgr, sender))
|
(Some(state), LlmpRestartingEventManager::new(mgr, sender))
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,16 @@ use core::marker::PhantomData;
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{BrokerEventResult, Event, EventManager},
|
events::{BrokerEventResult, Event, EventManager},
|
||||||
|
executors::{Executor, HasObservers},
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
|
observers::ObserversTuple,
|
||||||
stats::Stats,
|
stats::Stats,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A simple, single-threaded event manager that just logs
|
/// A simple, single-threaded event manager that just logs
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct LoggerEventManager<E, I, S, ST>
|
pub struct LoggerEventManager<I, S, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
ST: Stats, //CE: CustomEvent<I, OT>,
|
ST: Stats, //CE: CustomEvent<I, OT>,
|
||||||
@ -21,15 +23,19 @@ where
|
|||||||
stats: ST,
|
stats: ST,
|
||||||
/// The events that happened since the last handle_in_broker
|
/// The events that happened since the last handle_in_broker
|
||||||
events: Vec<Event<I>>,
|
events: Vec<Event<I>>,
|
||||||
phantom: PhantomData<(E, S)>,
|
phantom: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, I, S, ST> EventManager<E, I, S> for LoggerEventManager<E, I, S, ST>
|
impl<I, S, ST> EventManager<I, S> for LoggerEventManager<I, S, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
ST: Stats, //CE: CustomEvent<I, OT>,
|
ST: Stats, //CE: CustomEvent<I, OT>,
|
||||||
{
|
{
|
||||||
fn process(&mut self, state: &mut S, _executor: &mut E) -> Result<usize, Error> {
|
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
|
||||||
|
where
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
{
|
||||||
let count = self.events.len();
|
let count = self.events.len();
|
||||||
while self.events.len() > 0 {
|
while self.events.len() > 0 {
|
||||||
let event = self.events.pop().unwrap();
|
let event = self.events.pop().unwrap();
|
||||||
@ -47,7 +53,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, I, S, ST> LoggerEventManager<E, I, S, ST>
|
impl<I, S, ST> LoggerEventManager<I, S, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
ST: Stats, //TODO CE: CustomEvent,
|
ST: Stats, //TODO CE: CustomEvent,
|
||||||
|
@ -9,7 +9,10 @@ use core::{fmt, marker::PhantomData, time::Duration};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
executors::Executor, inputs::Input, observers::ObserversTuple, state::IfInteresting, Error,
|
executors::{Executor, HasObservers},
|
||||||
|
inputs::Input,
|
||||||
|
observers::ObserversTuple,
|
||||||
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The log event severity
|
/// The log event severity
|
||||||
@ -146,7 +149,7 @@ where
|
|||||||
|
|
||||||
/// EventManager is the main communications hub.
|
/// EventManager is the main communications hub.
|
||||||
/// For the "normal" multi-processed mode, you may want to look into `RestartingEventManager`
|
/// For the "normal" multi-processed mode, you may want to look into `RestartingEventManager`
|
||||||
pub trait EventManager<E, I, S>
|
pub trait EventManager<I, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
@ -155,7 +158,10 @@ where
|
|||||||
|
|
||||||
/// Lookup for incoming events and process them.
|
/// Lookup for incoming events and process them.
|
||||||
/// Return the number of processes events or an error
|
/// Return the number of processes events or an error
|
||||||
fn process(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>;
|
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
|
||||||
|
where
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple;
|
||||||
|
|
||||||
/// Serialize all observers for this type and manager
|
/// Serialize all observers for this type and manager
|
||||||
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
|
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
|
||||||
@ -189,16 +195,17 @@ where
|
|||||||
|
|
||||||
/// An eventmgr for tests, and as placeholder if you really don't need an event manager.
|
/// An eventmgr for tests, and as placeholder if you really don't need an event manager.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct NopEventManager<E, I, S> {
|
pub struct NopEventManager<I, S> {
|
||||||
phantom: PhantomData<(E, I, S)>,
|
phantom: PhantomData<(I, S)>,
|
||||||
}
|
}
|
||||||
impl<E, I, S> EventManager<E, I, S> for NopEventManager<E, I, S>
|
impl<I, S> EventManager<I, S> for NopEventManager<I, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn process(&mut self, _state: &mut S, _executor: &mut E) -> Result<usize, Error>
|
fn process<E, OT>(&mut self, state: &mut S, executor: &mut E) -> Result<usize, Error>
|
||||||
where
|
where
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn pre_exec<EM, S>(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error>
|
fn pre_exec<EM, S>(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
{
|
{
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -69,7 +69,7 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn post_exec<EM, S>(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error>
|
fn post_exec<EM, S>(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
{
|
{
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -132,7 +132,7 @@ where
|
|||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OFT: FeedbacksTuple<I>,
|
OFT: FeedbacksTuple<I>,
|
||||||
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
|
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
|
||||||
@ -200,7 +200,7 @@ pub mod unix_signals {
|
|||||||
info: siginfo_t,
|
info: siginfo_t,
|
||||||
_void: c_void,
|
_void: c_void,
|
||||||
) where
|
) where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OFT: FeedbacksTuple<I>,
|
OFT: FeedbacksTuple<I>,
|
||||||
@ -273,7 +273,7 @@ pub mod unix_signals {
|
|||||||
info: siginfo_t,
|
info: siginfo_t,
|
||||||
_void: c_void,
|
_void: c_void,
|
||||||
) where
|
) where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OFT: FeedbacksTuple<I>,
|
OFT: FeedbacksTuple<I>,
|
||||||
@ -346,7 +346,7 @@ pub mod unix_signals {
|
|||||||
|
|
||||||
pub unsafe fn setup_crash_handlers<EM, I, OC, OFT, OT, R, S>()
|
pub unsafe fn setup_crash_handlers<EM, I, OC, OFT, OT, R, S>()
|
||||||
where
|
where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
OC: Corpus<I>,
|
OC: Corpus<I>,
|
||||||
OFT: FeedbacksTuple<I>,
|
OFT: FeedbacksTuple<I>,
|
||||||
|
@ -87,21 +87,16 @@ where
|
|||||||
_input: &I,
|
_input: &I,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Called right after execution finished.
|
/// Called right after execution finished.
|
||||||
fn post_exec<EM, S>(
|
fn post_exec<EM, S>(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error>
|
||||||
&mut self,
|
|
||||||
_state: &S,
|
|
||||||
_event_mgr: &mut EM,
|
|
||||||
_input: &I,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
where
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, S>,
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, CorpusScheduler},
|
corpus::CorpusScheduler,
|
||||||
events::{Event, EventManager},
|
events::{Event, EventManager},
|
||||||
executors::Executor,
|
executors::{Executor, HasObservers},
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
|
observers::ObserversTuple,
|
||||||
stages::StagesTuple,
|
stages::StagesTuple,
|
||||||
state::{HasCorpus, HasExecutions, HasRand},
|
state::HasExecutions,
|
||||||
utils::{current_milliseconds, current_time, Rand},
|
utils::{current_milliseconds, current_time},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
/// Holds a set of stages
|
/// Holds a set of stages
|
||||||
pub trait HasStages<ST, I>
|
pub trait HasStages<ST, E, EM, S>: Sized
|
||||||
where
|
where
|
||||||
ST: StagesTuple<I>,
|
ST: StagesTuple<E, EM, Self, S>,
|
||||||
I: Input,
|
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &ST;
|
fn stages(&self) -> &ST;
|
||||||
|
|
||||||
@ -22,9 +22,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Holds a scheduler
|
/// Holds a scheduler
|
||||||
pub trait HasCorpusScheduler<CS>
|
pub trait HasCorpusScheduler<CS, I, S>
|
||||||
where
|
where
|
||||||
CS: CorpusScheduler,
|
CS: CorpusScheduler<I, S>,
|
||||||
|
I: Input,
|
||||||
{
|
{
|
||||||
fn scheduler(&self) -> &CS;
|
fn scheduler(&self) -> &CS;
|
||||||
|
|
||||||
@ -32,50 +33,29 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The main fuzzer trait.
|
/// The main fuzzer trait.
|
||||||
pub trait Fuzzer<CS, ST, I>: HasCorpusScheduler<CS> + HasStages<ST, I>
|
pub trait Fuzzer<E, EM, S> {
|
||||||
where
|
fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error>;
|
||||||
CS: CorpusScheduler,
|
|
||||||
ST: StagesTuple<I>,
|
|
||||||
I: Input,
|
|
||||||
{
|
|
||||||
fn fuzz_one<E, EM, S>(
|
|
||||||
&self,
|
|
||||||
state: &mut S,
|
|
||||||
executor: &mut E,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<usize, Error>
|
|
||||||
where
|
|
||||||
EM: EventManager<I>,
|
|
||||||
E: Executor<I>;
|
|
||||||
|
|
||||||
fn fuzz_loop<E, EM, S>(
|
fn fuzz_loop(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error>;
|
||||||
&self,
|
|
||||||
state: &mut S,
|
|
||||||
executor: &mut E,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<usize, Error>
|
|
||||||
where
|
|
||||||
EM: EventManager<I>,
|
|
||||||
E: Executor<I>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Your default fuzzer instance, for everyday use.
|
/// Your default fuzzer instance, for everyday use.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StdFuzzer<CS, ST, I>
|
pub struct StdFuzzer<CS, ST, E, EM, I, OT, S>
|
||||||
where
|
where
|
||||||
CS: CorpusScheduler,
|
CS: CorpusScheduler<I, S>,
|
||||||
ST: StagesTuple<I>,
|
ST: StagesTuple<E, EM, Self, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
scheduler: CS,
|
scheduler: CS,
|
||||||
stages: ST,
|
stages: ST,
|
||||||
phantom: PhantomData<I>,
|
phantom: PhantomData<(E, EM, I, OT, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, ST, I> HasStages<ST, I> for StdFuzzer<CS, ST, I>
|
impl<CS, ST, E, EM, I, OT, S> HasStages<ST, E, EM, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
|
||||||
where
|
where
|
||||||
CS: CorpusScheduler,
|
CS: CorpusScheduler<I, S>,
|
||||||
ST: StagesTuple<I>,
|
ST: StagesTuple<E, EM, Self, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn stages(&self) -> &ST {
|
fn stages(&self) -> &ST {
|
||||||
@ -87,10 +67,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, ST, I> HasCorpusScheduler<CS> for StdFuzzer<CS, ST, I>
|
impl<CS, ST, E, EM, I, OT, S> HasCorpusScheduler<CS, I, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
|
||||||
where
|
where
|
||||||
CS: CorpusScheduler,
|
CS: CorpusScheduler<I, S>,
|
||||||
ST: StagesTuple<I>,
|
ST: StagesTuple<E, EM, Self, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn scheduler(&self) -> &CS {
|
fn scheduler(&self) -> &CS {
|
||||||
@ -102,25 +82,17 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, ST, I> Fuzzer<CS, ST, I> for StdFuzzer<CS, ST, I>
|
impl<CS, ST, E, EM, I, OT, S> Fuzzer<E, EM, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
|
||||||
where
|
where
|
||||||
CS: CorpusScheduler,
|
CS: CorpusScheduler<I, S>,
|
||||||
ST: StagesTuple<I>,
|
S: HasExecutions,
|
||||||
|
ST: StagesTuple<E, EM, Self, S>,
|
||||||
|
EM: EventManager<I, S>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn fuzz_one<C, E, EM, R, S>(
|
fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error> {
|
||||||
&self,
|
|
||||||
state: &mut S,
|
|
||||||
executor: &mut E,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<usize, Error>
|
|
||||||
where
|
|
||||||
EM: EventManager<I>,
|
|
||||||
E: Executor<I>,
|
|
||||||
S: HasCorpus<C, I> + HasRand<R>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
let idx = self.scheduler().next(state)?;
|
let idx = self.scheduler().next(state)?;
|
||||||
|
|
||||||
self.stages()
|
self.stages()
|
||||||
@ -130,19 +102,7 @@ where
|
|||||||
Ok(idx)
|
Ok(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fuzz_loop<C, E, EM, R, S>(
|
fn fuzz_loop(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error> {
|
||||||
&self,
|
|
||||||
state: &mut S,
|
|
||||||
executor: &mut E,
|
|
||||||
manager: &mut EM,
|
|
||||||
) -> Result<usize, Error>
|
|
||||||
where
|
|
||||||
EM: EventManager<I>,
|
|
||||||
E: Executor<I>,
|
|
||||||
S: HasCorpus<C, I> + HasRand<R> + HasExecutions,
|
|
||||||
C: Corpus<I>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
let mut last = current_milliseconds();
|
let mut last = current_milliseconds();
|
||||||
loop {
|
loop {
|
||||||
self.fuzz_one(state, executor, manager)?;
|
self.fuzz_one(state, executor, manager)?;
|
||||||
@ -162,10 +122,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CS, ST, I> StdFuzzer<CS, ST, I>
|
impl<CS, ST, E, EM, I, OT, S> StdFuzzer<CS, ST, E, EM, I, OT, S>
|
||||||
where
|
where
|
||||||
CS: CorpusScheduler,
|
CS: CorpusScheduler<I, S>,
|
||||||
ST: StagesTuple<I>,
|
ST: StagesTuple<E, EM, Self, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
pub fn new(scheduler: CS, stages: ST) -> Self {
|
pub fn new(scheduler: CS, stages: ST) -> Self {
|
||||||
|
@ -5,7 +5,7 @@ use alloc::{borrow::ToOwned, rc::Rc, vec::Vec};
|
|||||||
use core::{cell::RefCell, convert::From};
|
use core::{cell::RefCell, convert::From};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::inputs::{HasBytesVec, HasTargetBytes, HasLen, Input, TargetBytes};
|
use crate::inputs::{HasBytesVec, HasLen, HasTargetBytes, Input, TargetBytes};
|
||||||
|
|
||||||
/// A bytes input is the basic input
|
/// A bytes input is the basic input
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
|
||||||
|
@ -106,4 +106,3 @@ pub trait HasLen {
|
|||||||
/// The lenght
|
/// The lenght
|
||||||
fn len(&self) -> usize;
|
fn len(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ pub mod fuzzer;
|
|||||||
pub use fuzzer::*;
|
pub use fuzzer::*;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::{fmt};
|
use core::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};
|
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};
|
||||||
|
@ -7,32 +7,24 @@ pub use mutations::*;
|
|||||||
pub mod token_mutations;
|
pub mod token_mutations;
|
||||||
pub use token_mutations::*;
|
pub use token_mutations::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{inputs::Input, Error};
|
||||||
inputs::Input,
|
|
||||||
Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO mutator stats method that produces something that can be sent with the NewTestcase event
|
// TODO mutator stats method that produces something that can be sent with the NewTestcase event
|
||||||
// We can use it to report which mutations generated the testcase in the broker logs
|
// We can use it to report which mutations generated the testcase in the broker logs
|
||||||
|
|
||||||
/// A mutator takes input, and mutates it.
|
/// A mutator takes input, and mutates it.
|
||||||
/// Simple as that.
|
/// Simple as that.
|
||||||
pub trait Mutator<I>
|
pub trait Mutator<F, I, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Mutate a given input
|
/// Mutate a given input
|
||||||
fn mutate<F, S>(
|
fn mutate(&self, fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32)
|
||||||
&mut self,
|
-> Result<(), Error>;
|
||||||
fuzzer: &F,
|
|
||||||
state: &mut S,
|
|
||||||
input: &mut I,
|
|
||||||
stage_idx: i32,
|
|
||||||
) -> Result<(), Error>;
|
|
||||||
|
|
||||||
/// Post-process given the outcome of the execution
|
/// Post-process given the outcome of the execution
|
||||||
fn post_exec<F, S>(
|
fn post_exec(
|
||||||
&mut self,
|
&self,
|
||||||
_fuzzer: &F,
|
_fuzzer: &F,
|
||||||
_state: &mut S,
|
_state: &mut S,
|
||||||
_is_interesting: u32,
|
_is_interesting: u32,
|
||||||
|
@ -27,8 +27,7 @@ pub enum MutationResult {
|
|||||||
|
|
||||||
// TODO maybe the mutator arg is not needed
|
// TODO maybe the mutator arg is not needed
|
||||||
/// The generic function type that identifies mutations
|
/// The generic function type that identifies mutations
|
||||||
pub type MutationFunction<F, I, M, S> =
|
pub type MutationFunction<F, I, M, S> = fn(&M, &F, &mut S, &mut I) -> Result<MutationResult, Error>;
|
||||||
fn(&mut M, &F, &mut S, &mut I) -> Result<MutationResult, Error>;
|
|
||||||
|
|
||||||
pub trait ComposedByMutations<F, I, S>
|
pub trait ComposedByMutations<F, I, S>
|
||||||
where
|
where
|
||||||
@ -125,7 +124,7 @@ const INTERESTING_32: [i32; 27] = [
|
|||||||
|
|
||||||
/// Bitflip mutation for inputs with a bytes vector
|
/// Bitflip mutation for inputs with a bytes vector
|
||||||
pub fn mutation_bitflip<F, I, M, R, S>(
|
pub fn mutation_bitflip<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -148,7 +147,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_byteflip<F, I, M, R, S>(
|
pub fn mutation_byteflip<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -171,7 +170,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_byteinc<F, I, M, R, S>(
|
pub fn mutation_byteinc<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -195,7 +194,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytedec<F, I, M, R, S>(
|
pub fn mutation_bytedec<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -219,7 +218,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_byteneg<F, I, M, R, S>(
|
pub fn mutation_byteneg<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -242,7 +241,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_byterand<F, I, M, R, S>(
|
pub fn mutation_byterand<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -265,7 +264,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_byteadd<F, I, M, R, S>(
|
pub fn mutation_byteadd<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -293,7 +292,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_wordadd<F, I, M, R, S>(
|
pub fn mutation_wordadd<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -323,7 +322,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_dwordadd<F, I, M, R, S>(
|
pub fn mutation_dwordadd<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -353,7 +352,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_qwordadd<F, I, M, R, S>(
|
pub fn mutation_qwordadd<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -383,7 +382,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_byteinteresting<F, I, M, R, S>(
|
pub fn mutation_byteinteresting<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -407,7 +406,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_wordinteresting<F, I, M, R, S>(
|
pub fn mutation_wordinteresting<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -437,7 +436,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_dwordinteresting<F, I, M, R, S>(
|
pub fn mutation_dwordinteresting<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -467,7 +466,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytesdelete<F, I, M, R, S>(
|
pub fn mutation_bytesdelete<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -490,7 +489,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytesexpand<F, I, M, R, S>(
|
pub fn mutation_bytesexpand<F, I, M, R, S>(
|
||||||
mutator: &mut M,
|
mutator: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -520,7 +519,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytesinsert<F, I, M, R, S>(
|
pub fn mutation_bytesinsert<F, I, M, R, S>(
|
||||||
mutator: &mut M,
|
mutator: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -553,7 +552,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytesrandinsert<F, I, M, R, S>(
|
pub fn mutation_bytesrandinsert<F, I, M, R, S>(
|
||||||
mutator: &mut M,
|
mutator: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -586,7 +585,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytesset<F, I, M, R, S>(
|
pub fn mutation_bytesset<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -611,7 +610,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytesrandset<F, I, M, R, S>(
|
pub fn mutation_bytesrandset<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -636,7 +635,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytescopy<F, I, M, R, S>(
|
pub fn mutation_bytescopy<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -661,7 +660,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutation_bytesswap<F, I, M, R, S>(
|
pub fn mutation_bytesswap<F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -689,7 +688,7 @@ where
|
|||||||
|
|
||||||
/// Crossover insert mutation
|
/// Crossover insert mutation
|
||||||
pub fn mutation_crossover_insert<C, F, I, M, R, S>(
|
pub fn mutation_crossover_insert<C, F, I, M, R, S>(
|
||||||
mutator: &mut M,
|
mutator: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -704,10 +703,13 @@ where
|
|||||||
let size = input.bytes().len();
|
let size = input.bytes().len();
|
||||||
|
|
||||||
// We don't want to use the testcase we're already using for splicing
|
// We don't want to use the testcase we're already using for splicing
|
||||||
let (other_testcase, idx) = state.random_corpus_entry()?;
|
let idx = state.rand_mut().below(state.corpus().count() as u64) as usize;
|
||||||
if idx == state.corpus().current_testcase().1 {
|
if let Some(cur) = state.corpus().current() {
|
||||||
return Ok(MutationResult::Skipped);
|
if idx == *cur {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let other_testcase = state.corpus().get(idx)?;
|
||||||
|
|
||||||
let mut other_ref = other_testcase.borrow_mut();
|
let mut other_ref = other_testcase.borrow_mut();
|
||||||
let other = other_ref.load_input()?;
|
let other = other_ref.load_input()?;
|
||||||
@ -738,7 +740,7 @@ where
|
|||||||
|
|
||||||
/// Crossover replace mutation
|
/// Crossover replace mutation
|
||||||
pub fn mutation_crossover_replace<C, F, I, M, R, S>(
|
pub fn mutation_crossover_replace<C, F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -752,10 +754,13 @@ where
|
|||||||
let size = input.bytes().len();
|
let size = input.bytes().len();
|
||||||
|
|
||||||
// We don't want to use the testcase we're already using for splicing
|
// We don't want to use the testcase we're already using for splicing
|
||||||
let (other_testcase, idx) = state.random_corpus_entry()?;
|
let idx = state.rand_mut().below(state.corpus().count() as u64) as usize;
|
||||||
if idx == state.corpus().current_testcase().1 {
|
if let Some(cur) = state.corpus().current() {
|
||||||
return Ok(MutationResult::Skipped);
|
if idx == *cur {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let other_testcase = state.corpus().get(idx)?;
|
||||||
|
|
||||||
let mut other_ref = other_testcase.borrow_mut();
|
let mut other_ref = other_testcase.borrow_mut();
|
||||||
let other = other_ref.load_input()?;
|
let other = other_ref.load_input()?;
|
||||||
@ -792,7 +797,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
|||||||
|
|
||||||
/// Splicing mutation from AFL
|
/// Splicing mutation from AFL
|
||||||
pub fn mutation_splice<C, F, I, M, R, S>(
|
pub fn mutation_splice<C, F, I, M, R, S>(
|
||||||
_: &mut M,
|
_: &M,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -804,10 +809,13 @@ where
|
|||||||
S: HasRand<R> + HasCorpus<C, I>,
|
S: HasRand<R> + HasCorpus<C, I>,
|
||||||
{
|
{
|
||||||
// We don't want to use the testcase we're already using for splicing
|
// We don't want to use the testcase we're already using for splicing
|
||||||
let (other_testcase, idx) = state.random_corpus_entry()?;
|
let idx = state.rand_mut().below(state.corpus().count() as u64) as usize;
|
||||||
if idx == state.corpus().current_testcase().1 {
|
if let Some(cur) = state.corpus().current() {
|
||||||
return Ok(MutationResult::Skipped);
|
if idx == *cur {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let other_testcase = state.corpus().get(idx)?;
|
||||||
|
|
||||||
let mut other_ref = other_testcase.borrow_mut();
|
let mut other_ref = other_testcase.borrow_mut();
|
||||||
let other = other_ref.load_input()?;
|
let other = other_ref.load_input()?;
|
||||||
|
@ -15,27 +15,20 @@ use crate::{
|
|||||||
pub use crate::mutators::mutations::*;
|
pub use crate::mutators::mutations::*;
|
||||||
pub use crate::mutators::token_mutations::*;
|
pub use crate::mutators::token_mutations::*;
|
||||||
|
|
||||||
pub trait ScheduledMutator<F, I, S>: Mutator<I> + ComposedByMutations<F, I, S>
|
pub trait ScheduledMutator<F, I, S>: Mutator<F, I, S> + ComposedByMutations<F, I, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Compute the number of iterations used to apply stacked mutations
|
/// Compute the number of iterations used to apply stacked mutations
|
||||||
fn iterations(&mut self, state: &mut S, input: &I) -> u64;
|
fn iterations(&self, state: &mut S, input: &I) -> u64;
|
||||||
//{
|
|
||||||
// 1 << (1 + state.rand_mut().below(6))
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// Get the next mutation to apply
|
/// Get the next mutation to apply
|
||||||
fn schedule(&mut self, mutations_count: usize, state: &mut S, input: &I) -> usize;
|
fn schedule(&self, mutations_count: usize, state: &mut S, input: &I) -> usize;
|
||||||
//{
|
|
||||||
// debug_assert!(mutations_count > 0);
|
|
||||||
// rand.below(mutations_count as u64) as usize
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// New default implementation for mutate
|
/// New default implementation for mutate
|
||||||
/// Implementations must forward mutate() to this method
|
/// Implementations must forward mutate() to this method
|
||||||
fn scheduled_mutate(
|
fn scheduled_mutate(
|
||||||
&mut self,
|
&self,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -50,18 +43,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub struct StdScheduledMutator<F, I, R, S>
|
||||||
pub struct StdScheduledMutator<F, I, S>
|
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
mutations: Vec<MutationFunction<F, I, Self, S>>,
|
mutations: Vec<MutationFunction<F, I, Self, S>>,
|
||||||
max_size: usize,
|
max_size: usize,
|
||||||
|
phantom: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, I, S> Debug for StdScheduledMutator<F, I, S>
|
impl<F, I, R, S> Debug for StdScheduledMutator<F, I, R, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
@ -74,12 +71,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, I, S> Mutator<I> for StdScheduledMutator<F, I, S>
|
impl<F, I, R, S> Mutator<F, I, S> for StdScheduledMutator<F, I, R, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
fn mutate(
|
fn mutate(
|
||||||
&mut self,
|
&self,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
@ -89,9 +88,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, I, S> ComposedByMutations<F, I, S> for StdScheduledMutator<F, I, S>
|
impl<F, I, R, S> ComposedByMutations<F, I, S> for StdScheduledMutator<F, I, R, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mutation_by_idx(&self, index: usize) -> MutationFunction<F, I, Self, S> {
|
fn mutation_by_idx(&self, index: usize) -> MutationFunction<F, I, Self, S> {
|
||||||
@ -109,16 +110,29 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, I, S> ScheduledMutator<F, I, S> for StdScheduledMutator<F, I, S>
|
impl<F, I, R, S> ScheduledMutator<F, I, S> for StdScheduledMutator<F, I, R, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
// Just use the default methods
|
/// Compute the number of iterations used to apply stacked mutations
|
||||||
|
fn iterations(&self, state: &mut S, input: &I) -> u64 {
|
||||||
|
1 << (1 + state.rand_mut().below(6))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next mutation to apply
|
||||||
|
fn schedule(&self, mutations_count: usize, state: &mut S, input: &I) -> usize {
|
||||||
|
debug_assert!(mutations_count > 0);
|
||||||
|
state.rand_mut().below(mutations_count as u64) as usize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, I, S> HasMaxSize for StdScheduledMutator<F, I, S>
|
impl<F, I, R, S> HasMaxSize for StdScheduledMutator<F, I, R, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn max_size(&self) -> usize {
|
fn max_size(&self) -> usize {
|
||||||
@ -131,15 +145,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, I, S> StdScheduledMutator<F, I, S>
|
impl<F, I, R, S> StdScheduledMutator<F, I, R, S>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasRand<R>,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Create a new StdScheduledMutator instance without mutations and corpus
|
/// Create a new StdScheduledMutator instance without mutations and corpus
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mutations: vec![],
|
mutations: vec![],
|
||||||
max_size: DEFAULT_MAX_SIZE,
|
max_size: DEFAULT_MAX_SIZE,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +165,7 @@ where
|
|||||||
StdScheduledMutator {
|
StdScheduledMutator {
|
||||||
mutations: mutations,
|
mutations: mutations,
|
||||||
max_size: DEFAULT_MAX_SIZE,
|
max_size: DEFAULT_MAX_SIZE,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,7 +184,7 @@ where
|
|||||||
phantom: PhantomData<(C, F, I, R, S)>,
|
phantom: PhantomData<(C, F, I, R, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, F, I, R, S, SM> Mutator<I> for HavocBytesMutator<C, F, I, R, S, SM>
|
impl<C, F, I, R, S, SM> Mutator<F, I, S> for HavocBytesMutator<C, F, I, R, S, SM>
|
||||||
where
|
where
|
||||||
SM: ScheduledMutator<F, I, S> + HasMaxSize,
|
SM: ScheduledMutator<F, I, S> + HasMaxSize,
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
@ -176,8 +194,8 @@ where
|
|||||||
{
|
{
|
||||||
/// Mutate bytes
|
/// Mutate bytes
|
||||||
fn mutate(
|
fn mutate(
|
||||||
&mut self,
|
&self,
|
||||||
fuzzer: &mut F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
input: &mut I,
|
input: &mut I,
|
||||||
stage_idx: i32,
|
stage_idx: i32,
|
||||||
@ -246,7 +264,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, F, I, R, S> Default for HavocBytesMutator<C, F, I, R, S, StdScheduledMutator<F, I, S>>
|
impl<C, F, I, R, S> Default for HavocBytesMutator<C, F, I, R, S, StdScheduledMutator<F, I, R, S>>
|
||||||
where
|
where
|
||||||
I: Input + HasBytesVec,
|
I: Input + HasBytesVec,
|
||||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
|
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
|
||||||
@ -255,7 +273,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Create a new HavocBytesMutator instance wrapping StdScheduledMutator
|
/// Create a new HavocBytesMutator instance wrapping StdScheduledMutator
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut scheduled = StdScheduledMutator::<F, I, S>::new();
|
let mut scheduled = StdScheduledMutator::<F, I, R, S>::new();
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bitflip);
|
||||||
scheduled.add_mutation(mutation_byteflip);
|
scheduled.add_mutation(mutation_byteflip);
|
||||||
scheduled.add_mutation(mutation_byteinc);
|
scheduled.add_mutation(mutation_byteinc);
|
||||||
@ -283,8 +301,8 @@ where
|
|||||||
scheduled.add_mutation(mutation_bytescopy);
|
scheduled.add_mutation(mutation_bytescopy);
|
||||||
scheduled.add_mutation(mutation_bytesswap);
|
scheduled.add_mutation(mutation_bytesswap);
|
||||||
|
|
||||||
scheduled.add_mutation(mutation_tokeninsert);
|
//scheduled.add_mutation(mutation_tokeninsert);
|
||||||
scheduled.add_mutation(mutation_tokenreplace);
|
//scheduled.add_mutation(mutation_tokenreplace);
|
||||||
|
|
||||||
scheduled.add_mutation(mutation_crossover_insert);
|
scheduled.add_mutation(mutation_crossover_insert);
|
||||||
scheduled.add_mutation(mutation_crossover_replace);
|
scheduled.add_mutation(mutation_crossover_replace);
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
inputs::{HasBytesVec, Input},
|
inputs::{HasBytesVec, Input},
|
||||||
state::{HasRand, HasMetadata},
|
|
||||||
mutators::*,
|
mutators::*,
|
||||||
|
state::{HasMetadata, HasRand},
|
||||||
utils::Rand,
|
utils::Rand,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
pub mod mutational;
|
pub mod mutational;
|
||||||
pub use mutational::StdMutationalStage;
|
pub use mutational::StdMutationalStage;
|
||||||
|
|
||||||
use crate::{
|
use crate::{bolts::tuples::TupleList, corpus::Corpus, Error};
|
||||||
bolts::tuples::TupleList, corpus::Corpus, events::EventManager, executors::Executor,
|
|
||||||
inputs::Input, Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A stage is one step in the fuzzing process.
|
/// A stage is one step in the fuzzing process.
|
||||||
/// Multiple stages will be scheduled one by one for each input.
|
/// Multiple stages will be scheduled one by one for each input.
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
corpus::Corpus,
|
||||||
events::EventManager,
|
events::EventManager,
|
||||||
executors::Executor,
|
executors::{Executor, HasObservers},
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
mutators::Mutator,
|
mutators::Mutator,
|
||||||
stages::Corpus,
|
observers::ObserversTuple,
|
||||||
stages::Stage,
|
stages::Stage,
|
||||||
state::HasRand,
|
state::{Evaluator, HasCorpus, HasRand},
|
||||||
state::{Evaluator, HasCorpus},
|
|
||||||
utils::Rand,
|
utils::Rand,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -18,10 +18,15 @@ use crate::{
|
|||||||
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
||||||
/// Mutational stages will usually have a range of mutations that are
|
/// Mutational stages will usually have a range of mutations that are
|
||||||
/// being applied to the input one by one, between executions.
|
/// being applied to the input one by one, between executions.
|
||||||
pub trait MutationalStage<I, M>: Stage<I>
|
pub trait MutationalStage<C, E, EM, F, I, M, OT, S>: Stage<E, EM, F, S>
|
||||||
where
|
where
|
||||||
M: Mutator<I>,
|
M: Mutator<F, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasCorpus<C, I> + Evaluator<I>,
|
||||||
|
C: Corpus<I>,
|
||||||
|
EM: EventManager<I, S>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
/// The mutator registered for this stage
|
/// The mutator registered for this stage
|
||||||
fn mutator(&self) -> &M;
|
fn mutator(&self) -> &M;
|
||||||
@ -30,23 +35,17 @@ where
|
|||||||
fn mutator_mut(&mut self) -> &mut M;
|
fn mutator_mut(&mut self) -> &mut M;
|
||||||
|
|
||||||
/// Gets the number of iterations this mutator should run for.
|
/// Gets the number of iterations this mutator should run for.
|
||||||
fn iterations<S>(&mut self, state: &mut S) -> usize;
|
fn iterations(&mut self, state: &mut S) -> usize;
|
||||||
|
|
||||||
/// Runs this (mutational) stage for the given testcase
|
/// Runs this (mutational) stage for the given testcase
|
||||||
fn perform_mutational<C, E, EM, F, S>(
|
fn perform_mutational(
|
||||||
&self,
|
&self,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error> {
|
||||||
where
|
|
||||||
EM: EventManager<I>,
|
|
||||||
E: Executor<I>,
|
|
||||||
S: HasCorpus<C, I> + Evaluator<I>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
{
|
|
||||||
let num = self.iterations(state);
|
let num = self.iterations(state);
|
||||||
for i in 0..num {
|
for i in 0..num {
|
||||||
let mut input_mut = state
|
let mut input_mut = state
|
||||||
@ -71,19 +70,32 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
|
|||||||
|
|
||||||
/// The default mutational stage
|
/// The default mutational stage
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StdMutationalStage<I, M>
|
pub struct StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
|
||||||
where
|
where
|
||||||
M: Mutator<I>,
|
M: Mutator<F, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
|
||||||
|
C: Corpus<I>,
|
||||||
|
EM: EventManager<I, S>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
mutator: M,
|
mutator: M,
|
||||||
phantom: PhantomData<I>,
|
phantom: PhantomData<(C, E, EM, F, I, OT, R, S)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, M> MutationalStage<I, M> for StdMutationalStage<I, M>
|
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>
|
||||||
where
|
where
|
||||||
M: Mutator<I>,
|
M: Mutator<F, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
|
||||||
|
C: Corpus<I>,
|
||||||
|
EM: EventManager<I, S>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// The mutator, added to this stage
|
/// The mutator, added to this stage
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -98,43 +110,46 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of iterations as a random number
|
/// Gets the number of iterations as a random number
|
||||||
fn iterations<R, S>(&mut self, state: &mut S) -> usize
|
fn iterations(&mut self, state: &mut S) -> usize {
|
||||||
where
|
|
||||||
S: HasRand<R>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize
|
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, M> Stage<I> for StdMutationalStage<I, M>
|
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>
|
||||||
where
|
where
|
||||||
M: Mutator<I>,
|
M: Mutator<F, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
|
||||||
|
C: Corpus<I>,
|
||||||
|
EM: EventManager<I, S>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn perform<C, E, EM, F, S>(
|
fn perform(
|
||||||
&self,
|
&self,
|
||||||
fuzzer: &F,
|
fuzzer: &F,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
manager: &mut EM,
|
manager: &mut EM,
|
||||||
corpus_idx: usize,
|
corpus_idx: usize,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error> {
|
||||||
where
|
|
||||||
EM: EventManager<I>,
|
|
||||||
E: Executor<I>,
|
|
||||||
S: HasCorpus<C, I> + Evaluator<I>,
|
|
||||||
C: Corpus<I>,
|
|
||||||
{
|
|
||||||
self.perform_mutational(fuzzer, state, executor, manager, corpus_idx)
|
self.perform_mutational(fuzzer, state, executor, manager, corpus_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, M> StdMutationalStage<I, M>
|
impl<C, E, EM, F, I, M, OT, R, S> StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
|
||||||
where
|
where
|
||||||
M: Mutator<I>,
|
M: Mutator<F, I, S>,
|
||||||
I: Input,
|
I: Input,
|
||||||
|
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
|
||||||
|
C: Corpus<I>,
|
||||||
|
EM: EventManager<I, S>,
|
||||||
|
E: Executor<I> + HasObservers<OT>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Creates a new default mutational stage
|
/// Creates a new default mutational stage
|
||||||
pub fn new(mutator: M) -> Self {
|
pub fn new(mutator: M) -> Self {
|
||||||
|
@ -159,20 +159,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate an input modyfing the state of the fuzzer and returning a fitness
|
/// Evaluate an input modyfing the state of the fuzzer and returning a fitness
|
||||||
pub trait Evaluator<I>
|
pub trait Evaluator<I>: Sized
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Runs the input and triggers observers and feedback
|
/// Runs the input and triggers observers and feedback
|
||||||
fn evaluate_input<E, EM>(
|
fn evaluate_input<E, EM, OT>(
|
||||||
&mut self,
|
&mut self,
|
||||||
input: I,
|
input: I,
|
||||||
executor: &mut E,
|
executor: &mut E,
|
||||||
event_mgr: &mut EM,
|
event_mgr: &mut EM,
|
||||||
) -> Result<u32, Error>
|
) -> Result<u32, Error>
|
||||||
where
|
where
|
||||||
E: Executor<I>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
EM: EventManager<I>;
|
OT: ObserversTuple,
|
||||||
|
EM: EventManager<I, Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The state a fuzz run.
|
/// The state a fuzz run.
|
||||||
@ -442,7 +443,7 @@ where
|
|||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, Self>,
|
||||||
{
|
{
|
||||||
let (fitness, is_solution) = self.execute_input(&input, executor, manager)?;
|
let (fitness, is_solution) = self.execute_input(&input, executor, manager)?;
|
||||||
let observers = executor.observers();
|
let observers = executor.observers();
|
||||||
@ -490,7 +491,7 @@ where
|
|||||||
C: Corpus<BytesInput>,
|
C: Corpus<BytesInput>,
|
||||||
E: Executor<BytesInput> + HasObservers<OT>,
|
E: Executor<BytesInput> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
EM: EventManager<BytesInput>,
|
EM: EventManager<BytesInput, Self>,
|
||||||
{
|
{
|
||||||
for entry in fs::read_dir(in_dir)? {
|
for entry in fs::read_dir(in_dir)? {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
@ -532,7 +533,7 @@ where
|
|||||||
C: Corpus<BytesInput>,
|
C: Corpus<BytesInput>,
|
||||||
E: Executor<BytesInput> + HasObservers<OT>,
|
E: Executor<BytesInput> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
EM: EventManager<BytesInput>,
|
EM: EventManager<BytesInput, Self>,
|
||||||
{
|
{
|
||||||
for in_dir in in_dirs {
|
for in_dir in in_dirs {
|
||||||
self.load_from_directory(executor, manager, in_dir)?;
|
self.load_from_directory(executor, manager, in_dir)?;
|
||||||
@ -570,7 +571,7 @@ where
|
|||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, Self>,
|
||||||
{
|
{
|
||||||
executor.pre_exec_observers()?;
|
executor.pre_exec_observers()?;
|
||||||
|
|
||||||
@ -606,7 +607,7 @@ where
|
|||||||
C: Corpus<I>,
|
C: Corpus<I>,
|
||||||
E: Executor<I> + HasObservers<OT>,
|
E: Executor<I> + HasObservers<OT>,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
EM: EventManager<I>,
|
EM: EventManager<I, Self>,
|
||||||
{
|
{
|
||||||
let mut added = 0;
|
let mut added = 0;
|
||||||
for _ in 0..num {
|
for _ in 0..num {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Utility functions for AFL
|
//! Utility functions for AFL
|
||||||
|
|
||||||
use core::{cell::RefCell, debug_assert, fmt::Debug, time};
|
use core::{cell::RefCell, debug_assert, fmt::Debug, time};
|
||||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use xxhash_rust::xxh3::xxh3_64_with_seed;
|
use xxhash_rust::xxh3::xxh3_64_with_seed;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user