start working on tuples
This commit is contained in:
parent
9966098d6b
commit
60b0b16a60
@ -31,6 +31,7 @@ default = ["std"]
|
||||
std = []
|
||||
|
||||
[dependencies]
|
||||
tuple_list = "0.1.2"
|
||||
hashbrown = { version = "0.9", features = ["serde"] } # A faster hashmap, nostd compatible
|
||||
libc = "0.2" # For (*nix) libc
|
||||
num = "*"
|
||||
|
@ -8,8 +8,9 @@ use hashbrown::HashMap;
|
||||
|
||||
use crate::corpus::{Corpus, Testcase};
|
||||
use crate::events::{Event, EventManager};
|
||||
use crate::executors::Executor;
|
||||
use crate::feedbacks::Feedback;
|
||||
use crate::executors::{HasObservers, Executor};
|
||||
use crate::feedbacks::{FeedbacksTuple};
|
||||
use crate::observers::ObserversTuple;
|
||||
use crate::generators::Generator;
|
||||
use crate::inputs::Input;
|
||||
use crate::stages::Stage;
|
||||
@ -22,10 +23,11 @@ pub trait StateMetadata: Debug {
|
||||
}
|
||||
|
||||
/// The state a fuzz run.
|
||||
pub struct State<I, R>
|
||||
pub struct State<I, R, FT>
|
||||
where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>
|
||||
{
|
||||
/// How many times the executor ran the harness/target
|
||||
executions: usize,
|
||||
@ -34,14 +36,15 @@ where
|
||||
/// Metadata stored for this state by one of the components
|
||||
metadatas: HashMap<&'static str, Box<dyn StateMetadata>>,
|
||||
// additional_corpuses: HashMap<&'static str, Box<dyn Corpus>>,
|
||||
feedbacks: Vec<Box<dyn Feedback<I>>>,
|
||||
feedbacks: FT,
|
||||
phantom: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<I, R> State<I, R>
|
||||
impl<I, R, FT> State<I, R, FT>
|
||||
where
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>
|
||||
{
|
||||
/// Get executions
|
||||
#[inline]
|
||||
@ -98,39 +101,31 @@ where
|
||||
|
||||
/// Returns vector of feebacks
|
||||
#[inline]
|
||||
pub fn feedbacks(&self) -> &[Box<dyn Feedback<I>>] {
|
||||
pub fn feedbacks(&self) -> &FT {
|
||||
&self.feedbacks
|
||||
}
|
||||
|
||||
/// Returns vector of feebacks (mutable)
|
||||
#[inline]
|
||||
pub fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>> {
|
||||
pub fn feedbacks_mut(&mut self) -> &mut FT {
|
||||
&mut self.feedbacks
|
||||
}
|
||||
|
||||
/// Adds a feedback
|
||||
#[inline]
|
||||
pub fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>) {
|
||||
self.feedbacks_mut().push(feedback);
|
||||
}
|
||||
|
||||
// TODO move some of these, like evaluate_input, to FuzzingEngine
|
||||
// TODO move some of these, like evaluate_input, to Engine
|
||||
|
||||
/// Runs the input and triggers observers and feedback
|
||||
pub fn evaluate_input<E>(&mut self, input: &I, executor: &mut E) -> Result<u32, AflError>
|
||||
pub fn evaluate_input<E, OT>(&mut self, input: &I, executor: &mut E) -> Result<u32, AflError>
|
||||
where
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple
|
||||
{
|
||||
executor.reset_observers()?;
|
||||
executor.run_target(&input)?;
|
||||
self.set_executions(self.executions() + 1);
|
||||
executor.post_exec_observers()?;
|
||||
|
||||
let mut fitness = 0;
|
||||
let observers = executor.observers();
|
||||
for feedback in self.feedbacks_mut() {
|
||||
fitness += feedback.is_interesting(&input, observers)?;
|
||||
}
|
||||
let fitness = self.feedbacks_mut().is_interesting_all(&input, observers)?;
|
||||
Ok(fitness)
|
||||
}
|
||||
|
||||
@ -138,10 +133,7 @@ where
|
||||
#[inline]
|
||||
pub fn discard_input(&mut self, input: &I) -> Result<(), AflError> {
|
||||
// TODO: This could probably be automatic in the feedback somehow?
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.discard_metadata(input)?;
|
||||
}
|
||||
Ok(())
|
||||
self.feedbacks_mut().discard_metadata_all(&input)
|
||||
}
|
||||
|
||||
/// Creates a new testcase, appending the metadata from each feedback
|
||||
@ -149,10 +141,7 @@ where
|
||||
pub fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result<Testcase<I>, AflError> {
|
||||
let mut testcase = Testcase::new(input);
|
||||
testcase.set_fitness(fitness);
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.append_metadata(&mut testcase)?;
|
||||
}
|
||||
|
||||
self.feedbacks_mut().append_metadata_all(&mut testcase)?;
|
||||
Ok(testcase)
|
||||
}
|
||||
|
||||
@ -191,19 +180,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_initial_inputs<G, C, E, EM>(
|
||||
pub fn generate_initial_inputs<G, C, E, OT, EM>(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
corpus: &mut C,
|
||||
generator: &mut G,
|
||||
engine: &mut Engine<E, I>,
|
||||
engine: &mut Engine<E, OT, I>,
|
||||
manager: &mut EM,
|
||||
num: usize,
|
||||
) -> Result<(), AflError>
|
||||
where
|
||||
G: Generator<I, R>,
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
EM: EventManager<C, E, I, R>,
|
||||
{
|
||||
let mut added = 0;
|
||||
@ -237,18 +227,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Engine<E, I>
|
||||
pub struct Engine<E, OT, I>
|
||||
where
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
I: Input,
|
||||
{
|
||||
executor: E,
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<E, I> Engine<E, I>
|
||||
impl<E, OT, I> Engine<E, OT, I>
|
||||
where
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
I: Input,
|
||||
{
|
||||
/// Return the executor
|
||||
@ -271,30 +263,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Fuzzer<EM, E, C, I, R>
|
||||
pub trait Fuzzer<EM, E, OT, C, I, R>
|
||||
where
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>];
|
||||
fn stages(&self) -> &[Box<dyn Stage<EM, E, OT, C, I, R>>];
|
||||
|
||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>>;
|
||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, OT, C, I, R>>>;
|
||||
|
||||
fn add_stage(&mut self, stage: Box<dyn Stage<EM, E, C, I, R>>) {
|
||||
fn add_stage(&mut self, stage: Box<dyn Stage<EM, E, OT, C, I, R>>) {
|
||||
self.stages_mut().push(stage);
|
||||
}
|
||||
|
||||
fn fuzz_one(
|
||||
fn fuzz_one<FT>(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut State<I, R>,
|
||||
state: &mut State<I, R, FT>,
|
||||
corpus: &mut C,
|
||||
engine: &mut Engine<E, I>,
|
||||
engine: &mut Engine<E, OT, I>,
|
||||
manager: &mut EM,
|
||||
) -> Result<usize, AflError> {
|
||||
) -> Result<usize, AflError>
|
||||
where
|
||||
FT: FeedbacksTuple<I>
|
||||
{
|
||||
let (_, idx) = corpus.next(rand)?;
|
||||
|
||||
for stage in self.stages_mut() {
|
||||
@ -305,14 +301,15 @@ where
|
||||
Ok(idx)
|
||||
}
|
||||
|
||||
fn fuzz_loop(
|
||||
fn fuzz_loop<FT>(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut State<I, R>,
|
||||
state: &mut State<I, R, FT>,
|
||||
corpus: &mut C,
|
||||
engine: &mut Engine<E, I>,
|
||||
engine: &mut Engine<E, OT, I>,
|
||||
manager: &mut EM,
|
||||
) -> Result<(), AflError> {
|
||||
) -> Result<(), AflError> where
|
||||
FT: FeedbacksTuple<I>{
|
||||
let mut last = current_milliseconds();
|
||||
loop {
|
||||
self.fuzz_one(rand, state, corpus, engine, manager)?;
|
||||
@ -328,38 +325,41 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StdFuzzer<EM, E, C, I, R>
|
||||
pub struct StdFuzzer<EM, E, OT, C, I, R>
|
||||
where
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
stages: Vec<Box<dyn Stage<EM, E, C, I, R>>>,
|
||||
stages: Vec<Box<dyn Stage<EM, E, OT, C, I, R>>>,
|
||||
}
|
||||
|
||||
impl<EM, E, C, I, R> Fuzzer<EM, E, C, I, R> for StdFuzzer<EM, E, C, I, R>
|
||||
impl<EM, E, OT, C, I, R> Fuzzer<EM, E, OT, C, I, R> for StdFuzzer<EM, E, OT, C, I, R>
|
||||
where
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>] {
|
||||
fn stages(&self) -> &[Box<dyn Stage<EM, E, OT, C, I, R>>] {
|
||||
&self.stages
|
||||
}
|
||||
|
||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>> {
|
||||
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, OT, C, I, R>>> {
|
||||
&mut self.stages
|
||||
}
|
||||
}
|
||||
|
||||
impl<EM, E, C, I, R> StdFuzzer<EM, E, C, I, R>
|
||||
impl<EM, E, OT, C, I, R> StdFuzzer<EM, E, OT, C, I, R>
|
||||
where
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
@ -388,6 +388,7 @@ mod tests {
|
||||
use crate::inputs::bytes::BytesInput;
|
||||
use crate::mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator};
|
||||
use crate::stages::mutational::StdMutationalStage;
|
||||
use crate::tuples::tuple_list;
|
||||
use crate::utils::StdRand;
|
||||
|
||||
fn harness<I>(_executor: &dyn Executor<I>, _buf: &[u8]) -> ExitKind {
|
||||
@ -402,7 +403,7 @@ mod tests {
|
||||
let testcase = Testcase::new(vec![0; 4]).into();
|
||||
corpus.add(testcase);
|
||||
|
||||
let executor = InMemoryExecutor::<BytesInput>::new(harness);
|
||||
let executor = InMemoryExecutor::<BytesInput, _>::new(harness, tuple_list!());
|
||||
let mut state = State::new();
|
||||
|
||||
let mut events_manager = LoggerEventManager::new(stderr());
|
||||
|
@ -1,9 +1,9 @@
|
||||
use core::ffi::c_void;
|
||||
use core::ptr;
|
||||
|
||||
use crate::executors::{Executor, ExitKind};
|
||||
use crate::executors::{Executor, HasObservers, ExitKind};
|
||||
use crate::inputs::{HasTargetBytes, Input};
|
||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
||||
use crate::observers::{ObserversTuple};
|
||||
use crate::AflError;
|
||||
|
||||
/// The (unsafe) pointer to the current inmem executor, for the current run.
|
||||
@ -14,23 +14,25 @@ static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null();
|
||||
type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
|
||||
|
||||
/// The inmem executor simply calls a target function, then returns afterwards.
|
||||
pub struct InMemoryExecutor<I>
|
||||
pub struct InMemoryExecutor<I, OT>
|
||||
where
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple
|
||||
{
|
||||
harness: HarnessFunction<I>,
|
||||
observers: NamedSerdeAnyMap,
|
||||
observers: OT,
|
||||
}
|
||||
|
||||
impl<I> Executor<I> for InMemoryExecutor<I>
|
||||
impl<I, OT> Executor<I> for InMemoryExecutor<I, OT>
|
||||
where
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple
|
||||
{
|
||||
#[inline]
|
||||
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> {
|
||||
let bytes = input.target_bytes();
|
||||
unsafe {
|
||||
CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor<I> as *const c_void;
|
||||
CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor<I, OT> as *const c_void;
|
||||
}
|
||||
let ret = (self.harness)(self, bytes.as_slice());
|
||||
unsafe {
|
||||
@ -38,30 +40,35 @@ where
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, OT> HasObservers<OT> for InMemoryExecutor<I, OT> where
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple {
|
||||
#[inline]
|
||||
fn observers(&self) -> &NamedSerdeAnyMap {
|
||||
fn observers(&self) -> &OT {
|
||||
&self.observers
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap {
|
||||
fn observers_mut(&mut self) -> &mut OT {
|
||||
&mut self.observers
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> InMemoryExecutor<I>
|
||||
impl<I, OT> InMemoryExecutor<I, OT>
|
||||
where
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple
|
||||
{
|
||||
pub fn new(harness_fn: HarnessFunction<I>) -> Self {
|
||||
pub fn new(harness_fn: HarnessFunction<I>, observers: OT) -> Self {
|
||||
#[cfg(feature = "std")]
|
||||
unsafe {
|
||||
os_signals::setup_crash_handlers::<I>();
|
||||
}
|
||||
Self {
|
||||
harness: harness_fn,
|
||||
observers: NamedSerdeAnyMap::new(),
|
||||
observers: observers,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -169,6 +176,7 @@ mod tests {
|
||||
use crate::executors::inmemory::InMemoryExecutor;
|
||||
use crate::executors::{Executor, ExitKind};
|
||||
use crate::inputs::{HasTargetBytes, Input, TargetBytes};
|
||||
use crate::tuples::{tuple_list, tuple_list_type};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -182,7 +190,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
fn test_harness_fn_nop(_executor: &dyn Executor<NopInput>, buf: &[u8]) -> ExitKind {
|
||||
fn test_harness_fn_nop(_executor: &dyn Executor<NopInput, tuple_list_type!()>, buf: &[u8]) -> ExitKind {
|
||||
println!("Fake exec with buf of len {}", buf.len());
|
||||
ExitKind::Ok
|
||||
}
|
||||
@ -194,7 +202,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_inmem_exec() {
|
||||
let mut in_mem_executor = InMemoryExecutor::new(test_harness_fn_nop);
|
||||
let mut in_mem_executor = InMemoryExecutor::new(test_harness_fn_nop, tuple_list!());
|
||||
let mut input = NopInput {};
|
||||
assert!(in_mem_executor.run_target(&mut input).is_ok());
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
pub mod inmemory;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use crate::inputs::Input;
|
||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
||||
use crate::observers::Observer;
|
||||
use crate::observers::{ObserversTuple};
|
||||
use crate::AflError;
|
||||
|
||||
/// How an execution finished.
|
||||
@ -15,6 +12,26 @@ pub enum ExitKind {
|
||||
Timeout,
|
||||
}
|
||||
|
||||
pub trait HasObservers<OT> where OT: ObserversTuple {
|
||||
/// Get the linked observers
|
||||
fn observers(&self) -> &OT;
|
||||
|
||||
/// Get the linked observers
|
||||
fn observers_mut(&mut self) -> &mut OT;
|
||||
|
||||
/// Reset the state of all the observes linked to this executor
|
||||
#[inline]
|
||||
fn reset_observers(&mut self) -> Result<(), AflError> {
|
||||
self.observers_mut().reset_all()
|
||||
}
|
||||
|
||||
/// Run the post exec hook for all the observes linked to this executor
|
||||
#[inline]
|
||||
fn post_exec_observers(&mut self) -> Result<(), AflError> {
|
||||
self.observers_mut().post_exec_all()
|
||||
}
|
||||
}
|
||||
|
||||
/// An executor takes the given inputs, and runs the harness/target.
|
||||
pub trait Executor<I>
|
||||
where
|
||||
@ -22,31 +39,4 @@ where
|
||||
{
|
||||
/// Instruct the target about the input and run
|
||||
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError>;
|
||||
|
||||
/// Get the linked observers
|
||||
fn observers(&self) -> &NamedSerdeAnyMap;
|
||||
|
||||
/// Get the linked observers
|
||||
fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap;
|
||||
|
||||
/// Add a linked observer
|
||||
fn add_observer(&mut self, observer: Box<dyn Observer>) {
|
||||
let name = observer.name().clone();
|
||||
self.observers_mut().insert(observer, &name);
|
||||
}
|
||||
|
||||
/// Reset the state of all the observes linked to this executor
|
||||
#[inline]
|
||||
fn reset_observers(&mut self) -> Result<(), AflError> {
|
||||
self.observers_mut().for_each_mut(|_, x| Ok(x.reset()?))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Run the post exec hook for all the observes linked to this executor
|
||||
#[inline]
|
||||
fn post_exec_observers(&mut self) -> Result<(), AflError> {
|
||||
self.observers_mut()
|
||||
.for_each_mut(|_, x| Ok(x.post_exec()?))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,10 @@ use core::marker::PhantomData;
|
||||
use num::Integer;
|
||||
|
||||
use crate::inputs::Input;
|
||||
use crate::observers::observer_serde::NamedSerdeAnyMap;
|
||||
use crate::observers::MapObserver;
|
||||
use crate::observers::{ObserversTuple, Observer, MapObserver};
|
||||
use crate::corpus::Testcase;
|
||||
use crate::tuples::{Named, TupleList, MatchNameAndType, MatchType};
|
||||
use crate::AflError;
|
||||
use crate::{corpus::Testcase, observers::Observer};
|
||||
|
||||
pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
|
||||
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
|
||||
@ -19,12 +19,12 @@ pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
|
||||
/// Feedbacks evaluate the observers.
|
||||
/// Basically, they reduce the information provided by an observer to a value,
|
||||
/// indicating the "interestingness" of the last run.
|
||||
pub trait Feedback<I>
|
||||
pub trait Feedback<I>: Named
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
/// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55)
|
||||
fn is_interesting(&mut self, input: &I, observers: &NamedSerdeAnyMap) -> Result<u32, AflError>;
|
||||
fn is_interesting<OT: ObserversTuple>(&mut self, input: &I, observers: &OT) -> Result<u32, AflError>;
|
||||
|
||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||
#[inline]
|
||||
@ -37,9 +37,56 @@ where
|
||||
fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of this feedback
|
||||
fn name(&self) -> &String;
|
||||
pub trait FeedbacksTuple<I>: TupleList + MatchType + MatchNameAndType
|
||||
where
|
||||
I: Input
|
||||
{
|
||||
fn is_interesting_all<OT: ObserversTuple>(&mut self, input: &I, observers: &OT) -> Result<u32, AflError>;
|
||||
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), AflError>;
|
||||
fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>;
|
||||
//fn for_each(&self, f: fn(&dyn Feedback<I>));
|
||||
//fn for_each_mut(&mut self, f: fn(&mut dyn Feedback<I>));
|
||||
}
|
||||
|
||||
impl<I> FeedbacksTuple<I> for () where
|
||||
I: Input{
|
||||
fn is_interesting_all<OT: ObserversTuple>(&mut self, input: &I, observers: &OT) -> Result<u32, AflError> { Ok(0) }
|
||||
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), AflError> { Ok(())}
|
||||
fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError> { Ok(())}
|
||||
//fn for_each(&self, f: fn(&dyn Feedback<I>)) {}
|
||||
//fn for_each_mut(&mut self, f: fn(&mut dyn Feedback<I>)) {}
|
||||
}
|
||||
|
||||
impl<Head, Tail, I> FeedbacksTuple<I> for (Head, Tail) where
|
||||
Head: Feedback<I>,
|
||||
Tail: FeedbacksTuple<I>,
|
||||
I: Input
|
||||
{
|
||||
fn is_interesting_all<OT: ObserversTuple>(&mut self, input: &I, observers: &OT) -> Result<u32, AflError> {
|
||||
Ok(self.0.is_interesting(input, observers)? + self.1.is_interesting_all(input, observers)?)
|
||||
}
|
||||
|
||||
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), AflError>{
|
||||
self.0.append_metadata(testcase)?;
|
||||
self.1.append_metadata_all(testcase)
|
||||
}
|
||||
|
||||
fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>{
|
||||
self.0.discard_metadata(input)?;
|
||||
self.1.discard_metadata_all(input)
|
||||
}
|
||||
|
||||
/*fn for_each(&self, f: fn(&dyn Feedback<I>)) {
|
||||
f(&self.0);
|
||||
self.1.for_each(f)
|
||||
}
|
||||
|
||||
fn for_each_mut(&mut self, f: fn(&mut dyn Feedback<I>)) {
|
||||
f(self.0);
|
||||
self.1.for_each_mut(f)
|
||||
}*/
|
||||
}
|
||||
|
||||
/// A Reducer function is used to aggregate values for the novelty search
|
||||
@ -102,7 +149,7 @@ where
|
||||
/// Contains information about untouched entries
|
||||
history_map: Vec<T>,
|
||||
/// Name identifier of this instance
|
||||
name: String,
|
||||
name: &'static str,
|
||||
/// Phantom Data of Reducer
|
||||
phantom: PhantomData<(R, O)>,
|
||||
}
|
||||
@ -114,14 +161,14 @@ where
|
||||
O: MapObserver<T> + 'static,
|
||||
I: Input,
|
||||
{
|
||||
fn is_interesting(
|
||||
fn is_interesting<OT: ObserversTuple>(
|
||||
&mut self,
|
||||
_input: &I,
|
||||
observers: &NamedSerdeAnyMap,
|
||||
observers: &OT,
|
||||
) -> Result<u32, AflError> {
|
||||
let mut interesting = 0;
|
||||
// TODO optimize
|
||||
let observer = observers.get::<O>(&self.name).unwrap();
|
||||
let observer = observers.match_name_type::<O>(&self.name).unwrap();
|
||||
let size = observer.map().len();
|
||||
for i in 0..size {
|
||||
let history = self.history_map[i];
|
||||
@ -135,10 +182,17 @@ where
|
||||
|
||||
Ok(interesting)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R, O> Named for MapFeedback<T, R, O>
|
||||
where
|
||||
T: Integer + Default + Copy + 'static,
|
||||
R: Reducer<T>,
|
||||
O: MapObserver<T> + 'static,
|
||||
{
|
||||
#[inline]
|
||||
fn name(&self) -> &String {
|
||||
&self.name
|
||||
fn name(&self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +206,7 @@ where
|
||||
pub fn new(name: &'static str, map_size: usize) -> Self {
|
||||
Self {
|
||||
history_map: vec![T::default(); map_size],
|
||||
name: name.to_string(),
|
||||
name: name,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -160,7 +214,7 @@ where
|
||||
pub fn new_with_observer(map_observer: &O) -> Self {
|
||||
Self {
|
||||
history_map: vec![T::default(); map_observer.map().len()],
|
||||
name: map_observer.name().to_string(),
|
||||
name: map_observer.name(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ pub mod mutators;
|
||||
pub mod observers;
|
||||
pub mod serde_anymap;
|
||||
pub mod stages;
|
||||
pub mod tuples;
|
||||
pub mod utils;
|
||||
|
||||
use alloc::string::String;
|
||||
|
@ -5,14 +5,13 @@ use alloc::string::String;
|
||||
use core::any::Any;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::serde_anymap::{ArrayMut, SerdeAny};
|
||||
use crate::serde_anymap::ArrayMut;
|
||||
use crate::tuples::{TupleList, MatchNameAndType, MatchType, Named};
|
||||
use crate::AflError;
|
||||
|
||||
// TODO register each observer in the Registry in new()
|
||||
|
||||
/// Observers observe different information about the target.
|
||||
/// They can then be used by various sorts of feedback.
|
||||
pub trait Observer: SerdeAny + 'static {
|
||||
pub trait Observer: Named + 'static {
|
||||
/// The testcase finished execution, calculate any changes.
|
||||
#[inline]
|
||||
fn flush(&mut self) -> Result<(), AflError> {
|
||||
@ -25,11 +24,39 @@ pub trait Observer: SerdeAny + 'static {
|
||||
fn post_exec(&mut self) -> Result<(), AflError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn name(&self) -> &String;
|
||||
}
|
||||
|
||||
crate::create_serde_registry_for_trait!(observer_serde, crate::observers::Observer);
|
||||
pub trait ObserversTuple: TupleList + MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned {
|
||||
fn reset_all(&mut self) -> Result<(), AflError>;
|
||||
fn post_exec_all(&mut self) -> Result<(), AflError>;
|
||||
fn for_each(&self, f: fn(&dyn Observer));
|
||||
}
|
||||
|
||||
impl ObserversTuple for () {
|
||||
fn reset_all(&mut self) -> Result<(), AflError> { Ok(()) }
|
||||
fn post_exec_all(&mut self) -> Result<(), AflError> { Ok(()) }
|
||||
fn for_each(&self, f: fn(&dyn Observer)) { }
|
||||
}
|
||||
|
||||
impl<Head, Tail> ObserversTuple for (Head, Tail) where
|
||||
Head: Observer,
|
||||
Tail: ObserversTuple,
|
||||
{
|
||||
fn reset_all(&mut self) -> Result<(), AflError> {
|
||||
self.0.reset()?;
|
||||
self.1.reset_all()
|
||||
}
|
||||
|
||||
fn post_exec_all(&mut self) -> Result<(), AflError> {
|
||||
self.0.post_exec()?;
|
||||
self.1.post_exec_all()
|
||||
}
|
||||
|
||||
fn for_each(&self, f: fn(&dyn Observer)) {
|
||||
f(self.0);
|
||||
self.1.for_each(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A MapObserver observes the static map, as oftentimes used for afl-like coverage information
|
||||
pub trait MapObserver<T>
|
||||
@ -74,7 +101,7 @@ where
|
||||
{
|
||||
map: ArrayMut<T>,
|
||||
initial: T,
|
||||
name: String,
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
impl<T> Observer for StdMapObserver<T>
|
||||
@ -85,25 +112,14 @@ where
|
||||
fn reset(&mut self) -> Result<(), AflError> {
|
||||
self.reset_map()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SerdeAny for StdMapObserver<T>
|
||||
where
|
||||
impl<T> Named for StdMapObserver<T> where
|
||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
#[inline]
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
fn name(&self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +159,6 @@ where
|
||||
{
|
||||
/// Creates a new MapObserver
|
||||
pub fn new(name: &'static str, map: &'static mut [T]) -> Self {
|
||||
observer_serde::RegistryBuilder::register::<Self>();
|
||||
let initial = if map.len() > 0 { map[0] } else { T::default() };
|
||||
Self {
|
||||
map: ArrayMut::Cptr((map.as_mut_ptr(), map.len())),
|
||||
@ -154,7 +169,6 @@ where
|
||||
|
||||
/// Creates a new MapObserver from a raw pointer
|
||||
pub fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self {
|
||||
observer_serde::RegistryBuilder::register::<Self>();
|
||||
unsafe {
|
||||
let initial = if len > 0 { *map_ptr } else { T::default() };
|
||||
StdMapObserver {
|
||||
@ -166,6 +180,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@ -183,3 +198,4 @@ mod tests {
|
||||
assert_eq!(d.name(), o.name());
|
||||
}
|
||||
}
|
||||
*/
|
@ -4,17 +4,21 @@ pub use mutational::StdMutationalStage;
|
||||
use crate::corpus::Corpus;
|
||||
use crate::engines::{Engine, State};
|
||||
use crate::events::EventManager;
|
||||
use crate::executors::Executor;
|
||||
use crate::executors::{HasObservers, Executor};
|
||||
use crate::observers::ObserversTuple;
|
||||
use crate::feedbacks::FeedbacksTuple;
|
||||
use crate::inputs::Input;
|
||||
use crate::utils::Rand;
|
||||
use crate::AflError;
|
||||
|
||||
/// A stage is one step in the fuzzing process.
|
||||
/// Multiple stages will be scheduled one by one for each input.
|
||||
pub trait Stage<EM, E, C, I, R>
|
||||
pub trait Stage<EM, E, OT, C, I, R>
|
||||
where
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I> + HasObservers<OT>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
@ -23,9 +27,9 @@ where
|
||||
fn perform(
|
||||
&mut self,
|
||||
rand: &mut R,
|
||||
state: &mut State<I, R>,
|
||||
state: &mut State<I, R, FT>,
|
||||
corpus: &mut C,
|
||||
engine: &mut Engine<E, I>,
|
||||
engine: &mut Engine<E, OT, I>,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), AflError>;
|
||||
|
@ -2,6 +2,7 @@ use core::marker::PhantomData;
|
||||
|
||||
use crate::events::EventManager;
|
||||
use crate::executors::Executor;
|
||||
use crate::observers::ObserversTuple;
|
||||
use crate::inputs::Input;
|
||||
use crate::mutators::Mutator;
|
||||
use crate::stages::Corpus;
|
||||
@ -17,11 +18,12 @@ use crate::serde_anymap::{Ptr, PtrMut};
|
||||
/// 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<M, EM, E, C, I, R>: Stage<EM, E, C, I, R>
|
||||
pub trait MutationalStage<M, EM, E, OT, C, I, R>: Stage<EM, E, OT, C, I, R>
|
||||
where
|
||||
M: Mutator<C, I, R>,
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I, OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
@ -82,24 +84,26 @@ where
|
||||
}
|
||||
|
||||
/// The default mutational stage
|
||||
pub struct StdMutationalStage<M, EM, E, C, I, R>
|
||||
pub struct StdMutationalStage<M, EM, E, OT, C, I, R>
|
||||
where
|
||||
M: Mutator<C, I, R>,
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I, OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
mutator: M,
|
||||
phantom: PhantomData<(EM, E, C, I, R)>,
|
||||
phantom: PhantomData<(EM, E, OT, C, I, R)>,
|
||||
}
|
||||
|
||||
impl<M, EM, E, C, I, R> MutationalStage<M, EM, E, C, I, R> for StdMutationalStage<M, EM, E, C, I, R>
|
||||
impl<M, EM, E, OT, C, I, R> MutationalStage<M, EM, E, OT, C, I, R> for StdMutationalStage<M, EM, E, OT, C, I, R>
|
||||
where
|
||||
M: Mutator<C, I, R>,
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I, OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
@ -117,11 +121,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, EM, E, C, I, R> Stage<EM, E, C, I, R> for StdMutationalStage<M, EM, E, C, I, R>
|
||||
impl<M, EM, E, OT, C, I, R> Stage<EM, E, OT, C, I, R> for StdMutationalStage<M, EM, E, OT, C, I, R>
|
||||
where
|
||||
M: Mutator<C, I, R>,
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I, OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
@ -140,11 +145,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, EM, E, C, I, R> StdMutationalStage<M, EM, E, C, I, R>
|
||||
impl<M, EM, E, OT, C, I, R> StdMutationalStage<M, EM, E, OT, C, I, R>
|
||||
where
|
||||
M: Mutator<C, I, R>,
|
||||
EM: EventManager<C, E, I, R>,
|
||||
E: Executor<I>,
|
||||
E: Executor<I, OT>,
|
||||
OT: ObserversTuple,
|
||||
C: Corpus<I, R>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
|
@ -1,6 +1,8 @@
|
||||
use tuple_list::TupleList;
|
||||
use tuple_list::tuple_list;
|
||||
use core::any::{TypeId, Any};
|
||||
pub use tuple_list::TupleList;
|
||||
pub use tuple_list::tuple_list;
|
||||
pub use tuple_list::tuple_list_type;
|
||||
|
||||
use core::any::TypeId;
|
||||
|
||||
pub trait HasLen {
|
||||
fn len(&self) -> usize;
|
||||
@ -20,10 +22,12 @@ impl<Head, Tail> HasLen for (Head, Tail) where
|
||||
|
||||
pub trait MatchFirstType {
|
||||
fn match_first_type<T: 'static>(&self) -> Option<&T>;
|
||||
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T>;
|
||||
}
|
||||
|
||||
impl MatchFirstType for () {
|
||||
fn match_first_type<T: 'static>(&self) -> Option<&T> { None }
|
||||
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T> { None }
|
||||
}
|
||||
|
||||
impl<Head, Tail> MatchFirstType for (Head, Tail) where
|
||||
@ -37,14 +41,24 @@ impl<Head, Tail> MatchFirstType for (Head, Tail) where
|
||||
self.1.match_first_type::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
fn match_first_type_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||
if TypeId::of::<T>() == TypeId::of::<Head>() {
|
||||
unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }
|
||||
} else {
|
||||
self.1.match_first_type_mut::<T>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MatchType {
|
||||
fn match_type<T: 'static>(&self, f: fn(t: &T));
|
||||
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &mut T));
|
||||
}
|
||||
|
||||
impl MatchType for () {
|
||||
fn match_type<T: 'static>(&self, f: fn(t: &T)) { () }
|
||||
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &mut T)) { () }
|
||||
}
|
||||
|
||||
impl<Head, Tail> MatchType for (Head, Tail) where
|
||||
@ -57,6 +71,13 @@ impl<Head, Tail> MatchType for (Head, Tail) where
|
||||
}
|
||||
self.1.match_type::<T>(f);
|
||||
}
|
||||
|
||||
fn match_type_mut<T: 'static>(&mut self, f: fn(t: &mut T)) {
|
||||
if TypeId::of::<T>() == TypeId::of::<Head>() {
|
||||
f(unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }.unwrap());
|
||||
}
|
||||
self.1.match_type_mut::<T>(f);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Named {
|
||||
@ -65,10 +86,12 @@ pub trait Named {
|
||||
|
||||
pub trait MatchNameAndType {
|
||||
fn match_name_type<T: 'static>(&self, name: &'static str) -> Option<&T>;
|
||||
fn match_name_type_mut<T: 'static>(&mut self, name: &'static str) -> Option<&mut T>;
|
||||
}
|
||||
|
||||
impl MatchNameAndType for () {
|
||||
fn match_name_type<T: 'static>(&self, name: &'static str) -> Option<&T> { None }
|
||||
fn match_name_type_mut<T: 'static>(&mut self, name: &'static str) -> Option<&mut T> { None }
|
||||
}
|
||||
|
||||
impl<Head, Tail> MatchNameAndType for (Head, Tail) where
|
||||
@ -82,6 +105,14 @@ impl<Head, Tail> MatchNameAndType for (Head, Tail) where
|
||||
self.1.match_name_type::<T>(name)
|
||||
}
|
||||
}
|
||||
|
||||
fn match_name_type_mut<T: 'static>(&mut self, name: &'static str) -> Option<&mut T> {
|
||||
if TypeId::of::<T>() == TypeId::of::<Head>() && name == self.0.name() {
|
||||
unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }
|
||||
} else {
|
||||
self.1.match_name_type_mut::<T>(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Prepend<T>: TupleList {
|
||||
|
Loading…
x
Reference in New Issue
Block a user