objective corpus and feedbacks

This commit is contained in:
Andrea Fioraldi 2021-02-15 10:55:05 +01:00
parent e3773e080f
commit 7a75155e6b
12 changed files with 261 additions and 115 deletions

View File

@ -251,9 +251,9 @@ where
}
// Handle arriving events in the client
fn handle_in_client<C, FT, R>(
fn handle_in_client<C, FT, OC, OFT, R>(
&mut self,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
_sender_id: u32,
event: Event<I>,
) -> Result<(), AflError>
@ -261,6 +261,8 @@ where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
match event {
Event::NewTestcase {
@ -306,11 +308,16 @@ where
}
}
fn process<C, FT, R>(&mut self, state: &mut State<C, FT, I, R>) -> Result<usize, AflError>
fn process<C, FT, OC, OFT, R>(
&mut self,
state: &mut State<C, FT, I, OC, OFT, R>,
) -> Result<usize, AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
// TODO: Get around local event copy by moving handle_in_client
let mut events = vec![];
@ -339,9 +346,9 @@ where
Ok(count)
}
fn fire<C, FT, R>(
fn fire<C, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
event: Event<I>,
) -> Result<(), AflError>
where
@ -349,6 +356,8 @@ where
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
let serialized = postcard::to_allocvec(&event)?;
self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?;
@ -359,8 +368,8 @@ where
/// Serialize the current state and corpus during an executiont to bytes.
/// On top, add the current llmp event manager instance to be restored
/// This method is needed when the fuzzer run crashes and has to restart.
pub fn serialize_state_mgr<C, FT, I, R, SH, ST>(
state: &State<C, FT, I, R>,
pub fn serialize_state_mgr<C, FT, I, OC, OFT, R, SH, ST>(
state: &State<C, FT, I, OC, OFT, R>,
mgr: &LlmpEventManager<I, SH, ST>,
) -> Result<Vec<u8>, AflError>
where
@ -368,6 +377,8 @@ where
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
SH: ShMem,
ST: Stats,
{
@ -375,18 +386,20 @@ where
}
/// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)`
pub fn deserialize_state_mgr<C, FT, I, R, SH, ST>(
pub fn deserialize_state_mgr<C, FT, I, OC, OFT, R, SH, ST>(
state_corpus_serialized: &[u8],
) -> Result<(State<C, FT, I, R>, LlmpEventManager<I, SH, ST>), AflError>
) -> Result<(State<C, FT, I, OC, OFT, R>, LlmpEventManager<I, SH, ST>), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
SH: ShMem,
ST: Stats,
{
let tuple: (State<C, FT, I, R>, _) = postcard::from_bytes(&state_corpus_serialized)?;
let tuple: (State<C, FT, I, OC, OFT, R>, _) = postcard::from_bytes(&state_corpus_serialized)?;
Ok((
tuple.0,
LlmpEventManager::existing_client_from_description(&tuple.1)?,
@ -422,11 +435,16 @@ where
}
/// 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<C, FT, R>(&mut self, state: &mut State<C, FT, I, R>) -> Result<(), AflError>
fn on_restart<C, FT, OC, OFT, R>(
&mut self,
state: &mut State<C, FT, I, OC, OFT, R>,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
// First, reset the page to 0 so the next iteration can read read from the beginning of this page
unsafe { self.sender.reset() };
@ -435,24 +453,31 @@ where
.send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized)
}
fn process<C, FT, R>(&mut self, state: &mut State<C, FT, I, R>) -> Result<usize, AflError>
fn process<C, FT, OC, OFT, R>(
&mut self,
state: &mut State<C, FT, I, OC, OFT, R>,
) -> Result<usize, AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
self.llmp_mgr.process(state)
}
fn fire<C, FT, R>(
fn fire<C, FT, OC, OFT, R>(
&mut self,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
event: Event<I>,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
// 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)
@ -490,13 +515,13 @@ where
/// A restarting state is a combination of restarter and runner, that can be used on systems without `fork`.
/// The restarter will start a new process each time the child crashes or timeouts.
#[cfg(feature = "std")]
pub fn setup_restarting_mgr<I, C, FT, R, SH, ST>(
pub fn setup_restarting_mgr<I, C, FT, OC, OFT, R, SH, ST>(
//mgr: &mut LlmpEventManager<I, SH, ST>,
stats: ST,
broker_port: u16,
) -> Result<
(
Option<State<C, FT, I, R>>,
Option<State<C, FT, I, OC, OFT, R>>,
LlmpRestartingEventManager<I, SH, ST>,
),
AflError,
@ -506,6 +531,8 @@ where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
SH: ShMem,
ST: Stats,
{
@ -565,7 +592,7 @@ where
// Restoring from a previous run, deserialize state and corpus.
Some((_sender, _tag, msg)) => {
println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len());
let (state, mgr): (State<C, FT, I, R>, LlmpEventManager<I, SH, ST>) =
let (state, mgr): (State<C, FT, I, OC, OFT, R>, LlmpEventManager<I, SH, ST>) =
deserialize_state_mgr(&msg)?;
(Some(state), LlmpRestartingEventManager::new(mgr, sender))

View File

@ -31,11 +31,16 @@ where
I: Input,
ST: Stats, //CE: CustomEvent<I, OT>,
{
fn process<C, FT, R>(&mut self, state: &mut State<C, FT, I, R>) -> Result<usize, AflError>
fn process<C, FT, OC, OFT, R>(
&mut self,
state: &mut State<C, FT, I, OC, OFT, R>,
) -> Result<usize, AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
let count = self.events.len();
while self.events.len() > 0 {
@ -45,15 +50,17 @@ where
Ok(count)
}
fn fire<C, FT, R>(
fn fire<C, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
event: Event<I>,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
match Self::handle_in_broker(&mut self.stats, 0, &event)? {
BrokerEventResult::Forward => self.events.push(event),
@ -125,9 +132,9 @@ where
}
// Handle arriving events in the client
fn handle_in_client<C, FT, R>(
fn handle_in_client<C, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
_sender_id: u32,
event: Event<I>,
) -> Result<(), AflError>
@ -135,6 +142,8 @@ where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
match event {
_ => Err(AflError::Unknown(format!(

View File

@ -162,11 +162,16 @@ where
/// Lookup for incoming events and process them.
/// Return the number of processes events or an error
fn process<C, FT, R>(&mut self, state: &mut State<C, FT, I, R>) -> Result<usize, AflError>
fn process<C, FT, OC, OFT, R>(
&mut self,
state: &mut State<C, FT, I, OC, OFT, R>,
) -> Result<usize, AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand;
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>;
/// Serialize all observers for this type and manager
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, AflError>
@ -186,11 +191,16 @@ where
/// For restarting event managers, implement a way to forward state to their next peers.
#[inline]
fn on_restart<C, FT, R>(&mut self, _state: &mut State<C, FT, I, R>) -> Result<(), AflError>
fn on_restart<C, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, OC, OFT, R>,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
Ok(())
}
@ -200,15 +210,17 @@ where
fn await_restart_safe(&mut self) {}
/// Send off an event to the broker
fn fire<C, FT, R>(
fn fire<C, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
event: Event<I>,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand;
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>;
}
/// An eventmgr for tests, and as placeholder if you really don't need an event manager.
@ -220,24 +232,31 @@ impl<I> EventManager<I> for NopEventManager<I>
where
I: Input,
{
fn process<C, FT, R>(&mut self, _state: &mut State<C, FT, I, R>) -> Result<usize, AflError>
fn process<C, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, OC, OFT, R>,
) -> Result<usize, AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
Ok(0)
}
fn fire<C, FT, R>(
fn fire<C, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
_event: Event<I>,
) -> Result<(), AflError>
where
C: Corpus<I, R>,
FT: FeedbacksTuple<I>,
R: Rand,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
Ok(())
}

View File

@ -54,30 +54,32 @@ where
OT: ObserversTuple,
{
#[inline]
fn pre_exec<C, EM, FT, R>(
fn pre_exec<C, EM, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), AflError>
where
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
C: Corpus<I, R>,
EM: EventManager<I>,
{
#[cfg(unix)]
#[cfg(feature = "std")]
unsafe {
set_oncrash_ptrs::<C, EM, FT, I, OT, R>(_state, _event_mgr, _input);
set_oncrash_ptrs::<C, EM, FT, I, OC, OFT, OT, R>(_state, _event_mgr, _input);
}
Ok(())
}
#[inline]
fn post_exec<C, EM, FT, R>(
fn post_exec<C, EM, FT, OC, OFT, R>(
&mut self,
_state: &State<C, FT, I, R>,
_state: &State<C, FT, I, OC, OFT, R>,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), AflError>
@ -86,6 +88,8 @@ where
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
EM: EventManager<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
#[cfg(unix)]
#[cfg(feature = "std")]
@ -142,23 +146,25 @@ where
/// * `on_crash_fn` - When an in-mem harness crashes, it may safe some state to continue fuzzing later.
/// Do that that in this function. The program will crash afterwards.
/// * `observers` - the observers observing the target during execution
pub fn new<C, EM, FT, R>(
pub fn new<C, EM, FT, OC, OFT, R>(
name: &'static str,
harness_fn: HarnessFunction<Self>,
observers: OT,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
_event_mgr: &mut EM,
) -> Self
where
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
C: Corpus<I, R>,
EM: EventManager<I>,
{
#[cfg(feature = "std")]
#[cfg(unix)]
unsafe {
setup_crash_handlers::<C, EM, FT, I, OT, R>();
setup_crash_handlers::<C, EM, FT, I, OC, OFT, OT, R>();
}
Self {
@ -229,7 +235,7 @@ pub mod unix_signals {
/// This is neede for certain non-rust side effects, as well as unix signal handling.
static mut CURRENT_INPUT_PTR: *const c_void = ptr::null();
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_crash<C, EM, FT, I, OT, R>(
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_crash<C, EM, FT, I, OC, OFT, OT, R>(
_sig: c_int,
info: siginfo_t,
_void: c_void,
@ -237,6 +243,8 @@ pub mod unix_signals {
EM: EventManager<I>,
C: Corpus<I, R>,
OT: ObserversTuple,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
FT: FeedbacksTuple<I>,
I: Input,
R: Rand,
@ -263,7 +271,9 @@ pub mod unix_signals {
let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap();
// Make sure we don't crash in the crash handler forever.
CURRENT_INPUT_PTR = ptr::null();
let state = (STATE_PTR as *mut State<C, FT, I, R>).as_mut().unwrap();
let state = (STATE_PTR as *mut State<C, FT, I, OC, OFT, R>)
.as_mut()
.unwrap();
let mgr = (EVENT_MGR_PTR as *mut EM).as_mut().unwrap();
mgr.fire(
state,
@ -282,13 +292,15 @@ pub mod unix_signals {
std::process::exit(1);
}
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_timeout<C, EM, FT, I, OT, R>(
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_timeout<C, EM, FT, I, OC, OFT, OT, R>(
_sig: c_int,
_info: siginfo_t,
_void: c_void,
) where
EM: EventManager<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
I: Input,
@ -306,7 +318,9 @@ pub mod unix_signals {
let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap();
// Make sure we don't crash in the crash handler forever.
CURRENT_INPUT_PTR = ptr::null();
let state = (STATE_PTR as *mut State<C, FT, I, R>).as_mut().unwrap();
let state = (STATE_PTR as *mut State<C, FT, I, OC, OFT, R>)
.as_mut()
.unwrap();
let mgr = (EVENT_MGR_PTR as *mut EM).as_mut().unwrap();
mgr.fire(
@ -325,13 +339,15 @@ pub mod unix_signals {
}
#[inline]
pub unsafe fn set_oncrash_ptrs<C, EM, FT, I, OT, R>(
state: &mut State<C, FT, I, R>,
pub unsafe fn set_oncrash_ptrs<C, EM, FT, I, OC, OFT, OT, R>(
state: &mut State<C, FT, I, OC, OFT, R>,
event_mgr: &mut EM,
input: &I,
) where
EM: EventManager<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
I: Input,
@ -350,10 +366,12 @@ pub mod unix_signals {
}
// TODO clearly state that manager should be static (maybe put the 'static lifetime?)
pub unsafe fn setup_crash_handlers<C, EM, FT, I, OT, R>()
pub unsafe fn setup_crash_handlers<C, EM, FT, I, OC, OFT, OT, R>()
where
EM: EventManager<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
I: Input,
@ -374,7 +392,8 @@ pub mod unix_signals {
let mut sa: sigaction = mem::zeroed();
libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sa.sa_sigaction = libaflrs_executor_inmem_handle_crash::<C, EM, FT, I, OT, R> as usize;
sa.sa_sigaction =
libaflrs_executor_inmem_handle_crash::<C, EM, FT, I, OC, OFT, OT, R> as usize;
for (sig, msg) in &[
(SIGSEGV, "segfault"),
(SIGBUS, "sigbus"),
@ -388,7 +407,8 @@ pub mod unix_signals {
}
}
sa.sa_sigaction = libaflrs_executor_inmem_handle_timeout::<C, EM, FT, I, OT, R> as usize;
sa.sa_sigaction =
libaflrs_executor_inmem_handle_timeout::<C, EM, FT, I, OC, OFT, OT, R> as usize;
if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 {
panic!("Could not set up sigusr2 handler for timeouts");
}

View File

@ -82,9 +82,9 @@ where
{
#[inline]
/// Called right before exexution starts
fn pre_exec<C, EM, FT, R>(
fn pre_exec<C, EM, FT, OC, OFT, R>(
&mut self,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), AflError>
@ -92,6 +92,8 @@ where
R: Rand,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
EM: EventManager<I>,
{
Ok(())
@ -99,9 +101,9 @@ where
#[inline]
/// Called right after execution finished.
fn post_exec<C, EM, FT, R>(
fn post_exec<C, EM, FT, OC, OFT, R>(
&mut self,
_state: &State<C, FT, I, R>,
_state: &State<C, FT, I, OC, OFT, R>,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), AflError>
@ -109,6 +111,8 @@ where
R: Rand,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
EM: EventManager<I>,
{
Ok(())

View File

@ -39,11 +39,13 @@ use utils::{current_milliseconds, current_time, Rand};
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};
/// The main fuzzer trait.
pub trait Fuzzer<C, E, EM, FT, ST, I, OT, R>
pub trait Fuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
where
ST: StagesTuple<C, E, EM, FT, I, OT, R>,
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -58,7 +60,7 @@ where
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
manager: &mut EM,
) -> Result<usize, AflError> {
let (_, idx) = state.corpus_mut().next(rand)?;
@ -74,7 +76,7 @@ where
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
manager: &mut EM,
) -> Result<(), AflError> {
let mut last = current_milliseconds();
@ -98,11 +100,13 @@ where
/// Your default fuzzer instance, for everyday use.
#[derive(Clone, Debug)]
pub struct StdFuzzer<C, E, EM, FT, ST, I, OT, R>
pub struct StdFuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
where
ST: StagesTuple<C, E, EM, FT, I, OT, R>,
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -110,15 +114,17 @@ where
R: Rand,
{
stages: ST,
phantom: PhantomData<(EM, E, OT, FT, C, I, R)>,
phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>,
}
impl<C, E, EM, FT, ST, I, OT, R> Fuzzer<C, E, EM, FT, ST, I, OT, R>
for StdFuzzer<C, E, EM, FT, ST, I, OT, R>
impl<C, E, EM, FT, ST, I, OC, OFT, OT, R> Fuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
for StdFuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
where
ST: StagesTuple<C, E, EM, FT, I, OT, R>,
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -134,11 +140,13 @@ where
}
}
impl<C, E, EM, FT, ST, I, OT, R> StdFuzzer<C, E, EM, FT, ST, I, OT, R>
impl<C, E, EM, FT, ST, I, OC, OFT, OT, R> StdFuzzer<C, E, EM, FT, ST, I, OC, OFT, OT, R>
where
ST: StagesTuple<C, E, EM, FT, I, OT, R>,
ST: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -248,12 +256,13 @@ mod tests {
mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator},
stages::StdMutationalStage,
state::{HasCorpus, State},
stats::SimpleStats,
utils::StdRand,
Fuzzer, StdFuzzer,
};
#[cfg(feature = "std")]
use crate::events::{LoggerEventManager, SimpleStats};
use crate::events::LoggerEventManager;
fn harness<E: Executor<I>, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind {
ExitKind::Ok
@ -267,7 +276,12 @@ mod tests {
let testcase = Testcase::new(vec![0; 4]).into();
corpus.add(testcase);
let mut state = State::new(corpus, tuple_list!());
let mut state = State::new(
corpus,
tuple_list!(),
InMemoryCorpus::<BytesInput, StdRand>::new(),
tuple_list!(),
);
let stats = SimpleStats::new(|s| {
println!("{}", s);
@ -295,8 +309,14 @@ mod tests {
}
let state_serialized = postcard::to_allocvec(&state).unwrap();
let state_deserialized: State<InMemoryCorpus<BytesInput, _>, (), BytesInput, StdRand> =
postcard::from_bytes(state_serialized.as_slice()).unwrap();
let state_deserialized: State<
InMemoryCorpus<BytesInput, _>,
(),
BytesInput,
InMemoryCorpus<BytesInput, _>,
(),
StdRand,
> = postcard::from_bytes(state_serialized.as_slice()).unwrap();
assert_eq!(state.executions(), state_deserialized.executions());
let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap();

View File

@ -999,7 +999,7 @@ token2="B"
corpus.add(BytesInput::new(vec![0x42; 0x1337]).into());
let mut state = State::new(corpus, ());
let mut state = State::new(corpus, (), InMemoryCorpus::new(), ());
let mut mutations: Vec<MutationFunction<BytesInput, WithMaxSize, StdRand, _>> = vec![];

View File

@ -343,7 +343,7 @@ mod tests {
.expect("Corpus did not contain entries");
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
let mut state = State::new(corpus, ());
let mut state = State::new(corpus, (), InMemoryCorpus::new(), ());
rand.set_seed(5);
@ -351,7 +351,7 @@ mod tests {
InMemoryCorpus<BytesInput, XKCDRand>,
_,
_,
State<_, (), _, _>,
State<_, (), _, InMemoryCorpus<BytesInput, XKCDRand>, (), _>,
>::new();
mutation_splice(&mut mutator, &mut rand, &mut state, &mut input).unwrap();
@ -378,7 +378,7 @@ mod tests {
let mut input = testcase.borrow_mut().load_input().unwrap().clone();
let input_prior = input.clone();
let mut state = State::new(corpus, ());
let mut state = State::new(corpus, (), InMemoryCorpus::new(), ());
let mut havoc = HavocBytesMutator::new(StdScheduledMutator::new());

View File

@ -16,10 +16,12 @@ use crate::{
/// A stage is one step in the fuzzing process.
/// Multiple stages will be scheduled one by one for each input.
pub trait Stage<C, E, EM, FT, I, OT, R>
pub trait Stage<C, E, EM, FT, I, OC, OFT, OT, R>
where
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -31,16 +33,18 @@ where
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), AflError>;
}
pub trait StagesTuple<C, E, EM, FT, I, OT, R>
pub trait StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>
where
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -51,18 +55,20 @@ where
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), AflError>;
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OT, R>));
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<C, E, EM, FT, I, OT, R>));
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>));
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>));
}
impl<C, E, EM, FT, I, OT, R> StagesTuple<C, E, EM, FT, I, OT, R> for ()
impl<C, E, EM, FT, I, OC, OFT, OT, R> StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R> for ()
where
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -73,22 +79,25 @@ where
&mut self,
_rand: &mut R,
_executor: &mut E,
_state: &mut State<C, FT, I, R>,
_state: &mut State<C, FT, I, OC, OFT, R>,
_manager: &mut EM,
_corpus_idx: usize,
) -> Result<(), AflError> {
Ok(())
}
fn for_each(&self, _f: fn(&dyn Stage<C, E, EM, FT, I, OT, R>)) {}
fn for_each_mut(&mut self, _f: fn(&mut dyn Stage<C, E, EM, FT, I, OT, R>)) {}
fn for_each(&self, _f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {}
fn for_each_mut(&mut self, _f: fn(&mut dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {}
}
impl<Head, Tail, EM, E, OT, FT, C, I, R> StagesTuple<C, E, EM, FT, I, OT, R> for (Head, Tail)
impl<Head, Tail, EM, E, OC, OFT, OT, FT, C, I, R> StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R>
for (Head, Tail)
where
Head: Stage<C, E, EM, FT, I, OT, R>,
Tail: StagesTuple<C, E, EM, FT, I, OT, R> + TupleList,
Head: Stage<C, E, EM, FT, I, OC, OFT, OT, R>,
Tail: StagesTuple<C, E, EM, FT, I, OC, OFT, OT, R> + TupleList,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -99,7 +108,7 @@ where
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), AflError> {
@ -108,12 +117,12 @@ where
.perform_all(rand, executor, state, manager, corpus_idx)
}
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OT, R>)) {
fn for_each(&self, f: fn(&dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {
f(&self.0);
self.1.for_each(f)
}
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<C, E, EM, FT, I, OT, R>)) {
fn for_each_mut(&mut self, f: fn(&mut dyn Stage<C, E, EM, FT, I, OC, OFT, OT, R>)) {
f(&mut self.0);
self.1.for_each_mut(f)
}

View File

@ -19,11 +19,14 @@ use crate::{
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
/// Mutational stages will usually have a range of mutations that are
/// being applied to the input one by one, between executions.
pub trait MutationalStage<C, E, EM, FT, I, M, OT, R>: Stage<C, E, EM, FT, I, OT, R>
pub trait MutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>:
Stage<C, E, EM, FT, I, OC, OFT, OT, R>
where
M: Mutator<C, I, R, State<C, FT, I, R>>,
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -48,7 +51,7 @@ where
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), AflError> {
@ -102,30 +105,34 @@ where
#[derive(Clone, Debug)]
/// The default mutational stage
pub struct StdMutationalStage<C, E, EM, FT, I, M, OT, R>
pub struct StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
where
C: Corpus<I, R>,
E: Executor<I> + HasObservers<OT>,
EM: EventManager<I>,
FT: FeedbacksTuple<I>,
I: Input,
M: Mutator<C, I, R, State<C, FT, I, R>>,
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
R: Rand,
{
mutator: M,
phantom: PhantomData<(EM, E, OT, FT, C, I, R)>,
phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>,
}
impl<C, E, EM, FT, I, M, OT, R> MutationalStage<C, E, EM, FT, I, M, OT, R>
for StdMutationalStage<C, E, EM, FT, I, M, OT, R>
impl<C, E, EM, FT, I, M, OC, OFT, OT, R> MutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
for StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
where
C: Corpus<I, R>,
E: Executor<I> + HasObservers<OT>,
EM: EventManager<I>,
FT: FeedbacksTuple<I>,
I: Input,
M: Mutator<C, I, R, State<C, FT, I, R>>,
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
R: Rand,
{
@ -142,12 +149,14 @@ where
}
}
impl<C, E, EM, FT, I, M, OT, R> Stage<C, E, EM, FT, I, OT, R>
for StdMutationalStage<C, E, EM, FT, I, M, OT, R>
impl<C, E, EM, FT, I, M, OC, OFT, OT, R> Stage<C, E, EM, FT, I, OC, OFT, OT, R>
for StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
where
M: Mutator<C, I, R, State<C, FT, I, R>>,
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,
@ -159,7 +168,7 @@ where
&mut self,
rand: &mut R,
executor: &mut E,
state: &mut State<C, FT, I, R>,
state: &mut State<C, FT, I, OC, OFT, R>,
manager: &mut EM,
corpus_idx: usize,
) -> Result<(), AflError> {
@ -167,11 +176,13 @@ where
}
}
impl<C, E, EM, FT, I, M, OT, R> StdMutationalStage<C, E, EM, FT, I, M, OT, R>
impl<C, E, EM, FT, I, M, OC, OFT, OT, R> StdMutationalStage<C, E, EM, FT, I, M, OC, OFT, OT, R>
where
M: Mutator<C, I, R, State<C, FT, I, R>>,
M: Mutator<C, I, R, State<C, FT, I, OC, OFT, R>>,
EM: EventManager<I>,
E: Executor<I> + HasObservers<OT>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
OT: ObserversTuple,
FT: FeedbacksTuple<I>,
C: Corpus<I, R>,

View File

@ -57,12 +57,14 @@ pub trait HasMetadata {
/// The state a fuzz run.
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "FT: serde::de::DeserializeOwned")]
pub struct State<C, FT, I, R>
pub struct State<C, FT, I, OC, OFT, R>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
/// How many times the executor ran the harness/target
executions: usize,
@ -73,18 +75,24 @@ where
start_time: u64,
/// Metadata stored for this state by one of the components
metadata: SerdeAnyMap,
// additional_corpuses, maybe another TupleList?
// Feedbacks used to evaluate an input
/// Feedbacks used to evaluate an input
feedbacks: FT,
// Objective corpus
objective_corpus: OC,
/// Objective Feedbacks
objective_feedbacks: OFT,
phantom: PhantomData<(R, I)>,
}
#[cfg(feature = "std")]
impl<C, FT, R> State<C, FT, BytesInput, R>
impl<C, FT, OC, OFT, R> State<C, FT, BytesInput, OC, OFT, R>
where
C: Corpus<BytesInput, R>,
R: Rand,
FT: FeedbacksTuple<BytesInput>,
OC: Corpus<BytesInput, R>,
OFT: FeedbacksTuple<BytesInput>,
{
pub fn load_from_directory<E, OT, EM>(
&mut self,
@ -153,12 +161,14 @@ where
}
}
impl<C, FT, I, R> HasCorpus<C, I, R> for State<C, FT, I, R>
impl<C, FT, I, OC, OFT, R> HasCorpus<C, I, R> for State<C, FT, I, OC, OFT, R>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
/// Returns the corpus
fn corpus(&self) -> &C {
@ -172,12 +182,14 @@ where
}
/// Trait for elements offering metadata
impl<C, FT, I, R> HasMetadata for State<C, FT, I, R>
impl<C, FT, I, OC, OFT, R> HasMetadata for State<C, FT, I, OC, OFT, R>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
/// Get all the metadata into an HashMap
#[inline]
@ -192,12 +204,14 @@ where
}
}
impl<C, FT, I, R> State<C, FT, I, R>
impl<C, FT, I, OC, OFT, R> State<C, FT, I, OC, OFT, R>
where
C: Corpus<I, R>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
OC: Corpus<I, R>,
OFT: FeedbacksTuple<I>,
{
/// Get executions
#[inline]
@ -349,13 +363,15 @@ where
Ok(())
}
pub fn new(corpus: C, feedbacks: FT) -> Self {
pub fn new(corpus: C, feedbacks: FT, objective_corpus: OC, objective_feedbacks: OFT) -> Self {
Self {
corpus,
executions: 0,
start_time: current_milliseconds(),
metadata: SerdeAnyMap::default(),
feedbacks: feedbacks,
objective_corpus: objective_corpus,
objective_feedbacks: objective_feedbacks,
phantom: PhantomData,
}
}

View File

@ -5,7 +5,7 @@ use std::{env, path::PathBuf};
use afl::{
bolts::{serdeany::RegistryBuilder, shmem::AflShmem, tuples::tuple_list},
corpus::{Corpus, InMemoryCorpus},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
events::setup_restarting_mgr,
executors::{inprocess::InProcessExecutor, Executor, ExitKind},
feedbacks::MaxMapFeedback,
@ -59,18 +59,27 @@ pub fn main() {
"Workdir: {:?}",
env::current_dir().unwrap().to_string_lossy().to_string()
);
fuzz(vec![PathBuf::from("./corpus")], 1337).expect("An error occurred while fuzzing");
fuzz(
vec![PathBuf::from("./corpus")],
PathBuf::from("./crashes"),
1337,
)
.expect("An error occurred while fuzzing");
}
/// The actual fuzzer
fn fuzz(corpus_dirs: Vec<PathBuf>, broker_port: u16) -> Result<(), AflError> {
fn fuzz(
corpus_dirs: Vec<PathBuf>,
objective_dir: PathBuf,
broker_port: u16,
) -> Result<(), AflError> {
let mut rand = StdRand::new(0);
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
let stats = SimpleStats::new(|s| println!("{}", s));
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) =
setup_restarting_mgr::<_, _, _, _, AflShmem, _>(stats, broker_port)
setup_restarting_mgr::<_, _, _, _, _, _, AflShmem, _>(stats, broker_port)
.expect("Failed to setup the restarter".into());
// Create an observation channel using the coverage map
@ -86,6 +95,8 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, broker_port: u16) -> Result<(), AflError> {
&NAME_COV_MAP,
&edges_observer
)),
OnDiskCorpus::new(objective_dir),
tuple_list!(),
));
println!("We're a client, let's fuzz :)");