fix splicing

This commit is contained in:
Andrea Fioraldi 2020-11-21 11:30:13 +01:00
parent a4690046b3
commit c4180f0f47
5 changed files with 32 additions and 21 deletions

5
.gitignore vendored
View File

@ -4,5 +4,10 @@ Cargo.lock
*.o *.o
*.a *.a
*.so *.so
*.out
*.elf
*.bin
*.dll
*.exe
.vscode .vscode

View File

@ -59,9 +59,10 @@ pub extern "C" fn afl_libfuzzer_main() {
for i in 0..1000 { for i in 0..1000 {
println!("Fuzzer corpus iteration #{}", i); println!("Fuzzer corpus iteration #{}", i);
engine let idx = engine
.fuzz_one(&mut state) .fuzz_one(&mut state)
.expect(&format!("Error in iter {}", i)); .expect(&format!("Error in iter {}", i));
println!("Fuzzed entry #{}", idx);
} }
println!("OK"); println!("OK");
} }

View File

@ -58,19 +58,19 @@ where
} }
/// Gets a random entry /// Gets a random entry
fn random_entry(&self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> { fn random_entry(&self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
if self.count() == 0 { if self.count() == 0 {
Err(AflError::Empty("No entries in corpus".to_owned())) Err(AflError::Empty("No entries in corpus".to_owned()))
} else { } 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(), id))
} }
} }
// TODO: IntoIter // TODO: IntoIter
/// Gets the next entry /// Gets the next entry
fn next(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> { fn next(&mut self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
self.random_entry() self.random_entry()
} }
} }
@ -260,12 +260,12 @@ where
} }
/// Gets a random entry /// Gets a random entry
fn random_entry(&self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> { fn random_entry(&self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
self.corpus.random_entry() self.corpus.random_entry()
} }
/// Gets the next entry /// Gets the next entry
fn next(&mut self) -> Result<Rc<RefCell<Testcase<I>>>, AflError> { fn next(&mut self) -> Result<(Rc<RefCell<Testcase<I>>>, usize), AflError> {
self.pos += 1; self.pos += 1;
if self.corpus.count() == 0 { if self.corpus.count() == 0 {
return Err(AflError::Empty("Corpus".to_owned())); return Err(AflError::Empty("Corpus".to_owned()));
@ -275,7 +275,7 @@ where
self.pos = 1; self.pos = 1;
self.cycles += 1; self.cycles += 1;
} }
Ok(self.corpus.entries()[self.pos - 1].clone()) Ok((self.corpus.entries()[self.pos - 1].clone(), self.pos - 1))
} }
} }
@ -373,6 +373,7 @@ mod tests {
let filename = q let filename = q
.next() .next()
.unwrap() .unwrap()
.0
.borrow() .borrow()
.filename() .filename()
.as_ref() .as_ref()
@ -382,6 +383,7 @@ mod tests {
filename, filename,
q.next() q.next()
.unwrap() .unwrap()
.0
.borrow() .borrow()
.filename() .filename()
.as_ref() .as_ref()

View File

@ -177,12 +177,12 @@ where
self.stages_mut().push(stage); self.stages_mut().push(stage);
} }
fn fuzz_one(&mut self, state: &mut S) -> Result<(), AflError> { fn fuzz_one(&mut self, state: &mut S) -> Result<usize, AflError> {
let testcase = state.corpus_mut().next()?; let (testcase, idx) = state.corpus_mut().next()?;
for stage in self.stages_mut() { for stage in self.stages_mut() {
stage.perform(testcase.clone(), state)?; stage.perform(testcase.clone(), state)?;
} }
Ok(()) Ok(idx)
} }
} }

View File

