Merge branch 'main' into fix-default-prng

This commit is contained in:
Evan Richter 2021-02-25 15:50:30 -06:00 committed by GitHub
commit 00da3b975a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 200 additions and 284 deletions

44
.github/workflows/build_and_test.yml vendored Normal file
View File

@ -0,0 +1,44 @@
name: Build and Test
on: [push]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: cd libafl && cargo build --verbose
build-all:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: cd libafl &&cargo build --no-default-features --features runtime --features std --features anymapdbg --verbose
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Test
run: cd libafl && cargo test --verbose
build-no-std:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: cd libafl && cargo build --no-default-features --verbose
test-no-std:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Test
run: cd libafl && cargo test --no-default-features --verbose
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Test
run: cd libafl && cargo doc

View File

@ -1,11 +1,13 @@
# LibAFL, the fuzzer library. # LibAFL, the fuzzer library.
Advanced Fuzzing Library - Slot your own Fuzzers together and extend their features, using Rust. Advanced Fuzzing Library - Slot your own fuzzers together and extend their features using Rust.
LibAFL is written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>. LibAFL is written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>.
It is released as Free and Open Source Software under the GNU Lesser General Public License V3. It is released as Free and Open Source Software under the GNU Lesser General Public License V3.
## Example usages ## Example usages
We collect example fuzzers in `./fuzzers`. We collect example fuzzers in `./fuzzers`.
@ -14,6 +16,10 @@ The best-tested fuzzer is `./fuzzers/libfuzzer_libpng`, a clone of libfuzzer usi
If you want to get a quick overview, run `cargo doc`. If you want to get a quick overview, run `cargo doc`.
Feel free to open issues or contact us directly. Thank you for your support. <3 Feel free to open issues or contact us directly. Thank you for your support. <3
## The Core Concepts
We're still working on the documentation. In the meantime, you can watch the Video from last year's Rc3, here:
[![Video explaining libAFL's core concepts](http://img.youtube.com/vi/3RWkT1Q5IV0/0.jpg)](http://www.youtube.com/watch?v=3RWkT1Q5IV0 "Fuzzers Like LEGO")
## Roadmap for release ## Roadmap for release
+ Minset corpus scheduler + Minset corpus scheduler

View File

@ -1,3 +1,4 @@
//! Poor-rust-man's downcasts for stuff we send over the wire (or shared maps)
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use alloc::boxed::Box; use alloc::boxed::Box;

View File

@ -1,3 +1,5 @@
//! Compiletime lists used throughout the libafl universe
pub use tuple_list::{tuple_list, tuple_list_type, TupleList}; pub use tuple_list::{tuple_list, tuple_list_type, TupleList};
use core::any::TypeId; use core::any::TypeId;

View File

@ -1,7 +1,7 @@
//! Eventmanager manages all events that go to other instances of the fuzzer. //! Eventmanager manages all events that go to other instances of the fuzzer.
pub mod logger; pub mod simple;
pub use logger::*; pub use simple::*;
pub mod llmp; pub mod llmp;
pub use llmp::*; pub use llmp::*;

View File

@ -1,3 +1,4 @@
//! A very simple event manager, that just supports log outputs, but no multiprocessing
use alloc::{string::ToString, vec::Vec}; use alloc::{string::ToString, vec::Vec};
use core::marker::PhantomData; use core::marker::PhantomData;
@ -12,7 +13,7 @@ use crate::{
/// A simple, single-threaded event manager that just logs /// A simple, single-threaded event manager that just logs
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct LoggerEventManager<I, S, ST> pub struct SimpleEventManager<I, S, ST>
where where
I: Input, I: Input,
ST: Stats, //CE: CustomEvent<I, OT>, ST: Stats, //CE: CustomEvent<I, OT>,
@ -24,7 +25,7 @@ where
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<I, S, ST> EventManager<I, S> for LoggerEventManager<I, S, ST> impl<I, S, ST> EventManager<I, S> for SimpleEventManager<I, S, ST>
where where
I: Input, I: Input,
ST: Stats, //CE: CustomEvent<I, OT>, ST: Stats, //CE: CustomEvent<I, OT>,
@ -51,7 +52,7 @@ where
} }
} }
impl<I, S, ST> LoggerEventManager<I, S, ST> impl<I, S, ST> SimpleEventManager<I, S, ST>
where where
I: Input, I: Input,
ST: Stats, //TODO CE: CustomEvent, ST: Stats, //TODO CE: CustomEvent,

