State is now a struct

This commit is contained in:
Andrea Fioraldi 2020-12-08 13:07:57 +01:00
parent ff983ecf23
commit de4fb23f31
2 changed files with 161 additions and 202 deletions

View File

@ -19,167 +19,12 @@ use crate::stages::Stage;
use crate::utils::{current_milliseconds, Rand}; use crate::utils::{current_milliseconds, Rand};
use crate::AflError; use crate::AflError;
// TODO FeedbackMetadata to store histroy_map
pub trait StateMetadata: Debug { pub trait StateMetadata: Debug {
/// The name of this metadata - used to find it in the list of avaliable metadatas /// The name of this metadata - used to find it in the list of avaliable metadatas
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
} }
pub trait State<C, E, I, R> pub struct State<C, E, I, R>
where
C: Corpus<I, R>,
E: Executor<I>,
I: Input,
R: Rand,
{
/// Get executions
fn executions(&self) -> usize;
/// Set executions
fn set_executions(&mut self, executions: usize);
fn start_time(&self) -> u64;
fn set_start_time(&mut self, ms: u64);
fn executions_over_seconds(&self) -> u64 {
let elapsed = current_milliseconds() - self.start_time();
if elapsed == 0 {
return 0;
}
let elapsed = elapsed / 1000;
if elapsed == 0 {
0
} else {
(self.executions() as u64) / elapsed
}
}
/// Get all the metadatas into an HashMap
fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>>;
/// Get all the metadatas into an HashMap (mutable)
fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>>;
/// Add a metadata
fn add_metadata(&mut self, meta: Box<dyn StateMetadata>) {
self.metadatas_mut().insert(meta.name(), meta);
}
/// Returns vector of feebacks
fn feedbacks(&self) -> &[Box<dyn Feedback<I>>];
/// Returns vector of feebacks (mutable)
fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>>;
/// Adds a feedback
fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>) {
self.feedbacks_mut().push(feedback);
}
/// Return the executor
fn executor(&self) -> &E;
/// Return the executor (mutable)
fn executor_mut(&mut self) -> &mut E;
/// Runs the input and triggers observers and feedback
fn evaluate_input(&mut self, input: &I) -> Result<u32, AflError> {
self.executor_mut().reset_observers()?;
self.executor_mut().run_target(&input)?;
self.set_executions(self.executions() + 1);
self.executor_mut().post_exec_observers()?;
let mut fitness = 0;
let observers = self.executor().observers();
for feedback in self.feedbacks_mut() {
fitness += feedback.is_interesting(&input, observers)?;
}
Ok(fitness)
}
/// Resets all current feedbacks
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(())
}
/// Creates a new testcase, appending the metadata from each feedback
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)?;
}
Ok(testcase)
}
/// Create a testcase from this input, if it's intersting
fn testcase_if_interesting(
&mut self,
input: I,
fitness: u32,
) -> Result<Option<Testcase<I>>, AflError> {
if fitness > 0 {
Ok(Some(self.input_to_testcase(input, fitness)?))
} else {
self.discard_input(&input)?;
Ok(None)
}
}
/// Adds this input to the corpus, if it's intersting
fn add_if_interesting(
&mut self,
corpus: &mut C,
input: I,
fitness: u32,
) -> Result<Option<usize>, AflError> {
if fitness > 0 {
let testcase = self.input_to_testcase(input, fitness)?;
Ok(Some(corpus.add(testcase)))
} else {
self.discard_input(&input)?;
Ok(None)
}
}
}
pub fn generate_initial_inputs<S, G, C, E, I, R, EM>(
rand: &mut R,
state: &mut S,
corpus: &mut C,
generator: &mut G,
events: &mut EM,
num: usize,
) -> Result<(), AflError>
where
S: State<C, E, I, R>,
G: Generator<I, R>,
C: Corpus<I, R>,
E: Executor<I>,
I: Input,
R: Rand,
EM: EventManager<S, C, E, I, R>,
{
for _ in 0..num {
let input = generator.generate(rand)?;
let fitness = state.evaluate_input(&input)?;
state.add_if_interesting(corpus, input, fitness)?;
events.fire(Event::LoadInitial {
sender_id: 0,
phantom: PhantomData,
})?;
}
events.process(state, corpus)?;
Ok(())
}
pub struct StdState<C, E, I, R>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
E: Executor<I>, E: Executor<I>,
@ -196,60 +41,167 @@ where
phantom: PhantomData<(C, R)>, phantom: PhantomData<(C, R)>,
} }
impl<C, E, I, R> State<C, E, I, R> for StdState<C, E, I, R> impl<C, E, I, R> State<C, E, I, R>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
E: Executor<I>, E: Executor<I>,
I: Input, I: Input,
R: Rand, R: Rand,
{ {
fn executions(&self) -> usize { /// Get executions
pub fn executions(&self) -> usize {
self.executions self.executions
} }
fn set_executions(&mut self, executions: usize) { /// Set executions
pub fn set_executions(&mut self, executions: usize){
self.executions = executions self.executions = executions
} }
fn start_time(&self) -> u64 { pub fn start_time(&self) -> u64{
self.start_time self.start_time
} }
fn set_start_time(&mut self, ms: u64) { pub fn set_start_time(&mut self, ms: u64) {
self.start_time = ms self.start_time = ms
} }
fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>> { pub fn executions_over_seconds(&self) -> u64 {
let elapsed = current_milliseconds() - self.start_time();
if elapsed == 0 {
return 0;
}
let elapsed = elapsed / 1000;
if elapsed == 0 {
0
} else {
(self.executions() as u64) / elapsed
}
}
/// Get all the metadatas into an HashMap
pub fn metadatas(&self) -> &HashMap<&'static str, Box<dyn StateMetadata>>{
&self.metadatas &self.metadatas
} }
fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>> { /// Get all the metadatas into an HashMap (mutable)
pub fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn StateMetadata>>{
&mut self.metadatas &mut self.metadatas
} }
fn feedbacks(&self) -> &[Box<dyn Feedback<I>>] { /// Add a metadata
pub fn add_metadata(&mut self, meta: Box<dyn StateMetadata>) {
self.metadatas_mut().insert(meta.name(), meta);
}
/// Returns vector of feebacks
pub fn feedbacks(&self) -> &[Box<dyn Feedback<I>>]{
&self.feedbacks &self.feedbacks
} }
fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>> { /// Returns vector of feebacks (mutable)
pub fn feedbacks_mut(&mut self) -> &mut Vec<Box<dyn Feedback<I>>>{
&mut self.feedbacks &mut self.feedbacks
} }
fn executor(&self) -> &E { /// Adds a feedback
&self.executor pub fn add_feedback(&mut self, feedback: Box<dyn Feedback<I>>) {
self.feedbacks_mut().push(feedback);
} }
fn executor_mut(&mut self) -> &mut E { /// Runs the input and triggers observers and feedback
&mut self.executor pub fn evaluate_input<FE, EM>(&mut self, input: &I, engine: &FE) -> Result<u32, AflError>
} where
} FE: FuzzingEngine<EM, E, C, I, R>,
EM: EventManager<C, E, I, R>,
{
engine.executor_mut().reset_observers()?;
engine.executor_mut().run_target(&input)?;
self.set_executions(self.executions() + 1);
engine.executor_mut().post_exec_observers()?;
let mut fitness = 0;
let observers = self.executor().observers();
for feedback in self.feedbacks_mut() {
fitness += feedback.is_interesting(&input, observers)?;
}
Ok(fitness)
}
/// Resets all current feedbacks
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(())
}
/// Creates a new testcase, appending the metadata from each feedback
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)?;
}
Ok(testcase)
}
/// Create a testcase from this input, if it's intersting
pub fn testcase_if_interesting(
&mut self,
input: I,
fitness: u32,
) -> Result<Option<Testcase<I>>, AflError> {
if fitness > 0 {
Ok(Some(self.input_to_testcase(input, fitness)?))
} else {
self.discard_input(&input)?;
Ok(None)
}
}
/// Adds this input to the corpus, if it's intersting
pub fn add_if_interesting(
&mut self,
corpus: &mut C,
input: I,
fitness: u32,
) -> Result<Option<usize>, AflError> {
if fitness > 0 {
let testcase = self.input_to_testcase(input, fitness)?;
Ok(Some(corpus.add(testcase)))
} else {
self.discard_input(&input)?;
Ok(None)
}
}
pub fn generate_initial_inputs<G, EM>(
&mut self,
rand: &mut R,
corpus: &mut C,
generator: &mut G,
events: &mut EM,
num: usize,
) -> Result<(), AflError>
where
G: Generator<I, R>,
EM: EventManager<C, E, I, R>,
{
for _ in 0..num {
let input = generator.generate(rand)?;
let fitness = self.evaluate_input(&input)?;
self.add_if_interesting(corpus, input, fitness)?;
events.fire(Event::LoadInitial {
sender_id: 0,
phantom: PhantomData,
})?;
}
events.process(self, corpus)?;
Ok(())
}
impl<C, E, I, R> StdState<C, E, I, R>
where
C: Corpus<I, R>,
E: Executor<I>,
I: Input,
R: Rand,
{
pub fn new(executor: E) -> Self { pub fn new(executor: E) -> Self {
Self { Self {
executions: 0, executions: 0,
@ -263,27 +215,38 @@ where
} }
} }
pub trait Engine<S, EM, E, C, I, R> pub trait FuzzingEngine<EM, E, C, I, R>
where where
S: State<C, E, I, R>, EM: EventManager<C, E, I, R>,
EM: EventManager<S, C, E, I, R>,
E: Executor<I>, E: Executor<I>,
C: Corpus<I, R>, C: Corpus<I, R>,
I: Input, I: Input,
R: Rand, R: Rand,
{ {
fn stages(&self) -> &[Box<dyn Stage<S, EM, E, C, I, R>>]; fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>];
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, EM, E, C, I, R>>>; fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>>;
fn add_stage(&mut self, stage: Box<dyn Stage<S, EM, E, C, I, R>>) { fn add_stage(&mut self, stage: Box<dyn Stage<EM, E, C, I, R>>) {
self.stages_mut().push(stage); self.stages_mut().push(stage);
} }
fn events_manager(&self) -> &EM;
fn events_manager_mut(&mut self) -> &mut EM;
/// Return the executor
fn executor(&self) -> &E;
/// Return the executor (mutable)
fn executor_mut(&mut self) -> &mut E;
// TODO additional executors, Vec<Box<dyn Executor<I>>>
fn fuzz_one( fn fuzz_one(
&mut self, &mut self,
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut State<C, E, I, R>,
corpus: &mut C, corpus: &mut C,
events: &mut EM, events: &mut EM,
) -> Result<usize, AflError> { ) -> Result<usize, AflError> {
@ -309,7 +272,7 @@ where
fn fuzz_loop( fn fuzz_loop(
&mut self, &mut self,
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut State<C, E, I, R>,
corpus: &mut C, corpus: &mut C,
events: &mut EM, events: &mut EM,
) -> Result<(), AflError> { ) -> Result<(), AflError> {
@ -329,41 +292,38 @@ where
} }
} }
pub struct StdEngine<S, EM, E, C, I, R> pub struct StdFuzzingEngine<EM, E, C, I, R>
where where
S: State<C, E, I, R>, EM: EventManager<C, E, I, R>,
EM: EventManager<S, C, E, I, R>,
E: Executor<I>, E: Executor<I>,
C: Corpus<I, R>, C: Corpus<I, R>,
I: Input, I: Input,
R: Rand, R: Rand,
{ {
stages: Vec<Box<dyn Stage<S, EM, E, C, I, R>>>, stages: Vec<Box<dyn Stage<EM, E, C, I, R>>>,
phantom: PhantomData<EM>, phantom: PhantomData<EM>,
} }
impl<S, EM, E, C, I, R> Engine<S, EM, E, C, I, R> for StdEngine<S, EM, E, C, I, R> impl<EM, E, C, I, R> FuzzingEngine<EM, E, C, I, R> for StdFuzzingEngine<EM, E, C, I, R>
where where
S: State<C, E, I, R>, EM: EventManager<C, E, I, R>,
EM: EventManager<S, C, E, I, R>,
E: Executor<I>, E: Executor<I>,
C: Corpus<I, R>, C: Corpus<I, R>,
I: Input, I: Input,
R: Rand, R: Rand,
{ {
fn stages(&self) -> &[Box<dyn Stage<S, EM, E, C, I, R>>] { fn stages(&self) -> &[Box<dyn Stage<EM, E, C, I, R>>] {
&self.stages &self.stages
} }
fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<S, EM, E, C, I, R>>> { fn stages_mut(&mut self) -> &mut Vec<Box<dyn Stage<EM, E, C, I, R>>> {
&mut self.stages &mut self.stages
} }
} }
impl<S, EM, E, C, I, R> StdEngine<S, EM, E, C, I, R> impl<EM, E, C, I, R> StdFuzzingEngine<EM, E, C, I, R>
where where
S: State<C, E, I, R>, EM: EventManager<C, E, I, R>,
EM: EventManager<S, C, E, I, R>,
E: Executor<I>, E: Executor<I>,
C: Corpus<I, R>, C: Corpus<I, R>,
I: Input, I: Input,

View File

@ -9,10 +9,9 @@ use crate::inputs::Input;
use crate::utils::Rand; use crate::utils::Rand;
use crate::AflError; use crate::AflError;
pub trait Stage<S, EM, E, C, I, R> pub trait Stage<EM, E, C, I, R>
where where
S: State<C, E, I, R>, EM: EventManager<C, E, I, R>,
EM: EventManager<S, C, E, I, R>,
E: Executor<I>, E: Executor<I>,
C: Corpus<I, R>, C: Corpus<I, R>,
I: Input, I: Input,
@ -22,7 +21,7 @@ where
fn perform( fn perform(
&mut self, &mut self,
rand: &mut R, rand: &mut R,
state: &mut S, state: &mut State<C, E, I, R>,
corpus: &C, corpus: &C,
events: &mut EM, events: &mut EM,
input: &I, input: &I,