generate initial inputs
This commit is contained in:
parent
a3501cfb43
commit
0a22db2db9
@ -24,119 +24,6 @@ pub trait TestcaseMetadata {
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
pub trait TestcaseTraitTODO<I, T>
|
||||
where
|
||||
I: Input,
|
||||
T: TestcaseMetadata,
|
||||
{
|
||||
/// The input associated with this testcase
|
||||
fn input(&self) -> &Option<I>;
|
||||
|
||||
/// The input associated with this testcase (mutable)
|
||||
fn input_mut(&mut self) -> &mut Option<I>;
|
||||
|
||||
/// Filename, if this testcase is backed by a file in the filesystem
|
||||
fn filename(&self) -> &Option<String>;
|
||||
|
||||
/// Map of metadatas associated with this testcase
|
||||
fn metadatas(&self) -> &HashMap<&'static str, Box<dyn TestcaseMetadata>>;
|
||||
|
||||
/// Map of metadatas associated with this testcase
|
||||
fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box<dyn TestcaseMetadata>>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub enum FileBackedTestcase<I, P> {
|
||||
/// A testcase on disk, not yet loaded
|
||||
Stored { filename: P },
|
||||
|
||||
/// A testcase that has been loaded, and not yet dirtied.
|
||||
/// The input should be equal to the on-disk state.
|
||||
Loaded {
|
||||
input: I,
|
||||
filename: P,
|
||||
//metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>,
|
||||
},
|
||||
|
||||
/// A testcase that has been mutated, but not yet written to disk
|
||||
Dirty {
|
||||
input: I,
|
||||
filename: P,
|
||||
//metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<I, P> FileBackedTestcase<I, P>
|
||||
where
|
||||
I: Input,
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
/// Load a testcase from disk if it is not already loaded.
|
||||
///
|
||||
/// # Errors
|
||||
/// Errors if the testcase is [Dirty](FileBackedTestcase::Dirty)
|
||||
pub fn load(self) -> Result<Self, AflError> {
|
||||
match self {
|
||||
Self::Stored { filename } => {
|
||||
let input = I::from_file(&filename)?;
|
||||
Ok(Self::Loaded { filename, input })
|
||||
}
|
||||
Self::Loaded {
|
||||
input: _,
|
||||
filename: _,
|
||||
} => Ok(self),
|
||||
_ => Err(AflError::IllegalState(
|
||||
"Attempted load on dirty testcase".into(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure that the in-memory state is syncd to disk, and load it from disk if
|
||||
/// Nece
|
||||
pub fn refresh(self) -> Result<Self, AflError> {
|
||||
match self {
|
||||
Self::Dirty {
|
||||
input: _,
|
||||
filename: _,
|
||||
} => self.save(),
|
||||
other => other.load(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes changes to disk
|
||||
pub fn save(self) -> Result<Self, AflError> {
|
||||
match self {
|
||||
Self::Loaded {
|
||||
input: _,
|
||||
filename: _,
|
||||
} => Ok(self),
|
||||
Self::Dirty { input, filename } => {
|
||||
let mut file = File::create(&filename)?;
|
||||
file.write_all(input.serialize()?)?;
|
||||
|
||||
Ok(Self::Loaded { input, filename })
|
||||
}
|
||||
Self::Stored { filename } => Err(AflError::IllegalState(format!(
|
||||
"Tried to store to {:?} without input (in stored state)",
|
||||
filename.as_ref()
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
// Removes contents of this testcase from memory
|
||||
pub fn unload(self) -> Result<Self, AflError> {
|
||||
match self {
|
||||
Self::Loaded { input: _, filename } => Ok(Self::Stored { filename }),
|
||||
Self::Stored { filename: _ } => Ok(self),
|
||||
Self::Dirty {
|
||||
filename: _,
|
||||
input: _,
|
||||
} => self.save(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry in the Testcase Corpus
|
||||
#[derive(Default)]
|
||||
pub struct Testcase<I>
|
||||
@ -147,6 +34,8 @@ where
|
||||
input: Option<I>,
|
||||
/// Filename, if this testcase is backed by a file in the filesystem
|
||||
filename: Option<String>,
|
||||
/// Accumulated fitness from all the feedbacks
|
||||
fitness: u32,
|
||||
/// Map of metadatas associated with this testcase
|
||||
metadatas: HashMap<&'static str, Box<dyn TestcaseMetadata>>,
|
||||
}
|
||||
@ -186,22 +75,41 @@ where
|
||||
pub fn input_mut(&mut self) -> &mut Option<I> {
|
||||
&mut self.input
|
||||
}
|
||||
/// Set the input
|
||||
pub fn set_input(&mut self, input: I) {
|
||||
self.input = Some(input);
|
||||
}
|
||||
|
||||
/// Get the filename, if any
|
||||
pub fn filename(&self) -> &Option<String> {
|
||||
&self.filename
|
||||
}
|
||||
|
||||
/// Get the filename, if any (mutable)
|
||||
pub fn filename_mut(&mut self) -> &mut Option<String> {
|
||||
&mut self.filename
|
||||
}
|
||||
/// Set the filename
|
||||
pub fn set_filename(&mut self, filename: String) {
|
||||
self.filename = Some(filename);
|
||||
}
|
||||
|
||||
/// Get the fitness
|
||||
pub fn fitness(&self) -> u32 {
|
||||
self.fitness
|
||||
}
|
||||
/// Get the fitness (mutable)
|
||||
pub fn fitness_mut(&mut self) -> &mut u32 {
|
||||
&mut self.fitness
|
||||
}
|
||||
/// Set the fitness
|
||||
pub fn set_fitness(&mut self, fitness: u32) {
|
||||
self.fitness = fitness;
|
||||
}
|
||||
|
||||
/// Get all the metadatas into an HashMap (mutable)
|
||||
pub fn metadatas(&mut self) -> &mut HashMap<&'static str, Box<dyn TestcaseMetadata>> {
|
||||
&mut self.metadatas
|
||||
}
|
||||
|
||||
/// Add a metadata
|
||||
pub fn add_metadata(&mut self, meta: Box<dyn TestcaseMetadata>) {
|
||||
self.metadatas.insert(meta.name(), meta);
|
||||
@ -215,6 +123,7 @@ where
|
||||
Testcase {
|
||||
input: Some(input.into()),
|
||||
filename: None,
|
||||
fitness: 0,
|
||||
metadatas: HashMap::default(),
|
||||
}
|
||||
}
|
||||
@ -224,6 +133,7 @@ where
|
||||
Testcase {
|
||||
input: Some(input),
|
||||
filename: Some(filename),
|
||||
fitness: 0,
|
||||
metadatas: HashMap::default(),
|
||||
}
|
||||
}
|
||||
@ -232,6 +142,7 @@ where
|
||||
Testcase {
|
||||
input: None,
|
||||
filename: None,
|
||||
fitness: 0,
|
||||
metadatas: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ use crate::corpus::{Corpus, HasCorpus, Testcase};
|
||||
use crate::events::EventManager;
|
||||
use crate::executors::Executor;
|
||||
use crate::feedbacks::Feedback;
|
||||
use crate::generators::Generator;
|
||||
use crate::inputs::Input;
|
||||
use crate::observers::Observer;
|
||||
use crate::stages::Stage;
|
||||
@ -95,30 +96,68 @@ where
|
||||
fn executor_mut(&mut self) -> &mut E;
|
||||
|
||||
/// Runs the input and triggers observers and feedback
|
||||
fn evaluate_input(&mut self, input: &I) -> Result<bool, AflError> {
|
||||
fn evaluate_input(
|
||||
&mut self,
|
||||
input: I,
|
||||
) -> Result<(bool, Option<Rc<RefCell<Testcase<I>>>>), AflError> {
|
||||
self.reset_observers()?;
|
||||
self.executor_mut().run_target(input)?;
|
||||
self.executor_mut().run_target(&input)?;
|
||||
self.set_executions(self.executions() + 1);
|
||||
self.post_exec_observers()?;
|
||||
|
||||
let mut rate_acc = 0;
|
||||
let mut fitness = 0;
|
||||
for feedback in self.feedbacks_mut() {
|
||||
rate_acc += feedback.is_interesting(input)?;
|
||||
fitness += feedback.is_interesting(&input)?;
|
||||
}
|
||||
|
||||
if rate_acc >= 25 {
|
||||
let testcase = Rc::new(RefCell::new(Testcase::new(input.clone())));
|
||||
if fitness >= 25 {
|
||||
let testcase: Rc<RefCell<_>> = Testcase::new(input).into();
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.append_metadata(testcase.clone())?;
|
||||
}
|
||||
Ok(true)
|
||||
testcase.borrow_mut().set_fitness(fitness);
|
||||
self.corpus_mut().add(testcase.clone());
|
||||
Ok((true, Some(testcase)))
|
||||
} else {
|
||||
for feedback in self.feedbacks_mut() {
|
||||
feedback.discard_metadata()?;
|
||||
}
|
||||
Ok(false)
|
||||
Ok((false, None))
|
||||
}
|
||||
}
|
||||
|
||||
fn load_initial_input(&mut self, input: I) -> Result<(), AflError> {
|
||||
// Inefficent clone, but who cares this is done once at init
|
||||
let (_, testcase) = self.evaluate_input(input.clone())?;
|
||||
if testcase.is_none() {
|
||||
let testcase = Testcase::new(input).into();
|
||||
self.corpus_mut().add(testcase);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_initial_inputs<S, G, C, E, I, R, EM>(
|
||||
rand: &mut R,
|
||||
state: &mut S,
|
||||
generator: &mut G,
|
||||
_events: &mut EM,
|
||||
num: usize,
|
||||
) -> Result<(), AflError>
|
||||
where
|
||||
S: State<C, E, I, R>,
|
||||
G: Generator<I, R>,
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
EM: EventManager,
|
||||
{
|
||||
for _ in 0..num {
|
||||
let input = generator.generate(rand)?;
|
||||
state.load_initial_input(input)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct StdState<C, E, I, R>
|
||||
@ -247,12 +286,17 @@ where
|
||||
events: &mut EM,
|
||||
) -> Result<usize, AflError> {
|
||||
let (testcase, idx) = state.corpus_mut().next(rand)?;
|
||||
println!("Cur entry: {}\tExecutions: {}", idx, state.executions());
|
||||
for stage in self.stages_mut() {
|
||||
stage.perform(rand, state, events, testcase.clone())?;
|
||||
}
|
||||
Ok(idx)
|
||||
}
|
||||
|
||||
fn fuzz_loop(&mut self, rand: &mut R, state: &mut S, events: &mut EM) -> Result<(), AflError> {
|
||||
loop {
|
||||
self.fuzz_one(rand, state, events)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StdEngine<S, EM, E, C, I, R>
|
||||
|
@ -5,10 +5,14 @@ pub use scheduled::ScheduledMutator;
|
||||
pub use scheduled::StdScheduledMutator;
|
||||
|
||||
use crate::corpus::Corpus;
|
||||
use crate::corpus::Testcase;
|
||||
use crate::inputs::Input;
|
||||
use crate::utils::Rand;
|
||||
use crate::AflError;
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
pub trait Mutator<C, I, R>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
@ -25,7 +29,12 @@ where
|
||||
) -> Result<(), AflError>;
|
||||
|
||||
/// Post-process given the outcome of the execution
|
||||
fn post_exec(&mut self, _is_interesting: bool, _stage_idx: i32) -> Result<(), AflError> {
|
||||
fn post_exec(
|
||||
&mut self,
|
||||
_is_interesting: bool,
|
||||
_new_testcase: Option<Rc<RefCell<Testcase<I>>>>,
|
||||
_stage_idx: i32,
|
||||
) -> Result<(), AflError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ where
|
||||
|
||||
/// Bitflip mutation for inputs with a bytes vector
|
||||
pub fn mutation_bitflip<M, C, I, R>(
|
||||
mutator: &mut M,
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
_corpus: &mut C,
|
||||
input: &mut I,
|
||||
@ -190,7 +190,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
||||
|
||||
/// Splicing mutator
|
||||
pub fn mutation_splice<M, C, I, R>(
|
||||
mutator: &mut M,
|
||||
_mutator: &mut M,
|
||||
rand: &mut R,
|
||||
corpus: &mut C,
|
||||
input: &mut I,
|
||||
|
@ -46,20 +46,15 @@ where
|
||||
testcase: Rc<RefCell<Testcase<I>>>,
|
||||
) -> Result<(), AflError> {
|
||||
let num = self.iterations(rand);
|
||||
let input = testcase.borrow_mut().load_input()?.clone();
|
||||
|
||||
for i in 0..num {
|
||||
let mut input_tmp = input.clone();
|
||||
let mut input = testcase.borrow_mut().load_input()?.clone();
|
||||
self.mutator_mut()
|
||||
.mutate(rand, state.corpus_mut(), &mut input_tmp, i as i32)?;
|
||||
.mutate(rand, state.corpus_mut(), &mut input, i as i32)?;
|
||||
|
||||
let interesting = state.evaluate_input(&input_tmp)?;
|
||||
let (interesting, new_testcase) = state.evaluate_input(input)?;
|
||||
|
||||
self.mutator_mut().post_exec(interesting, i as i32)?;
|
||||
|
||||
if interesting {
|
||||
state.corpus_mut().add(Testcase::new(input_tmp).into());
|
||||
}
|
||||
self.mutator_mut()
|
||||
.post_exec(interesting, new_testcase, i as i32)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -8,11 +8,12 @@ use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
|
||||
use afl::corpus::{Corpus, InMemoryCorpus, Testcase};
|
||||
use afl::engines::{Engine, State, StdEngine, StdState};
|
||||
use afl::engines::{generate_initial_inputs, Engine, State, StdEngine, StdState};
|
||||
use afl::events::LoggerEventManager;
|
||||
use afl::executors::inmemory::InMemoryExecutor;
|
||||
use afl::executors::{Executor, ExitKind};
|
||||
use afl::feedbacks::{create_history_map, MaxMapFeedback};
|
||||
use afl::generators::{Generator, RandPrintablesGenerator};
|
||||
use afl::inputs::bytes::BytesInput;
|
||||
use afl::mutators::scheduled::HavocBytesMutator;
|
||||
use afl::observers::StdMapObserver;
|
||||
@ -42,9 +43,9 @@ fn harness<I>(_executor: &dyn Executor<I>, buf: &[u8]) -> ExitKind {
|
||||
pub extern "C" fn afl_libfuzzer_main() {
|
||||
let mut rand = StdRand::new(0);
|
||||
|
||||
let mut corpus = InMemoryCorpus::new();
|
||||
let testcase = Testcase::new(vec![0; 4]).into();
|
||||
corpus.add(testcase);
|
||||
let corpus = InMemoryCorpus::new();
|
||||
let mut generator = RandPrintablesGenerator::new(4096);
|
||||
let mut events = LoggerEventManager::new();
|
||||
|
||||
let edges_observer = Rc::new(RefCell::new(StdMapObserver::new_from_ptr(
|
||||
unsafe { __lafl_edges_map },
|
||||
@ -53,23 +54,22 @@ pub extern "C" fn afl_libfuzzer_main() {
|
||||
let edges_history_map = create_history_map::<u8>(MAP_SIZE);
|
||||
let edges_feedback = MaxMapFeedback::new(edges_observer.clone(), edges_history_map);
|
||||
|
||||
let executor = InMemoryExecutor::<BytesInput>::new(harness);
|
||||
let executor = InMemoryExecutor::new(harness);
|
||||
let mut state = StdState::new(corpus, executor);
|
||||
state.add_observer(edges_observer);
|
||||
state.add_feedback(Box::new(edges_feedback));
|
||||
|
||||
generate_initial_inputs(&mut rand, &mut state, &mut generator, &mut events, 4)
|
||||
.expect("Failed to load initial inputs");
|
||||
|
||||
let mut engine = StdEngine::new();
|
||||
let mutator = HavocBytesMutator::new_default();
|
||||
let stage = StdMutationalStage::new(mutator);
|
||||
engine.add_stage(Box::new(stage));
|
||||
|
||||
let mut events = LoggerEventManager::new();
|
||||
|
||||
for i in 0..1000 {
|
||||
engine
|
||||
.fuzz_one(&mut rand, &mut state, &mut events)
|
||||
.expect(&format!("Error in iter {}", i));
|
||||
}
|
||||
.fuzz_loop(&mut rand, &mut state, &mut events)
|
||||
.expect("Fuzzer fatal error");
|
||||
#[cfg(feature = "std")]
|
||||
println!("OK");
|
||||
}
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
int target_func(const uint8_t *buf, size_t size) {
|
||||
|
||||
printf("BUF (%ld): ", size);
|
||||
/*printf("BUF (%ld): ", size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
printf("%02X", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("\n");*/
|
||||
|
||||
switch (buf[0]) {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user