@ -9,8 +9,13 @@ use alloc::vec::Vec;
use core::cell::RefCell; use core::cell::RefCell;
use core::marker::PhantomData; use core::marker::PhantomData;
pub enum MutationResult {
Mutated,
Skipped,
}
/// The generic function type that identifies mutations /// The generic function type that identifies mutations
type MutationFunction<C, M, I> = fn(&mut M, &mut C, &mut I) -> Result<(), AflError>; type MutationFunction<C, M, I> = fn(&mut M, &mut C, &mut I) -> Result<MutationResult, AflError>;
pub trait ComposedByMutations<C, I> pub trait ComposedByMutations<C, I>
where where
@ -159,7 +164,7 @@ pub fn mutation_bitflip<C, M, I>(
mutator: &mut M, mutator: &mut M,
_corpus: &mut C, _corpus: &mut C,
input: &mut I, input: &mut I,
) -> Result<(), AflError> ) -> Result<MutationResult, AflError>
where where
C: Corpus<I>, C: Corpus<I>,
M: HasRand, M: HasRand,
@ -167,7 +172,7 @@ where
{ {
let bit = mutator.rand_below((input.bytes().len() * 8) as u64) as usize; let bit = mutator.rand_below((input.bytes().len() * 8) 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(MutationResult::Mutated)
} }
/// Returns the first and last diff position between the given vectors, stopping at the min len /// Returns the first and last diff position between the given vectors, stopping at the min len
@ -191,7 +196,7 @@ pub fn mutation_splice<C, M, I>(
mutator: &mut M, mutator: &mut M,
corpus: &mut C, corpus: &mut C,
input: &mut I, input: &mut I,
) -> Result<(), AflError> ) -> Result<MutationResult, AflError>
where where
C: Corpus<I>, C: Corpus<I>,
M: HasRand, M: HasRand,
@ -201,14 +206,12 @@ where
// We don't want to use the testcase we're already using for splicing // We don't want to use the testcase we're already using for splicing
let other_rr = loop { let other_rr = loop {
let mut found = false; let mut found = false;
let other_rr = corpus.random_entry()?.clone(); let (other_rr, _) = corpus.random_entry()?.clone();
match other_rr.try_borrow_mut() { match other_rr.try_borrow_mut() {
Ok(_) => found = true, Ok(_) => found = true,
Err(_) => { Err(_) => {
if retry_count == 20 { if retry_count == 20 {
return Err(AflError::Empty( return Ok(MutationResult::Skipped);
"No suitable testcase found for splicing".into(),
));
} }
retry_count += 1; retry_count += 1;
} }
@ -230,7 +233,7 @@ where
break (f, l); break (f, l);
} }
if counter == 20 { if counter == 20 {
return Err(AflError::Empty("No valid diff found".into())); return Ok(MutationResult::Skipped);
} }
counter += 1; counter += 1;
}; };
@ -246,7 +249,7 @@ where
// println!("Splice result: {:?}, input is now: {:?}", split_result, input.bytes()); // println!("Splice result: {:?}, input is now: {:?}", split_result, input.bytes());
Ok(()) Ok(MutationResult::Mutated)
} }
/// Schedule some selected byte level mutations given a ScheduledMutator type /// Schedule some selected byte level mutations given a ScheduledMutator type
@ -342,7 +345,7 @@ mod tests {
corpus.add(Testcase::new(vec!['a' as u8, 'b' as u8, 'c' as u8]).into()); corpus.add(Testcase::new(vec!['a' as u8, 'b' as u8, 'c' as u8]).into());
corpus.add(Testcase::new(vec!['d' as u8, 'e' as u8, 'f' as u8]).into()); corpus.add(Testcase::new(vec!['d' as u8, 'e' as u8, 'f' as u8]).into());
let testcase_rr = corpus.next().expect("Corpus did not contain entries"); let (testcase_rr, _) = corpus.next().expect("Corpus did not contain entries");
let mut testcase = testcase_rr.borrow_mut(); let mut testcase = testcase_rr.borrow_mut();
let mut input = testcase.load_input().expect("No input in testcase").clone(); let mut input = testcase.load_input().expect("No input in testcase").clone();