has target bytes, corpus, comments
This commit is contained in:
parent
9c0bcf19f9
commit
f1565246f5
@ -56,14 +56,19 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random entry
|
/// Gets a random entry
|
||||||
fn random_entry(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
fn random_entry(&self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
||||||
|
if self.count() == 0 {
|
||||||
|
Err(AflError::Empty("No entries in corpus".to_owned()))
|
||||||
|
} else {
|
||||||
let len = { self.entries().len() };
|
let len = { self.entries().len() };
|
||||||
let id = self.rand_below(len as u64) as usize;
|
let id = self.rand_below(len as u64) as usize;
|
||||||
Ok(self.entries()[id].clone())
|
Ok(self.entries()[id].clone())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the next entry (random by default)
|
// TODO: IntoIter
|
||||||
fn get(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
/// Gets the next entry
|
||||||
|
fn next(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
||||||
self.random_entry()
|
self.random_entry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,21 +253,22 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random entry
|
/// Gets a random entry
|
||||||
fn random_entry(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
fn random_entry(&self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
||||||
self.corpus.random_entry()
|
self.corpus.random_entry()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
fn get(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
fn next(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> {
|
||||||
|
self.pos += 1;
|
||||||
if self.corpus.count() == 0 {
|
if self.corpus.count() == 0 {
|
||||||
return Err(AflError::Empty("Testcases".to_string()));
|
return Err(AflError::Empty("Corpus".to_owned()));
|
||||||
}
|
}
|
||||||
self.pos = self.pos + 1;
|
if self.pos > self.corpus.count() {
|
||||||
if self.pos >= self.corpus.count() {
|
// TODO: Always loop or return informational error?
|
||||||
self.cycles = self.cycles + 1;
|
self.pos = 1;
|
||||||
self.pos = 0;
|
self.cycles += 1;
|
||||||
}
|
}
|
||||||
Ok(self.corpus.entries()[self.pos].clone())
|
Ok(self.corpus.entries()[self.pos - 1].clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,9 +303,7 @@ mod tests {
|
|||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
use crate::utils::Xoshiro256StarRand;
|
use crate::utils::Xoshiro256StarRand;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
||||||
@ -310,7 +314,7 @@ mod tests {
|
|||||||
let t = Testcase::with_filename_rr(i, PathBuf::from("fancyfile"));
|
let t = Testcase::with_filename_rr(i, PathBuf::from("fancyfile"));
|
||||||
q.add(t);
|
q.add(t);
|
||||||
let filename = q
|
let filename = q
|
||||||
.get()
|
.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow()
|
.borrow()
|
||||||
.filename()
|
.filename()
|
||||||
@ -319,7 +323,7 @@ mod tests {
|
|||||||
.to_owned();
|
.to_owned();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
filename,
|
filename,
|
||||||
q.get()
|
q.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow()
|
.borrow()
|
||||||
.filename()
|
.filename()
|
||||||
|
@ -6,22 +6,28 @@ use std::cell::RefCell;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
// TODO: Give example
|
||||||
|
/// Metadata for a testcase
|
||||||
pub trait TestcaseMetadata {
|
pub trait TestcaseMetadata {
|
||||||
|
/// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An entry in the Testcase Corpus
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Testcase<I>
|
pub struct Testcase<I>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
|
/// The input of this testcase
|
||||||
input: Option<I>, // TODO remove box
|
input: Option<I>, // TODO remove box
|
||||||
|
/// Filename, if this testcase is backed by a file in the filesystem
|
||||||
filename: Option<PathBuf>,
|
filename: Option<PathBuf>,
|
||||||
|
/// Map of metadatas associated with this testcase
|
||||||
metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>,
|
metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TestcaseRef<I> = Rc<RefCell<Testcase<I>>>;
|
/// Impl of a testcase
|
||||||
|
|
||||||
impl<I> Testcase<I>
|
impl<I> Testcase<I>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
|
@ -51,9 +51,12 @@ where
|
|||||||
fn executor_mut(&mut self) -> &mut E;
|
fn executor_mut(&mut self) -> &mut E;
|
||||||
|
|
||||||
fn fuzz_one(&mut self) -> Result<(), AflError> {
|
fn fuzz_one(&mut self) -> Result<(), AflError> {
|
||||||
let entry = self.corpus_mut().get()?;
|
if self.corpus().count() == 0 {
|
||||||
|
return Err(AflError::Empty("No testcases in corpus".to_owned()));
|
||||||
|
}
|
||||||
|
let entry = self.corpus_mut().next()?;
|
||||||
for stage in self.stages_mut() {
|
for stage in self.stages_mut() {
|
||||||
stage.perform(entry.clone())?;
|
stage.perform(&entry)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -203,7 +206,7 @@ mod tests {
|
|||||||
let mut stage = DefaultMutationalStage::new(&rand, &engine);
|
let mut stage = DefaultMutationalStage::new(&rand, &engine);
|
||||||
//engine.borrow_mut().add_stage(stage);
|
//engine.borrow_mut().add_stage(stage);
|
||||||
//engine.borrow_mut().fuzz_one().unwrap();
|
//engine.borrow_mut().fuzz_one().unwrap();
|
||||||
let t = { engine.borrow_mut().corpus_mut().get().unwrap() };
|
let t = { engine.borrow_mut().corpus_mut().next().unwrap() };
|
||||||
stage.perform(t).unwrap();
|
stage.perform(&t).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
use crate::inputs::Input;
|
use crate::inputs::{HasBytesVec, HasTargetBytes, Input};
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
pub trait HasBytesVec {
|
/// A bytes input is the basic input
|
||||||
fn bytes(&self) -> &Vec<u8>;
|
|
||||||
fn bytes_mut(&mut self) -> &mut Vec<u8>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct BytesInput {
|
pub struct BytesInput {
|
||||||
pub bytes: Vec<u8>,
|
pub bytes: Vec<u8>,
|
||||||
@ -31,7 +27,14 @@ impl HasBytesVec for BytesInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasTargetBytes for BytesInput {
|
||||||
|
fn target_bytes(&self) -> &Vec<u8> {
|
||||||
|
&self.bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BytesInput {
|
impl BytesInput {
|
||||||
|
/// Creates a new bytes input using the given bytes
|
||||||
pub fn new(bytes: Vec<u8>) -> Self {
|
pub fn new(bytes: Vec<u8>) -> Self {
|
||||||
BytesInput { bytes: bytes }
|
BytesInput { bytes: bytes }
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
pub mod bytes;
|
pub mod bytes;
|
||||||
pub use bytes::{BytesInput, HasBytesVec};
|
pub use bytes::BytesInput;
|
||||||
|
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -9,13 +9,16 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
|
/// An input for the target
|
||||||
pub trait Input: Clone {
|
pub trait Input: Clone {
|
||||||
|
/// Write this input to the file
|
||||||
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()?)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load the contents of this input from a file
|
||||||
fn from_file(&mut self, path: &PathBuf) -> Result<(), AflError> {
|
fn from_file(&mut self, path: &PathBuf) -> Result<(), AflError> {
|
||||||
let mut file = File::create(path)?;
|
let mut file = File::create(path)?;
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
@ -24,7 +27,27 @@ pub trait Input: Clone {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize this input, for later deserialization.
|
||||||
|
/// This is not necessarily the representation to be used by the target
|
||||||
|
/// Instead, to get bytes for a target, use [HasTargetBytes](afl::inputs::HasTargetBytes).
|
||||||
fn serialize(&self) -> Result<&[u8], AflError>;
|
fn serialize(&self) -> Result<&[u8], AflError>;
|
||||||
|
|
||||||
|
/// Deserialize this input, using the bytes serialized before.
|
||||||
fn deserialize(&mut self, buf: &[u8]) -> Result<(), AflError>;
|
fn deserialize(&mut self, buf: &[u8]) -> Result<(), AflError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Can be serialized to a bytes representation
|
||||||
|
/// This representation is not necessarily deserializable
|
||||||
|
/// Instead, it can be used as bytes input for a target
|
||||||
|
pub trait HasTargetBytes {
|
||||||
|
/// Target bytes, that can be written to a target
|
||||||
|
fn target_bytes(&self) -> &Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains an internal bytes Vector
|
||||||
|
pub trait HasBytesVec {
|
||||||
|
/// The internal bytes map
|
||||||
|
fn bytes(&self) -> &Vec<u8>;
|
||||||
|
/// The internal bytes map (as mutable borrow)
|
||||||
|
fn bytes_mut(&mut self) -> &mut Vec<u8>;
|
||||||
|
}
|
||||||
|
@ -18,10 +18,14 @@ pub enum AflError {
|
|||||||
Serialize(String),
|
Serialize(String),
|
||||||
#[error("File IO failed")]
|
#[error("File IO failed")]
|
||||||
File(#[from] io::Error),
|
File(#[from] io::Error),
|
||||||
|
#[error("Optional value `{0}` was not set")]
|
||||||
|
EmptyOptional(String),
|
||||||
#[error("Key `{0}` not in Corpus")]
|
#[error("Key `{0}` not in Corpus")]
|
||||||
KeyNotFound(String),
|
KeyNotFound(String),
|
||||||
#[error("No items in {0}")]
|
#[error("No items in {0}")]
|
||||||
Empty(String),
|
Empty(String),
|
||||||
|
#[error("All elements have been processed in {0} iterator")]
|
||||||
|
IteratorEnd(String),
|
||||||
#[error("Not implemented: {0}")]
|
#[error("Not implemented: {0}")]
|
||||||
NotImplemented(String),
|
NotImplemented(String),
|
||||||
#[error("Unknown error: {0}")]
|
#[error("Unknown error: {0}")]
|
||||||
|
@ -22,5 +22,5 @@ where
|
|||||||
I: Input,
|
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>;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ where
|
|||||||
1 + self.rand_below(128) as usize
|
1 + self.rand_below(128) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_mutational(&mut self, entry: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError> {
|
fn perform_mutational(&mut self, entry: &Rc<RefCell<Testcase<I>>>) -> Result<(), AflError> {
|
||||||
let num = self.iterations();
|
let num = self.iterations();
|
||||||
let mut input = entry.borrow_mut().load_input()?.clone();
|
let mut input = entry.borrow_mut().load_input()?.clone();
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ where
|
|||||||
R: Rand,
|
R: Rand,
|
||||||
E: Evaluator<I>,
|
E: Evaluator<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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ pub trait Rand: Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Has a Rand Rc RefCell field
|
/// Has a Rand Rc RefCell field (internal mutability), that can be used to get random values
|
||||||
pub trait HasRand {
|
pub trait HasRand {
|
||||||
type R: Rand;
|
type R: Rand;
|
||||||
|
|
||||||
@ -162,6 +162,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
fn test_has_rand() {
|
fn test_has_rand() {
|
||||||
let rand = Xoshiro256StarRand::new_rr();
|
let rand = Xoshiro256StarRand::new_rr();
|
||||||
let has_rand = HasRandTest {
|
let has_rand = HasRandTest {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user