From f1565246f515923cab14e2b62fa551c7f0e77c38 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 9 Nov 2020 12:41:52 +0100 Subject: [PATCH] has target bytes, corpus, comments --- src/corpus/mod.rs | 40 ++++++++++++++++++++++------------------ src/corpus/testcase.rs | 10 ++++++++-- src/engines/mod.rs | 11 +++++++---- src/inputs/bytes.rs | 15 +++++++++------ src/inputs/mod.rs | 25 ++++++++++++++++++++++++- src/lib.rs | 4 ++++ src/stages/mod.rs | 2 +- src/stages/mutational.rs | 4 ++-- src/utils.rs | 3 ++- 9 files changed, 79 insertions(+), 35 deletions(-) diff --git a/src/corpus/mod.rs b/src/corpus/mod.rs index 9a1b18681a..ab27c6b63e 100644 --- a/src/corpus/mod.rs +++ b/src/corpus/mod.rs @@ -56,14 +56,19 @@ where } /// Gets a random entry - fn random_entry(&mut self) -> Result>>, AflError> { - let len = { self.entries().len() }; - let id = self.rand_below(len as u64) as usize; - Ok(self.entries()[id].clone()) + fn random_entry(&self) -> Result>>, AflError> { + if self.count() == 0 { + Err(AflError::Empty("No entries in corpus".to_owned())) + } else { + let len = { self.entries().len() }; + let id = self.rand_below(len as u64) as usize; + Ok(self.entries()[id].clone()) + } } - /// Gets the next entry (random by default) - fn get(&mut self) -> Result>>, AflError> { + // TODO: IntoIter + /// Gets the next entry + fn next(&mut self) -> Result>>, AflError> { self.random_entry() } } @@ -248,21 +253,22 @@ where } /// Gets a random entry - fn random_entry(&mut self) -> Result>>, AflError> { + fn random_entry(&self) -> Result>>, AflError> { self.corpus.random_entry() } /// Gets the next entry - fn get(&mut self) -> Result>>, AflError> { + fn next(&mut self) -> Result>>, AflError> { + self.pos += 1; 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() { - self.cycles = self.cycles + 1; - self.pos = 0; + if self.pos > self.corpus.count() { + // TODO: Always loop or return informational error? + self.pos = 1; + 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::utils::Xoshiro256StarRand; - use std::cell::RefCell; use std::path::PathBuf; - use std::rc::Rc; #[test] @@ -310,7 +314,7 @@ mod tests { let t = Testcase::with_filename_rr(i, PathBuf::from("fancyfile")); q.add(t); let filename = q - .get() + .next() .unwrap() .borrow() .filename() @@ -319,7 +323,7 @@ mod tests { .to_owned(); assert_eq!( filename, - q.get() + q.next() .unwrap() .borrow() .filename() diff --git a/src/corpus/testcase.rs b/src/corpus/testcase.rs index 9ba2dce787..1e03ae9670 100644 --- a/src/corpus/testcase.rs +++ b/src/corpus/testcase.rs @@ -6,22 +6,28 @@ use std::cell::RefCell; use std::path::PathBuf; use std::rc::Rc; +// TODO: Give example +/// Metadata for a testcase pub trait TestcaseMetadata { + /// The name of this metadata - used to find it in the list of avaliable metadatas fn name(&self) -> &'static str; } +/// An entry in the Testcase Corpus #[derive(Default)] pub struct Testcase where I: Input, { + /// The input of this testcase input: Option, // TODO remove box + /// Filename, if this testcase is backed by a file in the filesystem filename: Option, + /// Map of metadatas associated with this testcase metadatas: HashMap<&'static str, Box>, } -pub type TestcaseRef = Rc>>; - +/// Impl of a testcase impl Testcase where I: Input, diff --git a/src/engines/mod.rs b/src/engines/mod.rs index 8453a43d37..58b3dc483e 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -51,9 +51,12 @@ where fn executor_mut(&mut self) -> &mut E; 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() { - stage.perform(entry.clone())?; + stage.perform(&entry)?; } Ok(()) } @@ -203,7 +206,7 @@ mod tests { let mut stage = DefaultMutationalStage::new(&rand, &engine); //engine.borrow_mut().add_stage(stage); //engine.borrow_mut().fuzz_one().unwrap(); - let t = { engine.borrow_mut().corpus_mut().get().unwrap() }; - stage.perform(t).unwrap(); + let t = { engine.borrow_mut().corpus_mut().next().unwrap() }; + stage.perform(&t).unwrap(); } } diff --git a/src/inputs/bytes.rs b/src/inputs/bytes.rs index 7353697dc2..d8a36d1f6c 100644 --- a/src/inputs/bytes.rs +++ b/src/inputs/bytes.rs @@ -1,11 +1,7 @@ -use crate::inputs::Input; +use crate::inputs::{HasBytesVec, HasTargetBytes, Input}; use crate::AflError; -pub trait HasBytesVec { - fn bytes(&self) -> &Vec; - fn bytes_mut(&mut self) -> &mut Vec; -} - +/// A bytes input is the basic input #[derive(Clone, Debug, Default)] pub struct BytesInput { pub bytes: Vec, @@ -31,7 +27,14 @@ impl HasBytesVec for BytesInput { } } +impl HasTargetBytes for BytesInput { + fn target_bytes(&self) -> &Vec { + &self.bytes + } +} + impl BytesInput { + /// Creates a new bytes input using the given bytes pub fn new(bytes: Vec) -> Self { BytesInput { bytes: bytes } } diff --git a/src/inputs/mod.rs b/src/inputs/mod.rs index 86451437da..ecedbe9e3d 100644 --- a/src/inputs/mod.rs +++ b/src/inputs/mod.rs @@ -1,5 +1,5 @@ pub mod bytes; -pub use bytes::{BytesInput, HasBytesVec}; +pub use bytes::BytesInput; use std::clone::Clone; use std::fs::File; @@ -9,13 +9,16 @@ use std::path::PathBuf; use crate::AflError; +/// An input for the target pub trait Input: Clone { + /// Write this input to the file fn to_file(&self, path: &PathBuf) -> Result<(), AflError> { let mut file = File::create(path)?; file.write_all(self.serialize()?)?; Ok(()) } + /// Load the contents of this input from a file fn from_file(&mut self, path: &PathBuf) -> Result<(), AflError> { let mut file = File::create(path)?; let mut buf = vec![]; @@ -24,7 +27,27 @@ pub trait Input: Clone { 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>; + /// Deserialize this input, using the bytes serialized before. 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; +} + +/// Contains an internal bytes Vector +pub trait HasBytesVec { + /// The internal bytes map + fn bytes(&self) -> &Vec; + /// The internal bytes map (as mutable borrow) + fn bytes_mut(&mut self) -> &mut Vec; +} diff --git a/src/lib.rs b/src/lib.rs index 8f9aaeb5a2..12cf09cda8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,10 +18,14 @@ pub enum AflError { Serialize(String), #[error("File IO failed")] File(#[from] io::Error), + #[error("Optional value `{0}` was not set")] + EmptyOptional(String), #[error("Key `{0}` not in Corpus")] KeyNotFound(String), #[error("No items in {0}")] Empty(String), + #[error("All elements have been processed in {0} iterator")] + IteratorEnd(String), #[error("Not implemented: {0}")] NotImplemented(String), #[error("Unknown error: {0}")] diff --git a/src/stages/mod.rs b/src/stages/mod.rs index 43676df6d2..3ec48bcd23 100644 --- a/src/stages/mod.rs +++ b/src/stages/mod.rs @@ -22,5 +22,5 @@ where I: Input, { /// Run the stage - fn perform(&mut self, entry: Rc>>) -> Result<(), AflError>; + fn perform(&mut self, entry: &Rc>>) -> Result<(), AflError>; } diff --git a/src/stages/mutational.rs b/src/stages/mutational.rs index ac10b014b3..3d33c539dd 100644 --- a/src/stages/mutational.rs +++ b/src/stages/mutational.rs @@ -27,7 +27,7 @@ where 1 + self.rand_below(128) as usize } - fn perform_mutational(&mut self, entry: Rc>>) -> Result<(), AflError> { + fn perform_mutational(&mut self, entry: &Rc>>) -> Result<(), AflError> { let num = self.iterations(); let mut input = entry.borrow_mut().load_input()?.clone(); @@ -109,7 +109,7 @@ where R: Rand, E: Evaluator, { - fn perform(&mut self, entry: Rc>>) -> Result<(), AflError> { + fn perform(&mut self, entry: &Rc>>) -> Result<(), AflError> { self.perform_mutational(entry) } } diff --git a/src/utils.rs b/src/utils.rs index dcfc1891a6..29da8acb96 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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 { type R: Rand; @@ -162,6 +162,7 @@ mod tests { } } + #[test] fn test_has_rand() { let rand = Xoshiro256StarRand::new_rr(); let has_rand = HasRandTest {