import dominik map feedback

This commit is contained in:
Andrea Fioraldi 2020-11-05 10:43:28 +01:00
parent b2a6ddb0dd
commit 63a83a70ff
16 changed files with 450 additions and 156 deletions

View File

@ -1,16 +1,19 @@
pub mod testcase; pub mod testcase;
pub use testcase::{Testcase, TestcaseMetadata}; pub use testcase::{Testcase, TestcaseMetadata};
use crate::utils::{Rand, HasRand};
use crate::inputs::Input; use crate::inputs::Input;
use crate::utils::{HasRand, Rand};
use crate::AflError; use crate::AflError;
use std::path::PathBuf;
use std::marker::PhantomData;
use std::cell::RefCell; use std::cell::RefCell;
use std::marker::PhantomData;
use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
pub trait HasEntriesVec<I> where I: Input { pub trait HasEntriesVec<I>
where
I: Input,
{
/// Get the entries vector field /// Get the entries vector field
fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>>; fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>>;
@ -19,7 +22,10 @@ pub trait HasEntriesVec<I> where I: Input {
} }
/// Corpus with all current testcases /// Corpus with all current testcases
pub trait Corpus<I> : HasEntriesVec<I> + HasRand where I: Input { pub trait Corpus<I>: HasEntriesVec<I> + HasRand
where
I: Input,
{
/// Returns the number of elements /// Returns the number of elements
fn count(&self) -> usize { fn count(&self) -> usize {
self.entries().len() self.entries().len()
@ -37,7 +43,8 @@ pub trait Corpus<I> : HasEntriesVec<I> + HasRand where I: Input {
let mut found = false; let mut found = false;
for x in self.entries() { for x in self.entries() {
i = i + 1; i = i + 1;
if &*x.borrow() as *const _ == entry as *const _ { // TODO check if correct if &*x.borrow() as *const _ == entry as *const _ {
// TODO check if correct
found = true; found = true;
break; break;
} }
@ -61,21 +68,33 @@ pub trait Corpus<I> : HasEntriesVec<I> + HasRand where I: Input {
} }
} }
pub struct InMemoryCorpus<'a, I, R> where I: Input, R: Rand { pub struct InMemoryCorpus<'a, I, R>
where
I: Input,
R: Rand,
{
rand: &'a mut R, rand: &'a mut R,
entries: Vec<Rc<RefCell<Testcase<I>>>> entries: Vec<Rc<RefCell<Testcase<I>>>>,
} }
impl<I, R> HasEntriesVec<I> for InMemoryCorpus<'_, I, R> where I: Input, R: Rand { impl<I, R> HasEntriesVec<I> for InMemoryCorpus<'_, I, R>
where
I: Input,
R: Rand,
{
fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>> { fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>> {
&self.entries &self.entries
} }
fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>>{ fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>> {
&mut self.entries &mut self.entries
} }
} }
impl<I, R> HasRand for InMemoryCorpus<'_, I, R> where I: Input, R: Rand { impl<I, R> HasRand for InMemoryCorpus<'_, I, R>
where
I: Input,
R: Rand,
{
type R = R; type R = R;
fn rand(&self) -> &Self::R { fn rand(&self) -> &Self::R {
@ -86,11 +105,19 @@ impl<I, R> HasRand for InMemoryCorpus<'_, I, R> where I: Input, R: Rand {
} }
} }
impl<I, R> Corpus<I> for InMemoryCorpus<'_, I, R> where I: Input, R: Rand { impl<I, R> Corpus<I> for InMemoryCorpus<'_, I, R>
where
I: Input,
R: Rand,
{
// Just use the default implementation // Just use the default implementation
} }
impl<'a, I, R> InMemoryCorpus<'a, I, R> where I: Input, R: Rand { impl<'a, I, R> InMemoryCorpus<'a, I, R>
where
I: Input,
R: Rand,
{
pub fn new(rand: &'a mut R) -> Self { pub fn new(rand: &'a mut R) -> Self {
InMemoryCorpus { InMemoryCorpus {
rand: rand, rand: rand,
@ -99,22 +126,34 @@ impl<'a, I, R> InMemoryCorpus<'a, I, R> where I: Input, R: Rand {
} }
} }
pub struct OnDiskCorpus<'a, I, R> where I: Input, R: Rand { pub struct OnDiskCorpus<'a, I, R>
where
I: Input,
R: Rand,
{
rand: &'a mut R, rand: &'a mut R,
entries: Vec<Rc<RefCell<Testcase<I>>>>, entries: Vec<Rc<RefCell<Testcase<I>>>>,
dir_path: PathBuf, dir_path: PathBuf,
} }
impl<I, R> HasEntriesVec<I> for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { impl<I, R> HasEntriesVec<I> for OnDiskCorpus<'_, I, R>
where
I: Input,
R: Rand,
{
fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>> { fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>> {
&self.entries &self.entries
} }
fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>>{ fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>> {
&mut self.entries &mut self.entries
} }
} }
impl<I, R> HasRand for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { impl<I, R> HasRand for OnDiskCorpus<'_, I, R>
where
I: Input,
R: Rand,
{
type R = R; type R = R;
fn rand(&self) -> &Self::R { fn rand(&self) -> &Self::R {
@ -125,7 +164,11 @@ impl<I, R> HasRand for OnDiskCorpus<'_, I, R> where I: Input, R: Rand {
} }
} }
impl<I, R> Corpus<I> for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { impl<I, R> Corpus<I> for OnDiskCorpus<'_, I, R>
where
I: Input,
R: Rand,
{
/// Add an entry and save it to disk /// Add an entry and save it to disk
fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) { fn add(&mut self, entry: Rc<RefCell<Testcase<I>>>) {
if *entry.borrow().filename() == None { if *entry.borrow().filename() == None {
@ -140,7 +183,11 @@ impl<I, R> Corpus<I> for OnDiskCorpus<'_, I, R> where I: Input, R: Rand {
// TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus // TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus
} }
impl<'a, I, R> OnDiskCorpus<'a, I, R> where I: Input, R: Rand { impl<'a, I, R> OnDiskCorpus<'a, I, R>
where
I: Input,
R: Rand,
{
pub fn new(rand: &'a mut R, dir_path: PathBuf) -> Self { pub fn new(rand: &'a mut R, dir_path: PathBuf) -> Self {
OnDiskCorpus { OnDiskCorpus {
dir_path: dir_path, dir_path: dir_path,
@ -151,23 +198,35 @@ impl<'a, I, R> OnDiskCorpus<'a, I, R> where I: Input, R: Rand {
} }
/// A Queue-like corpus, wrapping an existing Corpus instance /// A Queue-like corpus, wrapping an existing Corpus instance
pub struct QueueCorpus<I, C> where I: Input, C: Corpus<I> { pub struct QueueCorpus<I, C>
where
I: Input,
C: Corpus<I>,
{
corpus: C, corpus: C,
phantom: PhantomData<I>, phantom: PhantomData<I>,
pos: usize, pos: usize,
cycles: u64, cycles: u64,
} }
impl<'a, I, C> HasEntriesVec<I> for QueueCorpus<I, C> where I: Input, C: Corpus<I> { impl<'a, I, C> HasEntriesVec<I> for QueueCorpus<I, C>
where
I: Input,
C: Corpus<I>,
{
fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>> { fn entries(&self) -> &Vec<Rc<RefCell<Testcase<I>>>> {
self.corpus.entries() self.corpus.entries()
} }
fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>>{ fn entries_mut(&mut self) -> &mut Vec<Rc<RefCell<Testcase<I>>>> {
self.corpus.entries_mut() self.corpus.entries_mut()
} }
} }
impl<'a, I, C> HasRand for QueueCorpus<I, C> where I: Input, C: Corpus<I> { impl<'a, I, C> HasRand for QueueCorpus<I, C>
where
I: Input,
C: Corpus<I>,
{
type R = C::R; type R = C::R;
fn rand(&self) -> &Self::R { fn rand(&self) -> &Self::R {
@ -178,7 +237,11 @@ impl<'a, I, C> HasRand for QueueCorpus<I, C> where I: Input, C: Corpus<I> {
} }
} }
impl<'a, I, C> Corpus<I> for QueueCorpus<I, C> where I: Input, C: Corpus<I> { impl<'a, I, C> Corpus<I> for QueueCorpus<I, C>
where
I: Input,
C: Corpus<I>,
{
/// Returns the number of elements /// Returns the number of elements
fn count(&self) -> usize { fn count(&self) -> usize {
self.corpus.count() self.corpus.count()
@ -212,7 +275,11 @@ impl<'a, I, C> Corpus<I> for QueueCorpus<I, C> where I: Input, C: Corpus<I> {
} }
} }
impl<'a, I, C> QueueCorpus<I, C> where I: Input, C: Corpus<I> { impl<'a, I, C> QueueCorpus<I, C>
where
I: Input,
C: Corpus<I>,
{
pub fn new(corpus: C) -> Self { pub fn new(corpus: C) -> Self {
QueueCorpus::<I, C> { QueueCorpus::<I, C> {
corpus: corpus, corpus: corpus,
@ -234,13 +301,13 @@ impl<'a, I, C> QueueCorpus<I, C> where I: Input, C: Corpus<I> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::corpus::Corpus; use crate::corpus::Corpus;
use crate::corpus::{QueueCorpus, OnDiskCorpus};
use crate::corpus::Testcase; use crate::corpus::Testcase;
use crate::corpus::{OnDiskCorpus, QueueCorpus};
use crate::inputs::bytes::BytesInput; use crate::inputs::bytes::BytesInput;
use crate::utils::Xoshiro256StarRand; use crate::utils::Xoshiro256StarRand;
use std::path::PathBuf;
use std::cell::RefCell; use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
#[test] #[test]
@ -249,10 +316,29 @@ mod tests {
let mut rand = Xoshiro256StarRand::new(); let mut rand = Xoshiro256StarRand::new();
let mut q = QueueCorpus::new(OnDiskCorpus::new(&mut rand, PathBuf::from("fancy/path"))); let mut q = QueueCorpus::new(OnDiskCorpus::new(&mut rand, PathBuf::from("fancy/path")));
let i = BytesInput::new(vec![0; 4]); let i = BytesInput::new(vec![0; 4]);
let t = Rc::new(RefCell::new(Testcase::new_with_filename(i, PathBuf::from("fancyfile")))); let t = Rc::new(RefCell::new(Testcase::new_with_filename(
i,
PathBuf::from("fancyfile"),
)));
q.add(t); q.add(t);
let filename = q.get().unwrap().borrow().filename().as_ref().unwrap().to_owned(); let filename = q
assert_eq!(filename, q.get().unwrap().borrow().filename().as_ref().unwrap().to_owned()); .get()
.unwrap()
.borrow()
.filename()
.as_ref()
.unwrap()
.to_owned();
assert_eq!(
filename,
q.get()
.unwrap()
.borrow()
.filename()
.as_ref()
.unwrap()
.to_owned()
);
assert_eq!(filename, PathBuf::from("fancy/path/fancyfile")); assert_eq!(filename, PathBuf::from("fancy/path/fancyfile"));
} }
} }

View File

@ -29,19 +29,25 @@ pub trait TestcaseTrait<I: Input> {
*/ */
#[derive(Default)] #[derive(Default)]
pub struct Testcase<I> where I: Input { pub struct Testcase<I>
where
I: Input,
{
input: Option<I>, // TODO remove box input: Option<I>, // TODO remove box
filename: Option<PathBuf>, filename: Option<PathBuf>,
metadatas: HashMap<String, Box<dyn TestcaseMetadata>>, metadatas: HashMap<String, Box<dyn TestcaseMetadata>>,
} }
impl<I> Testcase<I> where I: Input { impl<I> Testcase<I>
where
I: Input,
{
/// Make sure to return a valid input instance loading it from disk if not in memory /// Make sure to return a valid input instance loading it from disk if not in memory
pub fn load_input(&mut self) -> Result<&I, AflError> { pub fn load_input(&mut self) -> Result<&I, AflError> {
// TODO: Implement cache to disk // TODO: Implement cache to disk
match self.input.as_ref() { match self.input.as_ref() {
Some(i) => Ok(i), Some(i) => Ok(i),
None => Err(AflError::NotImplemented("load_input".to_string())) None => Err(AflError::NotImplemented("load_input".to_string())),
} }
} }

View File

@ -1,12 +1,13 @@
use std::time; use std::time;
use crate::engines::Engine; use crate::engines::Engine;
use crate::inputs::Input;
use crate::executors::Executor; use crate::executors::Executor;
use crate::feedbacks::Feedback; use crate::feedbacks::Feedback;
use crate::inputs::Input;
use crate::monitors::Monitor; use crate::monitors::Monitor;
use crate::stages::Stage; use crate::stages::Stage;
use crate::utils::Rand; use crate::utils::Rand;
/* /*
pub struct AflEngine<'a, I: Input> { pub struct AflEngine<'a, I: Input> {
pub rand: &'a mut dyn Rand, pub rand: &'a mut dyn Rand,

View File

@ -1,14 +1,16 @@
pub mod aflengine; pub mod aflengine;
use crate::AflError;
use crate::inputs::Input;
use crate::corpus::testcase::Testcase; use crate::corpus::testcase::Testcase;
use crate::inputs::Input;
use crate::AflError;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
pub trait Engine<'a, I> where I: Input { pub trait Engine<'a, I>
where
fn execute(&mut self, input: &mut I, entry: Rc<RefCell<Testcase<I>>>) -> Result<bool, AflError>; I: Input,
{
fn execute(&mut self, input: &mut I, entry: Rc<RefCell<Testcase<I>>>)
-> Result<bool, AflError>;
} }

View File

@ -4,12 +4,15 @@ use crate::AflError;
use crate::executors::{Executor, ExitKind}; use crate::executors::{Executor, ExitKind};
use std::ptr;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr;
type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind; type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
pub struct InMemoryExecutor<I> where I: Input { pub struct InMemoryExecutor<I>
where
I: Input,
{
cur_input: Option<Box<I>>, cur_input: Option<Box<I>>,
observers: Vec<Box<dyn Observer>>, observers: Vec<Box<dyn Observer>>,
harness: HarnessFunction<I>, harness: HarnessFunction<I>,
@ -17,7 +20,10 @@ pub struct InMemoryExecutor<I> where I: Input {
static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null(); static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null();
impl<I> Executor<I> for InMemoryExecutor<I> where I: Input { impl<I> Executor<I> for InMemoryExecutor<I>
where
I: Input,
{
fn run_target(&mut self) -> Result<ExitKind, AflError> { fn run_target(&mut self) -> Result<ExitKind, AflError> {
let bytes = match self.cur_input.as_ref() { let bytes = match self.cur_input.as_ref() {
Some(i) => i.serialize(), Some(i) => i.serialize(),
@ -72,7 +78,10 @@ impl<I> Executor<I> for InMemoryExecutor<I> where I: Input {
} }
} }
impl<I> InMemoryExecutor<I> where I: Input { impl<I> InMemoryExecutor<I>
where
I: Input,
{
pub fn new(harness_fn: HarnessFunction<I>) -> Self { pub fn new(harness_fn: HarnessFunction<I>) -> Self {
unsafe { unsafe {
os_signals::setup_crash_handlers::<I, Self>(); os_signals::setup_crash_handlers::<I, Self>();
@ -98,14 +107,17 @@ pub mod unix_signals {
use std::{mem, process, ptr}; use std::{mem, process, ptr};
use crate::executors::inmemory::CURRENT_INMEMORY_EXECUTOR_PTR; use crate::executors::inmemory::CURRENT_INMEMORY_EXECUTOR_PTR;
use crate::inputs::Input;
use crate::executors::Executor; use crate::executors::Executor;
use crate::inputs::Input;
pub extern "C" fn libaflrs_executor_inmem_handle_crash<I, E>( pub extern "C" fn libaflrs_executor_inmem_handle_crash<I, E>(
_sig: c_int, _sig: c_int,
info: siginfo_t, info: siginfo_t,
_void: c_void, _void: c_void,
) where I: Input, E: Executor<I> { ) where
I: Input,
E: Executor<I>,
{
unsafe { unsafe {
if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() { if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() {
println!( println!(
@ -123,7 +135,10 @@ pub mod unix_signals {
_sig: c_int, _sig: c_int,
_info: siginfo_t, _info: siginfo_t,
_void: c_void, _void: c_void,
) where I: Input, E: Executor<I> { ) where
I: Input,
E: Executor<I>,
{
dbg!("TIMEOUT/SIGUSR2 received"); dbg!("TIMEOUT/SIGUSR2 received");
unsafe { unsafe {
if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() { if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() {
@ -137,7 +152,11 @@ pub mod unix_signals {
process::abort(); process::abort();
} }
pub unsafe fn setup_crash_handlers<I, E>() where I: Input, E: Executor<I> { pub unsafe fn setup_crash_handlers<I, E>()
where
I: Input,
E: Executor<I>,
{
let mut sa: sigaction = mem::zeroed(); let mut sa: sigaction = mem::zeroed();
libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
sa.sa_flags = SA_NODEFER | SA_SIGINFO; sa.sa_flags = SA_NODEFER | SA_SIGINFO;
@ -167,15 +186,14 @@ use unix_signals as os_signals;
#[cfg(not(unix))] #[cfg(not(unix))]
compile_error!("InMemoryExecutor not yet supported on this OS"); compile_error!("InMemoryExecutor not yet supported on this OS");
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::any::Any;
use crate::executors::{Executor, ExitKind};
use crate::executors::inmemory::InMemoryExecutor; use crate::executors::inmemory::InMemoryExecutor;
use crate::executors::{Executor, ExitKind};
use crate::inputs::Input; use crate::inputs::Input;
use crate::observers::Observer; use crate::observers::Observer;
use crate::AflError; use crate::AflError;
use std::any::Any;
#[derive(Clone)] #[derive(Clone)]
struct NopInput {} struct NopInput {}

View File

@ -13,7 +13,10 @@ pub enum ExitKind {
// TODO unbox input // TODO unbox input
pub trait Executor<I> where I: Input { pub trait Executor<I>
where
I: Input,
{
/// Run the target /// Run the target
fn run_target(&mut self) -> Result<ExitKind, AflError>; fn run_target(&mut self) -> Result<ExitKind, AflError>;

View File

@ -1,80 +1,142 @@
extern crate num; extern crate num;
use crate::corpus::Testcase; use crate::corpus::Testcase;
use crate::inputs::Input;
use crate::executors::Executor; use crate::executors::Executor;
use crate::inputs::Input;
use crate::observers::MapObserver; use crate::observers::MapObserver;
use num::Integer; use num::Integer;
use std::cell::RefCell;
use std::marker::PhantomData; use std::marker::PhantomData;
pub trait Feedback<I> where I: Input { pub trait Feedback<I>
where
I: Input,
{
/// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) /// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55)
fn is_interesting(&mut self, executor: &dyn Executor<I>, entry: &Testcase<I>) -> u8; fn is_interesting(&mut self, executor: &dyn Executor<I>, entry: &Testcase<I>) -> u8;
} }
/* pub trait Reducer<T>
pub trait Feedback { where
/// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) T: Integer + Copy + 'static,
fn is_interesting(&mut self, executor: &dyn Executor, entry: &Testcase) -> u8; {
}
pub trait Reducer<T: Integer + Copy + 'static> {
fn reduce(first: T, second: T) -> T; fn reduce(first: T, second: T) -> T;
} }
pub trait MaxReducer<T: Integer + Copy + 'static> { pub struct MaxReducer<T>
where
T: Integer + Copy + 'static,
{
phantom: PhantomData<T>,
}
impl<T> Reducer<T> for MaxReducer<T>
where
T: Integer + Copy + 'static,
{
fn reduce(first: T, second: T) -> T { fn reduce(first: T, second: T) -> T {
if first > second { first } else { second } if first > second {
first
} else {
second
}
} }
} }
pub trait MinReducer<T: Integer + Copy + 'static> { pub struct MinReducer<T>
where
T: Integer + Copy + 'static,
{
phantom: PhantomData<T>,
}
impl<T> Reducer<T> for MinReducer<T>
where
T: Integer + Copy + 'static,
{
fn reduce(first: T, second: T) -> T { fn reduce(first: T, second: T) -> T {
if first < second { first } else { second } if first < second {
first
} else {
second
}
} }
} }
pub struct MapFeedback<MapT: Integer + Copy + 'static, ReducerT: Reducer<MapT>> { /// The most common AFL-like feedback type
virgin_map: Vec<MapT>, pub struct MapFeedback<'a, T, R>
_phantom: PhantomData<ReducerT>, where
T: Integer + Copy + 'static,
R: Reducer<T>,
{
/// Contains information about untouched entries
history_map: &'a RefCell<Vec<T>>,
/// The observer this feedback struct observes
map_observer: &'a RefCell<MapObserver</*'a,*/ T>>,
/// Phantom Data of Reducer
phantom: PhantomData<R>,
} }
impl<'a, MapT: Integer + Copy + 'static, ReducerT: Reducer<MapT>> Feedback for MapFeedback<MapT, ReducerT> { impl<'a, T, R, I> Feedback<I> for MapFeedback<'a, T, R>
fn is_interesting(&mut self, executor: &dyn Executor, _entry: &dyn Testcase) -> u8 { where
T: Integer + Copy + 'static,
R: Reducer<T>,
I: Input,
{
fn is_interesting(&mut self, _executor: &dyn Executor<I>, entry: &Testcase<I>) -> u8 {
let mut interesting = 0; let mut interesting = 0;
for observer in executor.get_observers() {
if let Some(o) = observer.as_any().downcast_ref::<MapObserver<MapT>>() { // TODO: impl. correctly, optimize
// TODO: impl. correctly, optimize for (history, map) in self
for (virgin, map) in self.virgin_map.iter_mut().zip(o.get_map().iter()) { .history_map
let reduced = ReducerT::reduce(*virgin, *map); .borrow_mut()
if *virgin != reduced { .iter_mut()
*virgin = reduced; .zip(self.map_observer.borrow().get_map().iter())
if interesting < 250 { {
interesting += 25 let reduced = R::reduce(*history, *map);
} if *history != reduced {
} *history = reduced;
interesting += 25;
if interesting >= 250 {
return 255;
} }
break
} }
} }
interesting interesting
} }
} }
impl<'a, MapT: Integer + Copy + 'static, ReducerT: Reducer<MapT>> MapFeedback<MapT, ReducerT> { impl<'a, T, R> MapFeedback<'a, T, R>
/// Create new MapFeedback using a static map observer where
pub fn new(map_size: usize) -> Self { T: Integer + Copy + 'static,
R: Reducer<T>,
{
/// Create new MapFeedback using a map observer, and a map.
/// The map can be shared.
pub fn new(
map_observer: &'a RefCell<MapObserver</*'a, */ T>>,
history_map: &'a RefCell<Vec<T>>,
) -> Self {
MapFeedback { MapFeedback {
virgin_map: vec![MapT::zero(); map_size], map_observer: map_observer,
_phantom: PhantomData, history_map: history_map,
phantom: PhantomData,
} }
} }
} }
#[allow(dead_code)] /// Returns a usable history map of the given size
type MaxMapFeedback<MapT> = MapFeedback<MapT, dyn MaxReducer<MapT>>; pub fn create_history_map<T>(map_size: usize) -> RefCell<Vec<T>>
#[allow(dead_code)] where
type MinMapFeedback<MapT> = MapFeedback<MapT, dyn MinReducer<MapT>>; T: Default + Clone,
{
{
RefCell::new(vec![T::default(); map_size])
}
}
*/ #[allow(dead_code)]
type MaxMapFeedback<'a, T> = MapFeedback<'a, T, MaxReducer<T>>;
#[allow(dead_code)]
type MinMapFeedback<'a, T> = MapFeedback<'a, T, MinReducer<T>>;

View File

@ -33,9 +33,7 @@ impl HasBytesVec for BytesInput {
impl BytesInput { impl BytesInput {
pub fn new(bytes: Vec<u8>) -> Self { pub fn new(bytes: Vec<u8>) -> Self {
BytesInput { BytesInput { bytes: bytes }
bytes: bytes
}
} }
} }

View File

@ -1,15 +1,15 @@
pub mod bytes; pub mod bytes;
pub use bytes::{HasBytesVec, BytesInput}; pub use bytes::{BytesInput, HasBytesVec};
use std::clone::Clone;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
use std::clone::Clone;
use crate::AflError; use crate::AflError;
pub trait Input : Clone { pub trait Input: Clone {
fn to_file(&self, path: &PathBuf) -> Result<(), AflError> { fn to_file(&self, path: &PathBuf) -> Result<(), AflError> {
let mut file = File::create(path)?; let mut file = File::create(path)?;
file.write_all(self.serialize()?)?; file.write_all(self.serialize()?)?;

View File

@ -26,7 +26,7 @@ pub enum AflError {
NotImplemented(String), NotImplemented(String),
#[error("Unknown error: {0}")] #[error("Unknown error: {0}")]
Unknown(String), Unknown(String),
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -1,12 +1,15 @@
use crate::corpus::Corpus;
use crate::inputs::Input; use crate::inputs::Input;
use crate::utils::HasRand; use crate::utils::HasRand;
use crate::corpus::Corpus;
use crate::AflError; use crate::AflError;
pub mod scheduled; pub mod scheduled;
pub trait HasOptionCorpus<I> where I: Input { pub trait HasOptionCorpus<I>
type C : Corpus<I>; where
I: Input,
{
type C: Corpus<I>;
/// Get the associated corpus, if any /// Get the associated corpus, if any
fn corpus(&self) -> &Option<Box<Self::C>>; fn corpus(&self) -> &Option<Box<Self::C>>;
@ -18,7 +21,10 @@ pub trait HasOptionCorpus<I> where I: Input {
fn set_corpus(&mut self, corpus: Option<Box<Self::C>>); fn set_corpus(&mut self, corpus: Option<Box<Self::C>>);
} }
pub trait Mutator<I> : HasRand where I: Input { pub trait Mutator<I>: HasRand
where
I: Input,
{
/// Mutate a given input /// Mutate a given input
fn mutate(&mut self, input: &mut I, stage_idx: i32) -> Result<(), AflError>; fn mutate(&mut self, input: &mut I, stage_idx: i32) -> Result<(), AflError>;

View File

@ -1,7 +1,7 @@
use crate::mutators::{HasOptionCorpus, Mutator};
use crate::utils::{Rand, HasRand};
use crate::corpus::Corpus; use crate::corpus::Corpus;
use crate::inputs::{Input, HasBytesVec}; use crate::inputs::{HasBytesVec, Input};
use crate::mutators::{HasOptionCorpus, Mutator};
use crate::utils::{HasRand, Rand};
use crate::AflError; use crate::AflError;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -9,7 +9,10 @@ use std::marker::PhantomData;
/// The generic function type that identifies mutations /// The generic function type that identifies mutations
type MutationFunction<M, I> = fn(&mut M, &mut I) -> Result<(), AflError>; type MutationFunction<M, I> = fn(&mut M, &mut I) -> Result<(), AflError>;
pub trait ComposedByMutations<I> where I: Input { pub trait ComposedByMutations<I>
where
I: Input,
{
/// Get a mutation by index /// Get a mutation by index
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, I>, AflError>; fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, I>, AflError>;
@ -20,7 +23,10 @@ pub trait ComposedByMutations<I> where I: Input {
fn add_mutation(&mut self, mutation: MutationFunction<Self, I>); fn add_mutation(&mut self, mutation: MutationFunction<Self, I>);
} }
pub trait ScheduledMutator<I>: Mutator<I> + HasOptionCorpus<I> + ComposedByMutations<I> where I: Input { pub trait ScheduledMutator<I>: Mutator<I> + HasOptionCorpus<I> + ComposedByMutations<I>
where
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, _input: &I) -> u64 { fn iterations(&mut self, _input: &I) -> u64 {
1 << (1 + self.rand_mut().below(7)) 1 << (1 + self.rand_mut().below(7))
@ -50,13 +56,23 @@ pub trait ScheduledMutator<I>: Mutator<I> + HasOptionCorpus<I> + ComposedByMutat
} }
} }
pub struct DefaultScheduledMutator<'a, I, R, C> where I: Input, R: Rand, C: Corpus<I> { pub struct DefaultScheduledMutator<'a, I, R, C>
where
I: Input,
R: Rand,
C: Corpus<I>,
{
rand: &'a mut R, rand: &'a mut R,
corpus: Option<Box<C>>, corpus: Option<Box<C>>,
mutations: Vec<MutationFunction<Self, I>> mutations: Vec<MutationFunction<Self, I>>,
} }
impl<'a, I, R, C> HasRand for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus<I> { impl<'a, I, R, C> HasRand for DefaultScheduledMutator<'_, I, R, C>
where
I: Input,
R: Rand,
C: Corpus<I>,
{
type R = R; type R = R;
fn rand(&self) -> &Self::R { fn rand(&self) -> &Self::R {
@ -67,7 +83,12 @@ impl<'a, I, R, C> HasRand for DefaultScheduledMutator<'_, I, R, C> where I: Inpu
} }
} }
impl<I, R, C> HasOptionCorpus<I> for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus<I> { impl<I, R, C> HasOptionCorpus<I> for DefaultScheduledMutator<'_, I, R, C>
where
I: Input,
R: Rand,
C: Corpus<I>,
{
type C = C; type C = C;
fn corpus(&self) -> &Option<Box<Self::C>> { fn corpus(&self) -> &Option<Box<Self::C>> {
@ -83,13 +104,23 @@ impl<I, R, C> HasOptionCorpus<I> for DefaultScheduledMutator<'_, I, R, C> where
} }
} }
impl<'a, I, R, C> Mutator<I> for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus<I> { impl<'a, I, R, C> Mutator<I> for DefaultScheduledMutator<'_, I, R, C>
where
I: Input,
R: Rand,
C: Corpus<I>,
{
fn mutate(&mut self, input: &mut I, _stage_idx: i32) -> Result<(), AflError> { fn mutate(&mut self, input: &mut I, _stage_idx: i32) -> Result<(), AflError> {
self.scheduled_mutate(input, _stage_idx) self.scheduled_mutate(input, _stage_idx)
} }
} }
impl<'a, I, R, C> ComposedByMutations<I> for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus<I> { impl<'a, I, R, C> ComposedByMutations<I> for DefaultScheduledMutator<'_, I, R, C>
where
I: Input,
R: Rand,
C: Corpus<I>,
{
fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, I>, AflError> { fn mutation_by_idx(&self, index: usize) -> Result<MutationFunction<Self, I>, AflError> {
if index >= self.mutations.len() { if index >= self.mutations.len() {
return Err(AflError::Unknown("oob".to_string())); return Err(AflError::Unknown("oob".to_string()));
@ -106,44 +137,70 @@ impl<'a, I, R, C> ComposedByMutations<I> for DefaultScheduledMutator<'_, I, R, C
} }
} }
impl<'a, I, R, C> ScheduledMutator<I> for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus<I> { impl<'a, I, R, C> ScheduledMutator<I> for DefaultScheduledMutator<'_, I, R, C>
where
I: Input,
R: Rand,
C: Corpus<I>,
{
// Just use the default methods // Just use the default methods
} }
impl<'a, I, R, C> DefaultScheduledMutator<'a, I, R, C> where I: Input, R: Rand, C: Corpus<I> { impl<'a, I, R, C> DefaultScheduledMutator<'a, I, R, C>
where
I: Input,
R: Rand,
C: Corpus<I>,
{
/// Create a new DefaultScheduledMutator instance without mutations and corpus /// Create a new DefaultScheduledMutator instance without mutations and corpus
pub fn new(rand: &'a mut R) -> Self { pub fn new(rand: &'a mut R) -> Self {
DefaultScheduledMutator { DefaultScheduledMutator {
rand: rand, rand: rand,
corpus: None, corpus: None,
mutations: vec![] mutations: vec![],
} }
} }
/// Create a new DefaultScheduledMutator instance specifying mutations and corpus too /// Create a new DefaultScheduledMutator instance specifying mutations and corpus too
pub fn new_all(rand: &'a mut R, corpus: Option<Box<C>>, mutations: Vec<MutationFunction<Self, I>>) -> Self { pub fn new_all(
rand: &'a mut R,
corpus: Option<Box<C>>,
mutations: Vec<MutationFunction<Self, I>>,
) -> Self {
DefaultScheduledMutator { DefaultScheduledMutator {
rand: rand, rand: rand,
corpus: corpus, corpus: corpus,
mutations: mutations mutations: mutations,
} }
} }
} }
/// Bitflip mutation for inputs with a bytes vector /// Bitflip mutation for inputs with a bytes vector
pub fn mutation_bitflip<M, I>(mutator: &mut M, input: &mut I) -> Result<(), AflError> where M: Mutator<I>, I: Input + HasBytesVec { pub fn mutation_bitflip<M, I>(mutator: &mut M, input: &mut I) -> Result<(), AflError>
where
M: Mutator<I>,
I: Input + HasBytesVec,
{
let bit = mutator.rand_mut().below(input.bytes().len() as u64) as usize; let bit = mutator.rand_mut().below(input.bytes().len() as u64) as usize;
input.bytes_mut()[bit >> 3] ^= (128 >> (bit & 7)) as u8; input.bytes_mut()[bit >> 3] ^= (128 >> (bit & 7)) as u8;
Ok(()) Ok(())
} }
/// Schedule some selected byte level mutations given a ScheduledMutator type /// Schedule some selected byte level mutations given a ScheduledMutator type
pub struct HavocBytesMutator<I, S> where I: Input + HasBytesVec, S: ScheduledMutator<I> { pub struct HavocBytesMutator<I, S>
where
I: Input + HasBytesVec,
S: ScheduledMutator<I>,
{
scheduled: S, scheduled: S,
phantom: PhantomData<I> phantom: PhantomData<I>,
} }
impl<I, S> HasRand for HavocBytesMutator<I, S> where I: Input + HasBytesVec, S: ScheduledMutator<I> { impl<I, S> HasRand for HavocBytesMutator<I, S>
where
I: Input + HasBytesVec,
S: ScheduledMutator<I>,
{
type R = S::R; type R = S::R;
fn rand(&self) -> &Self::R { fn rand(&self) -> &Self::R {
@ -154,7 +211,11 @@ impl<I, S> HasRand for HavocBytesMutator<I, S> where I: Input + HasBytesVec, S:
} }
} }
impl<I, S> HasOptionCorpus<I> for HavocBytesMutator<I, S> where I: Input + HasBytesVec, S: ScheduledMutator<I> { impl<I, S> HasOptionCorpus<I> for HavocBytesMutator<I, S>
where
I: Input + HasBytesVec,
S: ScheduledMutator<I>,
{
type C = S::C; type C = S::C;
fn corpus(&self) -> &Option<Box<Self::C>> { fn corpus(&self) -> &Option<Box<Self::C>> {
@ -170,31 +231,44 @@ impl<I, S> HasOptionCorpus<I> for HavocBytesMutator<I, S> where I: Input + HasBy
} }
} }
impl<I, S> Mutator<I> for HavocBytesMutator<I, S> where I: Input + HasBytesVec, S: ScheduledMutator<I> { impl<I, S> Mutator<I> for HavocBytesMutator<I, S>
where
I: Input + HasBytesVec,
S: ScheduledMutator<I>,
{
fn mutate(&mut self, input: &mut I, stage_idx: i32) -> Result<(), AflError> { fn mutate(&mut self, input: &mut I, stage_idx: i32) -> Result<(), AflError> {
self.scheduled.mutate(input, stage_idx) self.scheduled.mutate(input, stage_idx)
} }
} }
impl<I, S> HavocBytesMutator<I, S> where I: Input + HasBytesVec, S: ScheduledMutator<I> { impl<I, S> HavocBytesMutator<I, S>
where
I: Input + HasBytesVec,
S: ScheduledMutator<I>,
{
/// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap /// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap
pub fn new(mut scheduled: S) -> Self { pub fn new(mut scheduled: S) -> Self {
scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);
HavocBytesMutator { HavocBytesMutator {
scheduled: scheduled, scheduled: scheduled,
phantom: PhantomData phantom: PhantomData,
} }
} }
} }
impl<'a, I, R, C> HavocBytesMutator<I, DefaultScheduledMutator<'a, I, R, C>> where I: Input + HasBytesVec, R: Rand, C: Corpus<I> { impl<'a, I, R, C> HavocBytesMutator<I, DefaultScheduledMutator<'a, I, R, C>>
where
I: Input + HasBytesVec,
R: Rand,
C: Corpus<I>,
{
/// Create a new HavocBytesMutator instance wrapping DefaultScheduledMutator /// Create a new HavocBytesMutator instance wrapping DefaultScheduledMutator
pub fn new_default(rand: &'a mut R) -> Self { pub fn new_default(rand: &'a mut R) -> Self {
let mut scheduled = DefaultScheduledMutator::<'a, I, R, C>::new(rand); let mut scheduled = DefaultScheduledMutator::<'a, I, R, C>::new(rand);
scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);
HavocBytesMutator { HavocBytesMutator {
scheduled: scheduled, scheduled: scheduled,
phantom: PhantomData phantom: PhantomData,
} }
} }
} }

View File

@ -1,14 +1,14 @@
extern crate num; extern crate num;
use std::slice::from_raw_parts_mut;
use std::any::Any;
use num::Integer; use num::Integer;
use std::any::Any;
use std::slice::from_raw_parts_mut;
use crate::AflError; use crate::AflError;
/// Observers observe different information about the target. /// Observers observe different information about the target.
/// They can then be used by various sorts of feedback. /// They can then be used by various sorts of feedback.
pub trait Observer : Any { pub trait Observer: Any {
fn flush(&mut self) -> Result<(), AflError> { fn flush(&mut self) -> Result<(), AflError> {
Ok(()) Ok(())
} }

View File

@ -1,22 +1,28 @@
pub mod mutational; pub mod mutational;
use crate::corpus::Testcase; use crate::corpus::Testcase;
use crate::inputs::Input;
use crate::engines::Engine; use crate::engines::Engine;
use crate::inputs::Input;
use crate::AflError; use crate::AflError;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
pub trait HasEngine<'a, I> where I: Input { pub trait HasEngine<'a, I>
type E : Engine<'a, I>; where
I: Input,
{
type E: Engine<'a, I>;
fn engine(&self) -> &Self::E; fn engine(&self) -> &Self::E;
fn engine_mut(&mut self) -> &mut Self::E; fn engine_mut(&mut self) -> &mut Self::E;
} }
pub trait Stage<'a, I> : HasEngine<'a, I> where I: Input { pub trait Stage<'a, I>: HasEngine<'a, I>
where
I: Input,
{
/// Run the stage /// Run the stage
fn perform(&mut self, entry: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError>; fn perform(&mut self, entry: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError>;
} }

View File

@ -1,17 +1,20 @@
use crate::AflError;
use crate::mutators::Mutator;
use crate::inputs::Input;
use crate::utils::{Rand, HasRand};
use crate::stages::{Stage, HasEngine};
use crate::corpus::testcase::Testcase; use crate::corpus::testcase::Testcase;
use crate::engines::Engine; use crate::engines::Engine;
use crate::inputs::Input;
use crate::mutators::Mutator;
use crate::stages::{HasEngine, Stage};
use crate::utils::{HasRand, Rand};
use crate::AflError;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
// TODO create HasMutatorsVec trait // TODO create HasMutatorsVec trait
pub trait MutationalStage<'a, I> : Stage<'a, I> + HasRand where I: Input { pub trait MutationalStage<'a, I>: Stage<'a, I> + HasRand
where
I: Input,
{
fn mutators(&self) -> &Vec<Box<dyn Mutator<I, R = Self::R>>>; fn mutators(&self) -> &Vec<Box<dyn Mutator<I, R = Self::R>>>;
fn mutators_mut(&mut self) -> &mut Vec<Box<dyn Mutator<I, R = Self::R>>>; fn mutators_mut(&mut self) -> &mut Vec<Box<dyn Mutator<I, R = Self::R>>>;
@ -41,18 +44,27 @@ pub trait MutationalStage<'a, I> : Stage<'a, I> + HasRand where I: Input {
input = entry.borrow_mut().load_input()?.clone(); input = entry.borrow_mut().load_input()?.clone();
} }
Ok(()) Ok(())
} }
} }
pub struct DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { pub struct DefaultMutationalStage<'a, I, R, E>
where
I: Input,
R: Rand,
E: Engine<'a, I>,
{
rand: &'a mut R, rand: &'a mut R,
engine: &'a mut E, engine: &'a mut E,
mutators: Vec<Box<dyn Mutator<I, R = R>>> mutators: Vec<Box<dyn Mutator<I, R = R>>>,
} }
impl<'a, I, R, E> HasRand for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { impl<'a, I, R, E> HasRand for DefaultMutationalStage<'a, I, R, E>
where
I: Input,
R: Rand,
E: Engine<'a, I>,
{
type R = R; type R = R;
fn rand(&self) -> &Self::R { fn rand(&self) -> &Self::R {
@ -63,7 +75,12 @@ impl<'a, I, R, E> HasRand for DefaultMutationalStage<'a, I, R, E> where I: Input
} }
} }
impl<'a, I, R, E> HasEngine<'a, I> for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { impl<'a, I, R, E> HasEngine<'a, I> for DefaultMutationalStage<'a, I, R, E>
where
I: Input,
R: Rand,
E: Engine<'a, I>,
{
type E = E; type E = E;
fn engine(&self) -> &Self::E { fn engine(&self) -> &Self::E {
@ -75,7 +92,12 @@ impl<'a, I, R, E> HasEngine<'a, I> for DefaultMutationalStage<'a, I, R, E> where
} }
} }
impl<'a, I, R, E> MutationalStage<'a, I> for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { impl<'a, I, R, E> MutationalStage<'a, I> for DefaultMutationalStage<'a, I, R, E>
where
I: Input,
R: Rand,
E: Engine<'a, I>,
{
fn mutators(&self) -> &Vec<Box<dyn Mutator<I, R = Self::R>>> { fn mutators(&self) -> &Vec<Box<dyn Mutator<I, R = Self::R>>> {
&self.mutators &self.mutators
} }
@ -85,18 +107,28 @@ impl<'a, I, R, E> MutationalStage<'a, I> for DefaultMutationalStage<'a, I, R, E>
} }
} }
impl<'a, I, R, E> Stage<'a, I> for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { impl<'a, I, R, E> Stage<'a, I> for DefaultMutationalStage<'a, I, R, E>
where
I: Input,
R: Rand,
E: Engine<'a, I>,
{
fn perform(&mut self, entry: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError> { fn perform(&mut self, entry: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError> {
self.perform_mutational(entry) self.perform_mutational(entry)
} }
} }
impl<'a, I, R, E> DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { impl<'a, I, R, E> DefaultMutationalStage<'a, I, R, E>
where
I: Input,
R: Rand,
E: Engine<'a, I>,
{
pub fn new(rand: &'a mut R, engine: &'a mut E) -> Self { pub fn new(rand: &'a mut R, engine: &'a mut E) -> Self {
DefaultMutationalStage { DefaultMutationalStage {
rand: rand, rand: rand,
engine: engine, engine: engine,
mutators: vec![] mutators: vec![],
} }
} }
} }

View File

@ -41,7 +41,7 @@ pub trait Rand: Debug {
/// Has a Rand box field /// Has a Rand box field
pub trait HasRand { pub trait HasRand {
type R : Rand; type R: Rand;
/// Get the hold Rand instance /// Get the hold Rand instance
fn rand(&self) -> &Self::R; fn rand(&self) -> &Self::R;