View File

@ -38,7 +38,7 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: &u32) {
//*trace_byte = (*trace_byte).wrapping_add(1); //*trace_byte = (*trace_byte).wrapping_add(1);
} }
/// Called when the targetprogram starts /// Called when the target program starts
#[no_mangle] #[no_mangle]
#[inline] #[inline]
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) { pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {

View File

@ -117,7 +117,6 @@ impl From<ParseIntError> for Error {
} }
} }
/*
// TODO: no_std test // TODO: no_std test
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg(test)] #[cfg(test)]
@ -125,7 +124,7 @@ mod tests {
use crate::{ use crate::{
bolts::tuples::tuple_list, bolts::tuples::tuple_list,
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, RandCorpusScheduler, Testcase},
executors::{Executor, ExitKind, InProcessExecutor}, executors::{Executor, ExitKind, InProcessExecutor},
inputs::{BytesInput, Input}, inputs::{BytesInput, Input},
mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}, mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator},
@ -137,7 +136,7 @@ mod tests {
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::events::LoggerEventManager; use crate::events::SimpleEventManager;
fn harness<E: Executor<I>, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind { fn harness<E: Executor<I>, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind {
ExitKind::Ok ExitKind::Ok
@ -145,23 +144,24 @@ mod tests {
#[test] #[test]
fn test_fuzzer() { fn test_fuzzer() {
let mut rand = StdRand::new(0); let rand = StdRand::new(0);
let mut corpus = InMemoryCorpus::<BytesInput, StdRand>::new(); let mut corpus = InMemoryCorpus::<BytesInput>::new();
let testcase = Testcase::new(vec![0; 4]).into(); let testcase = Testcase::new(vec![0; 4]).into();
corpus.add(testcase); corpus.add(testcase).unwrap();
let mut state = State::new( let mut state = State::new(
rand,
corpus, corpus,
tuple_list!(), tuple_list!(),
InMemoryCorpus::<BytesInput, StdRand>::new(), InMemoryCorpus::<BytesInput>::new(),
tuple_list!(), tuple_list!(),
); );
let stats = SimpleStats::new(|s| { let stats = SimpleStats::new(|s| {
println!("{}", s); println!("{}", s);
}); });
let mut event_manager = LoggerEventManager::new(stats); let mut event_manager = SimpleEventManager::new(stats);
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
"main", "main",
@ -175,29 +175,28 @@ mod tests {
let mut mutator = StdScheduledMutator::new(); let mut mutator = StdScheduledMutator::new();
mutator.add_mutation(mutation_bitflip); mutator.add_mutation(mutation_bitflip);
let stage = StdMutationalStage::new(mutator); let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); let fuzzer = StdFuzzer::new(RandCorpusScheduler::new(), tuple_list!(stage));
for i in 0..1000 { for i in 0..1000 {
fuzzer fuzzer
.fuzz_one(&mut rand, &mut executor, &mut state, &mut event_manager) .fuzz_one(&mut state, &mut executor, &mut event_manager)
.expect(&format!("Error in iter {}", i)); .expect(&format!("Error in iter {}", i));
} }
let state_serialized = postcard::to_allocvec(&state).unwrap(); let state_serialized = postcard::to_allocvec(&state).unwrap();
let state_deserialized: State< let state_deserialized: State<
InMemoryCorpus<BytesInput, _>, InMemoryCorpus<BytesInput>,
(), (),
BytesInput, BytesInput,
InMemoryCorpus<BytesInput, _>,
(), (),
StdRand, StdRand,
InMemoryCorpus<BytesInput>,
> = postcard::from_bytes(state_serialized.as_slice()).unwrap(); > = postcard::from_bytes(state_serialized.as_slice()).unwrap();
assert_eq!(state.executions(), state_deserialized.executions()); assert_eq!(state.corpus().count(), state_deserialized.corpus().count());
let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap(); let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap();
let corpus_deserialized: InMemoryCorpus<BytesInput, StdRand> = let corpus_deserialized: InMemoryCorpus<BytesInput> =
postcard::from_bytes(corpus_serialized.as_slice()).unwrap(); postcard::from_bytes(corpus_serialized.as_slice()).unwrap();
assert_eq!(state.corpus().count(), corpus_deserialized.count()); assert_eq!(state.corpus().count(), corpus_deserialized.count());
} }
} }
*/

