This commit is contained in:
Andrea Fioraldi 2021-02-22 11:26:11 +01:00
parent 1585645972
commit c411fec271
24 changed files with 314 additions and 335 deletions

View File

@ -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);

View File

@ -1,5 +1,4 @@
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,
@ -7,5 +6,4 @@ fn main() {
// 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},
); );
} }

View File

@ -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;

View File

@ -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)]

View File

@ -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)

View File

@ -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>
/// Add an entry to the corpus and return its index where
fn on_add<C, I, R, S>(
&self,
state: &mut S,
idx: usize,
testcase: &Testcase<I>,
) -> Result<(), Error>
where
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
I: Input, I: Input,
R: Rand, {
{ /// Add an entry to the corpus and return its index
fn on_add(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
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
}
} }

View File

@ -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))
} }

View File

@ -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,

View File

@ -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)
} }

View File

@ -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>,

View File

@ -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(())
} }

View File

@ -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 {

View File

@ -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)]

View File

@ -106,4 +106,3 @@ pub trait HasLen {
/// The lenght /// The lenght
fn len(&self) -> usize; fn len(&self) -> usize;
} }

View File

@ -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};

View File

@ -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,

View File

@ -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() {
if idx == *cur {
return Ok(MutationResult::Skipped); 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() {
if idx == *cur {
return Ok(MutationResult::Skipped); 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() {
if idx == *cur {
return Ok(MutationResult::Skipped); 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()?;

View File

@ -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);

View File

@ -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,
}; };

View File

@ -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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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")]