import dominik map feedback
This commit is contained in:
parent
b2a6ddb0dd
commit
63a83a70ff
@ -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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
@ -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 {}
|
||||||
|
@ -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>;
|
||||||
|
|
||||||
|
@ -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>>;
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()?)?;
|
||||||
|
@ -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 {
|
||||||
|
@ -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>;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
@ -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![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user