View File

@ -31,14 +31,3 @@ where
Ok(()) Ok(())
} }
} }
/// The maximum size of a testcase
pub const DEFAULT_MAX_SIZE: usize = 1048576;
/// Interact with the maximum size
pub trait HasMaxSize {
/// The maximum size of the contents returned
fn max_size(&self) -> usize;
/// Sets the maximum size of the contents returned
fn set_max_size(&mut self, max_size: usize);
}

View File

@ -1,8 +1,9 @@
//! A wide variety of mutations used during fuzzing.
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
inputs::{HasBytesVec, Input}, inputs::{HasBytesVec, Input},
mutators::*, state::{HasCorpus, HasMaxSize, HasRand},
state::{HasCorpus, HasRand},
utils::Rand, utils::Rand,
Error, Error,
}; };
@ -27,20 +28,20 @@ pub enum MutationResult {
// TODO maybe the mutator arg is not needed // TODO maybe the mutator arg is not needed
/// The generic function type that identifies mutations /// The generic function type that identifies mutations
pub type MutationFunction<I, M, S> = fn(&M, &mut S, &mut I) -> Result<MutationResult, Error>; pub type MutationFunction<I, S> = fn(&mut S, &mut I) -> Result<MutationResult, Error>;
pub trait ComposedByMutations<I, S> pub trait ComposedByMutations<I, S>
where where
I: Input, I: Input,
{ {
/// Get a mutation by index /// Get a mutation by index
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S>; fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, S>;
/// Get the number of mutations /// Get the number of mutations
fn mutations_count(&self) -> usize; fn mutations_count(&self) -> usize;
/// Add a mutation /// Add a mutation
fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>); fn add_mutation(&mut self, mutation: MutationFunction<I, S>);
} }
/// Mem move in the own vec /// Mem move in the own vec
@ -123,15 +124,10 @@ const INTERESTING_32: [i32; 27] = [
]; ];
/// Bitflip mutation for inputs with a bytes vector /// Bitflip mutation for inputs with a bytes vector
pub fn mutation_bitflip<I, M, R, S>( pub fn mutation_bitflip<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R> + HasMaxSize,
R: Rand, R: Rand,
{ {
if input.bytes().len() == 0 { if input.bytes().len() == 0 {
@ -146,12 +142,7 @@ where
} }
} }
pub fn mutation_byteflip<I, M, R, S>( pub fn mutation_byteflip<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -169,12 +160,7 @@ where
} }
} }
pub fn mutation_byteinc<I, M, R, S>( pub fn mutation_byteinc<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -193,12 +179,7 @@ where
} }
} }
pub fn mutation_bytedec<I, M, R, S>( pub fn mutation_bytedec<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -217,12 +198,7 @@ where
} }
} }
pub fn mutation_byteneg<I, M, R, S>( pub fn mutation_byteneg<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -240,12 +216,7 @@ where
} }
} }
pub fn mutation_byterand<I, M, R, S>( pub fn mutation_byterand<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -263,12 +234,7 @@ where
} }
} }
pub fn mutation_byteadd<I, M, R, S>( pub fn mutation_byteadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -291,12 +257,7 @@ where
} }
} }
pub fn mutation_wordadd<I, M, R, S>( pub fn mutation_wordadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -321,12 +282,7 @@ where
} }
} }
pub fn mutation_dwordadd<I, M, R, S>( pub fn mutation_dwordadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -351,12 +307,7 @@ where
} }
} }
pub fn mutation_qwordadd<I, M, R, S>( pub fn mutation_qwordadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -381,9 +332,7 @@ where
} }
} }
pub fn mutation_byteinteresting<I, M, R, S>( pub fn mutation_byteinteresting<I, R, S>(
_: &M,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -405,9 +354,7 @@ where
} }
} }
pub fn mutation_wordinteresting<I, M, R, S>( pub fn mutation_wordinteresting<I, R, S>(
_: &M,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -435,9 +382,7 @@ where
} }
} }
pub fn mutation_dwordinteresting<I, M, R, S>( pub fn mutation_dwordinteresting<I, R, S>(
_: &M,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -465,12 +410,7 @@ where
} }
} }
pub fn mutation_bytesdelete<I, M, R, S>( pub fn mutation_bytesdelete<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -488,25 +428,20 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesexpand<I, M, R, S>( pub fn mutation_bytesexpand<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
mutator: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
M: HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R> + HasMaxSize,
R: Rand, R: Rand,
{ {
let max_size = state.max_size();
let size = input.bytes().len(); let size = input.bytes().len();
let off = state.rand_mut().below((size + 1) as u64) as usize; let off = state.rand_mut().below((size + 1) as u64) as usize;
let mut len = 1 + state.rand_mut().below(16) as usize; let mut len = 1 + state.rand_mut().below(16) as usize;
if size + len > mutator.max_size() { if size + len > max_size {
if mutator.max_size() > size { if max_size > size {
len = mutator.max_size() - size; len = max_size - size;
} else { } else {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
@ -518,25 +453,23 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesinsert<I, M, R, S>( pub fn mutation_bytesinsert<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
mutator: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
M: HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R> + HasMaxSize,
R: Rand, R: Rand,
{ {
let max_size = state.max_size();
let size = input.bytes().len(); let size = input.bytes().len();
if size == 0 {
return Ok(MutationResult::Skipped);
}
let off = state.rand_mut().below((size + 1) as u64) as usize; let off = state.rand_mut().below((size + 1) as u64) as usize;
let mut len = 1 + state.rand_mut().below(16) as usize; let mut len = 1 + state.rand_mut().below(16) as usize;
if size + len > mutator.max_size() { if size + len > max_size {
if mutator.max_size() > size { if max_size > size {
len = mutator.max_size() - size; len = max_size - size;
} else { } else {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
@ -551,25 +484,23 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesrandinsert<I, M, R, S>( pub fn mutation_bytesrandinsert<I, R, S>(
mutator: &M,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
where where
M: HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R> + HasMaxSize,
R: Rand, R: Rand,
{ {
let max_size = state.max_size();
let size = input.bytes().len(); let size = input.bytes().len();
let off = state.rand_mut().below((size + 1) as u64) as usize; let off = state.rand_mut().below((size + 1) as u64) as usize;
let mut len = 1 + state.rand_mut().below(16) as usize; let mut len = 1 + state.rand_mut().below(16) as usize;
if size + len > mutator.max_size() { if size + len > max_size {
if mutator.max_size() > size { if max_size > size {
len = mutator.max_size() - size; len = max_size - size;
} else { } else {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
@ -584,12 +515,7 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesset<I, M, R, S>( pub fn mutation_bytesset<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -609,12 +535,7 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesrandset<I, M, R, S>( pub fn mutation_bytesrandset<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -634,12 +555,7 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytescopy<I, M, R, S>( pub fn mutation_bytescopy<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -659,12 +575,7 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesswap<I, M, R, S>( pub fn mutation_bytesswap<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R>, S: HasRand<R>,
@ -687,18 +598,15 @@ where
} }
/// Crossover insert mutation /// Crossover insert mutation
pub fn mutation_crossover_insert<C, I, M, R, S>( pub fn mutation_crossover_insert<C, I, R, S>(
mutator: &M,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
where where
M: HasMaxSize,
C: Corpus<I>, C: Corpus<I>,
I: Input + HasBytesVec, I: Input + HasBytesVec,
R: Rand, R: Rand,
S: HasRand<R> + HasCorpus<C, I>, S: HasRand<R> + HasCorpus<C, I> + HasMaxSize,
{ {
let size = input.bytes().len(); let size = input.bytes().len();
@ -722,6 +630,7 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
let max_size = state.max_size();
let from = state.rand_mut().below(other_size as u64) as usize; let from = state.rand_mut().below(other_size as u64) as usize;
let to = state.rand_mut().below(size as u64) as usize; let to = state.rand_mut().below(size as u64) as usize;
let mut len = state.rand_mut().below((other_size - from) as u64) as usize; let mut len = state.rand_mut().below((other_size - from) as u64) as usize;
@ -729,9 +638,9 @@ where
let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
let other = other_testcase.load_input()?; let other = other_testcase.load_input()?;
if size + len > mutator.max_size() { if size + len > max_size {
if mutator.max_size() > size { if max_size > size {
len = mutator.max_size() - size; len = max_size - size;
} else { } else {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
@ -745,9 +654,7 @@ where
} }
/// Crossover replace mutation /// Crossover replace mutation
pub fn mutation_crossover_replace<C, I, M, R, S>( pub fn mutation_crossover_replace<C, I, R, S>(
_: &M,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -808,12 +715,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
} }
/// Splicing mutation from AFL /// Splicing mutation from AFL
pub fn mutation_splice<C, I, M, R, S>( pub fn mutation_splice<C, I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input + HasBytesVec, I: Input + HasBytesVec,
@ -970,7 +872,6 @@ pub fn read_tokens_file(f: &str, tokens: &mut Vec<Vec<u8>>) -> Result<u32, Error
Ok(entries) Ok(entries)
} }
/*
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -1007,17 +908,6 @@ token2="B"
let _ = fs::remove_file("test.tkns"); let _ = fs::remove_file("test.tkns");
} }
struct WithMaxSize {}
impl HasMaxSize for WithMaxSize {
fn max_size(&self) -> usize {
16000 as usize
}
fn set_max_size(&mut self, _max_size: usize) {
todo!("Not needed");
}
}
#[test] #[test]
fn test_mutators() { fn test_mutators() {
let mut inputs = vec![ let mut inputs = vec![
@ -1030,16 +920,16 @@ token2="B"
BytesInput::new(vec![1; 4]), BytesInput::new(vec![1; 4]),
]; ];
let mut mutator = WithMaxSize {}; let rand = StdRand::new(1337);
let mut corpus = InMemoryCorpus::new();
let mut rand = StdRand::new(1337); corpus
let mut corpus: InMemoryCorpus<_, StdRand> = InMemoryCorpus::new(); .add(BytesInput::new(vec![0x42; 0x1337]).into())
.unwrap();
corpus.add(BytesInput::new(vec![0x42; 0x1337]).into()); let mut state = State::new(rand, corpus, (), InMemoryCorpus::new(), ());
let mut state = State::new(corpus, (), InMemoryCorpus::new(), ()); let mut mutations: Vec<MutationFunction<_, _>> = vec![];
let mut mutations: Vec<MutationFunction<BytesInput, WithMaxSize, StdRand, _>> = vec![];
mutations.push(mutation_bitflip); mutations.push(mutation_bitflip);
mutations.push(mutation_byteflip); mutations.push(mutation_byteflip);
@ -1072,7 +962,7 @@ token2="B"
for mutation in &mutations { for mutation in &mutations {
for input in inputs.iter() { for input in inputs.iter() {
let mut mutant = input.clone(); let mut mutant = input.clone();
match mutation(&mut mutator, &mut rand, &mut state, &mut mutant).unwrap() { match mutation(&mut state, &mut mutant).unwrap() {
MutationResult::Mutated => new_testcases.push(mutant), MutationResult::Mutated => new_testcases.push(mutant),
MutationResult::Skipped => (), MutationResult::Skipped => (),
}; };
@ -1087,4 +977,3 @@ token2="B"
*/ */
} }
} }
*/

View File

@ -1,13 +1,15 @@
use crate::inputs::HasBytesVec;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::{default::Default, fmt, marker::PhantomData}; use core::{
use fmt::Debug; default::Default,
fmt::{self, Debug},
marker::PhantomData,
};
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
inputs::Input, inputs::{HasBytesVec, Input},
mutators::{HasMaxSize, Mutator, DEFAULT_MAX_SIZE}, mutators::Mutator,
state::{HasCorpus, HasMetadata, HasRand}, state::{HasCorpus, HasMaxSize, HasMetadata, HasRand},
utils::Rand, utils::Rand,
Error, Error,
}; };
@ -31,7 +33,7 @@ where
let num = self.iterations(state, input); let num = self.iterations(state, input);
for _ in 0..num { for _ in 0..num {
let idx = self.schedule(self.mutations_count(), state, input); let idx = self.schedule(self.mutations_count(), state, input);
self.mutation_by_idx(idx)(self, state, input)?; self.mutation_by_idx(idx)(state, input)?;
} }
Ok(()) Ok(())
} }
@ -43,8 +45,7 @@ where
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
mutations: Vec<MutationFunction<I, Self, S>>, mutations: Vec<MutationFunction<I, S>>,
max_size: usize,
phantom: PhantomData<R>, phantom: PhantomData<R>,
} }
@ -57,9 +58,8 @@ where
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"StdScheduledMutator with {} Mutations, max_size: {}, for Input type {}", "StdScheduledMutator with {} Mutations for Input type {}",
self.mutations.len(), self.mutations.len(),
self.max_size,
core::any::type_name::<I>() core::any::type_name::<I>()
) )
} }
@ -83,7 +83,7 @@ where
R: Rand, R: Rand,
{ {
#[inline] #[inline]
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S> { fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, S> {
self.mutations[index] self.mutations[index]
} }
@ -93,7 +93,7 @@ where
} }
#[inline] #[inline]
fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>) { fn add_mutation(&mut self, mutation: MutationFunction<I, S>) {
self.mutations.push(mutation) self.mutations.push(mutation)
} }
} }
@ -116,23 +116,6 @@ where
} }
} }
impl<I, R, S> HasMaxSize for StdScheduledMutator<I, R, S>
where
I: Input,
S: HasRand<R>,
R: Rand,
{
#[inline]
fn max_size(&self) -> usize {
self.max_size
}
#[inline]
fn set_max_size(&mut self, max_size: usize) {
self.max_size = max_size;
}
}
impl<I, R, S> StdScheduledMutator<I, R, S> impl<I, R, S> StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
@ -143,16 +126,14 @@ where
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
mutations: vec![], mutations: vec![],
max_size: DEFAULT_MAX_SIZE,
phantom: PhantomData, phantom: PhantomData,
} }
} }
/// Create a new StdScheduledMutator instance specifying mutations /// Create a new StdScheduledMutator instance specifying mutations
pub fn with_mutations(mutations: Vec<MutationFunction<I, Self, S>>) -> Self { pub fn with_mutations(mutations: Vec<MutationFunction<I, S>>) -> Self {
StdScheduledMutator { StdScheduledMutator {
mutations: mutations, mutations: mutations,
max_size: DEFAULT_MAX_SIZE,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -162,9 +143,9 @@ where
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct HavocBytesMutator<C, I, R, S, SM> pub struct HavocBytesMutator<C, I, R, S, SM>
where where
SM: ScheduledMutator<I, S> + HasMaxSize, SM: ScheduledMutator<I, S>,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
C: Corpus<I>, C: Corpus<I>,
R: Rand, R: Rand,
{ {
@ -174,9 +155,9 @@ where
impl<C, I, R, S, SM> Mutator<I, S> for HavocBytesMutator<C, I, R, S, SM> impl<C, I, R, S, SM> Mutator<I, S> for HavocBytesMutator<C, I, R, S, SM>
where where
SM: ScheduledMutator<I, S> + HasMaxSize, SM: ScheduledMutator<I, S>,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
C: Corpus<I>, C: Corpus<I>,
R: Rand, R: Rand,
{ {
@ -208,30 +189,11 @@ where
} }
} }
impl<C, I, R, S, SM> HasMaxSize for HavocBytesMutator<C, I, R, S, SM>
where
SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>,
R: Rand,
{
#[inline]
fn max_size(&self) -> usize {
self.scheduled.max_size()
}
#[inline]
fn set_max_size(&mut self, max_size: usize) {
self.scheduled.set_max_size(max_size);
}
}
impl<C, I, R, S, SM> HavocBytesMutator<C, I, R, S, SM> impl<C, I, R, S, SM> HavocBytesMutator<C, I, R, S, SM>
where where
SM: ScheduledMutator<I, S> + HasMaxSize, SM: ScheduledMutator<I, S>,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
C: Corpus<I>, C: Corpus<I>,
R: Rand, R: Rand,
{ {
@ -249,7 +211,7 @@ where
impl<C, I, R, S> Default for HavocBytesMutator<C, I, R, S, StdScheduledMutator<I, R, S>> impl<C, I, R, S> Default for HavocBytesMutator<C, I, R, S, StdScheduledMutator<I, R, S>>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
C: Corpus<I>, C: Corpus<I>,
R: Rand, R: Rand,
{ {

View File

@ -4,7 +4,7 @@
use crate::{ use crate::{
inputs::{HasBytesVec, Input}, inputs::{HasBytesVec, Input},
mutators::*, mutators::*,
state::{HasMetadata, HasRand}, state::{HasMaxSize, HasMetadata, HasRand},
utils::Rand, utils::Rand,
Error, Error,
}; };
@ -30,17 +30,13 @@ impl TokensMetadata {
} }
/// Insert a dictionary token /// Insert a dictionary token
pub fn mutation_tokeninsert<I, M, R, S>( pub fn mutation_tokeninsert<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
mutator: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
M: HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasMetadata + HasRand<R>, S: HasMetadata + HasRand<R> + HasMaxSize,
R: Rand, R: Rand,
{ {
let max_size = state.max_size();
let tokens_len = { let tokens_len = {
let meta = state.metadata().get::<TokensMetadata>(); let meta = state.metadata().get::<TokensMetadata>();
if meta.is_none() { if meta.is_none() {
@ -60,9 +56,9 @@ where
let token = &meta.tokens[token_idx]; let token = &meta.tokens[token_idx];
let mut len = token.len(); let mut len = token.len();
if size + len > mutator.max_size() { if size + len > max_size {
if mutator.max_size() > size { if max_size > size {
len = mutator.max_size() - size; len = max_size - size;
} else { } else {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
@ -76,13 +72,8 @@ where
} }
/// Overwrite with a dictionary token /// Overwrite with a dictionary token
pub fn mutation_tokenreplace<I, M, R, S>( pub fn mutation_tokenreplace<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
_: &M,
state: &mut S,
input: &mut I,
) -> Result<MutationResult, Error>
where where
M: HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasMetadata + HasRand<R>, S: HasMetadata + HasRand<R>,
R: Rand, R: Rand,

View File

@ -24,6 +24,9 @@ use crate::{
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::inputs::bytes::BytesInput; use crate::inputs::bytes::BytesInput;
/// The maximum size of a testcase
pub const DEFAULT_MAX_SIZE: usize = 1048576;
/// Trait for elements offering a corpus /// Trait for elements offering a corpus
pub trait HasCorpus<C, I> pub trait HasCorpus<C, I>
where where
@ -36,6 +39,14 @@ where
fn corpus_mut(&mut self) -> &mut C; fn corpus_mut(&mut self) -> &mut C;
} }
/// Interact with the maximum size
pub trait HasMaxSize {
/// The maximum size hint for items and mutations returned
fn max_size(&self) -> usize;
/// Sets the maximum size hint for the items and mutations
fn set_max_size(&mut self, max_size: usize);
}
/// Trait for elements offering a corpus of solutions /// Trait for elements offering a corpus of solutions
pub trait HasSolutions<C, I> pub trait HasSolutions<C, I>
where where
@ -204,6 +215,8 @@ where
objectives: OFT, objectives: OFT,
/// Metadata stored for this state by one of the components /// Metadata stored for this state by one of the components
metadata: SerdeAnyMap, metadata: SerdeAnyMap,
/// MaxSize testcase size for mutators that appreciate it
max_size: usize,
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
@ -362,6 +375,24 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> HasMaxSize for State<C, FT, I, OFT, R, SC>
where
C: Corpus<I>,
I: Input,
R: Rand,
FT: FeedbacksTuple<I>,
SC: Corpus<I>,
OFT: FeedbacksTuple<I>,
{
fn max_size(&self) -> usize {
self.max_size
}
fn set_max_size(&mut self, max_size: usize) {
self.max_size = max_size
}
}
impl<C, FT, I, OFT, R, SC> HasStartTime for State<C, FT, I, OFT, R, SC> impl<C, FT, I, OFT, R, SC> HasStartTime for State<C, FT, I, OFT, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
@ -638,6 +669,7 @@ where
feedbacks, feedbacks,
solutions, solutions,
objectives, objectives,
max_size: DEFAULT_MAX_SIZE,
phantom: PhantomData, phantom: PhantomData,
} }
} }