diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml new file mode 100644 index 0000000000..8bc17fffd1 --- /dev/null +++ b/.github/workflows/build_and_test.yml @@ -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 \ No newline at end of file diff --git a/README.md b/README.md index de0a2bacc7..8319efb070 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # 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 and Dominik Maier . It is released as Free and Open Source Software under the GNU Lesser General Public License V3. + + ## Example usages 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`. 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 + Minset corpus scheduler diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index f793c6d4dd..dd9c7611e4 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -88,7 +88,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> StdRand::new(current_nanos()), // Corpus that will be evolved, we keep it in memory for performance InMemoryCorpus::new(), - // Feedbacks to rate the interestingness of an input + // Feedbacks to rate the interestingness of an input tuple_list!(MaxMapFeedback::new_with_observer("edges", &edges_observer)), // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer @@ -137,7 +137,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // In case the corpus is empty (on first run), reset if state.corpus().count() < 1 { - state + state .load_initial_inputs(&mut executor, &mut restarting_mgr, &corpus_dirs) .expect(&format!( "Failed to load initial corpus at {:?}", diff --git a/libafl/src/bolts/serdeany.rs b/libafl/src/bolts/serdeany.rs index 8fcd3ae208..c12d346e3f 100644 --- a/libafl/src/bolts/serdeany.rs +++ b/libafl/src/bolts/serdeany.rs @@ -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 alloc::boxed::Box; diff --git a/libafl/src/bolts/tuples.rs b/libafl/src/bolts/tuples.rs index ba20a0f29a..162bea12ce 100644 --- a/libafl/src/bolts/tuples.rs +++ b/libafl/src/bolts/tuples.rs @@ -1,3 +1,5 @@ +//! Compiletime lists used throughout the libafl universe + pub use tuple_list::{tuple_list, tuple_list_type, TupleList}; use core::any::TypeId; diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index c485101bd1..0ff73ead86 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -1,7 +1,7 @@ //! Eventmanager manages all events that go to other instances of the fuzzer. -pub mod logger; -pub use logger::*; +pub mod simple; +pub use simple::*; pub mod llmp; pub use llmp::*; diff --git a/libafl/src/events/logger.rs b/libafl/src/events/simple.rs similarity index 93% rename from libafl/src/events/logger.rs rename to libafl/src/events/simple.rs index 65c05dee7b..5fb217ec37 100644 --- a/libafl/src/events/logger.rs +++ b/libafl/src/events/simple.rs @@ -1,3 +1,4 @@ +//! A very simple event manager, that just supports log outputs, but no multiprocessing use alloc::{string::ToString, vec::Vec}; use core::marker::PhantomData; @@ -12,7 +13,7 @@ use crate::{ /// A simple, single-threaded event manager that just logs #[derive(Clone, Debug)] -pub struct LoggerEventManager +pub struct SimpleEventManager where I: Input, ST: Stats, //CE: CustomEvent, @@ -24,7 +25,7 @@ where phantom: PhantomData, } -impl EventManager for LoggerEventManager +impl EventManager for SimpleEventManager where I: Input, ST: Stats, //CE: CustomEvent, @@ -51,7 +52,7 @@ where } } -impl LoggerEventManager +impl SimpleEventManager where I: Input, ST: Stats, //TODO CE: CustomEvent, diff --git a/libafl/src/executors/runtime.rs b/libafl/src/executors/runtime.rs index c1aa4af39f..1b7de09d80 100644 --- a/libafl/src/executors/runtime.rs +++ b/libafl/src/executors/runtime.rs @@ -38,7 +38,7 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: &u32) { //*trace_byte = (*trace_byte).wrapping_add(1); } -/// Called when the targetprogram starts +/// Called when the target program starts #[no_mangle] #[inline] pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) { diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index ff2b795100..7d3212a9bd 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -117,7 +117,6 @@ impl From for Error { } } -/* // TODO: no_std test #[cfg(feature = "std")] #[cfg(test)] @@ -125,7 +124,7 @@ mod tests { use crate::{ bolts::tuples::tuple_list, - corpus::{Corpus, InMemoryCorpus, Testcase}, + corpus::{Corpus, InMemoryCorpus, RandCorpusScheduler, Testcase}, executors::{Executor, ExitKind, InProcessExecutor}, inputs::{BytesInput, Input}, mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}, @@ -137,7 +136,7 @@ mod tests { }; #[cfg(feature = "std")] - use crate::events::LoggerEventManager; + use crate::events::SimpleEventManager; fn harness, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind { ExitKind::Ok @@ -145,23 +144,24 @@ mod tests { #[test] fn test_fuzzer() { - let mut rand = StdRand::new(0); + let rand = StdRand::new(0); - let mut corpus = InMemoryCorpus::::new(); + let mut corpus = InMemoryCorpus::::new(); let testcase = Testcase::new(vec![0; 4]).into(); - corpus.add(testcase); + corpus.add(testcase).unwrap(); let mut state = State::new( + rand, corpus, tuple_list!(), - InMemoryCorpus::::new(), + InMemoryCorpus::::new(), tuple_list!(), ); let stats = SimpleStats::new(|s| { println!("{}", s); }); - let mut event_manager = LoggerEventManager::new(stats); + let mut event_manager = SimpleEventManager::new(stats); let mut executor = InProcessExecutor::new( "main", @@ -175,29 +175,28 @@ mod tests { let mut mutator = StdScheduledMutator::new(); mutator.add_mutation(mutation_bitflip); 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 { 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)); } let state_serialized = postcard::to_allocvec(&state).unwrap(); let state_deserialized: State< - InMemoryCorpus, + InMemoryCorpus, (), BytesInput, - InMemoryCorpus, (), StdRand, + InMemoryCorpus, > = 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_deserialized: InMemoryCorpus = + let corpus_deserialized: InMemoryCorpus = postcard::from_bytes(corpus_serialized.as_slice()).unwrap(); assert_eq!(state.corpus().count(), corpus_deserialized.count()); } } -*/ diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 2337152477..e0eaf420ea 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -31,14 +31,3 @@ where 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); -} diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 4b394e65a6..eb8606f9d3 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -1,8 +1,9 @@ +//! A wide variety of mutations used during fuzzing. + use crate::{ corpus::Corpus, inputs::{HasBytesVec, Input}, - mutators::*, - state::{HasCorpus, HasRand}, + state::{HasCorpus, HasMaxSize, HasRand}, utils::Rand, Error, }; @@ -27,20 +28,20 @@ pub enum MutationResult { // TODO maybe the mutator arg is not needed /// The generic function type that identifies mutations -pub type MutationFunction = fn(&M, &mut S, &mut I) -> Result; +pub type MutationFunction = fn(&mut S, &mut I) -> Result; pub trait ComposedByMutations where I: Input, { /// Get a mutation by index - fn mutation_by_idx(&self, index: usize) -> MutationFunction; + fn mutation_by_idx(&self, index: usize) -> MutationFunction; /// Get the number of mutations fn mutations_count(&self) -> usize; /// Add a mutation - fn add_mutation(&mut self, mutation: MutationFunction); + fn add_mutation(&mut self, mutation: MutationFunction); } /// Mem move in the own vec @@ -123,15 +124,10 @@ const INTERESTING_32: [i32; 27] = [ ]; /// Bitflip mutation for inputs with a bytes vector -pub fn mutation_bitflip( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bitflip(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, - S: HasRand, + S: HasRand + HasMaxSize, R: Rand, { if input.bytes().len() == 0 { @@ -146,12 +142,7 @@ where } } -pub fn mutation_byteflip( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_byteflip(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -169,12 +160,7 @@ where } } -pub fn mutation_byteinc( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_byteinc(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -193,12 +179,7 @@ where } } -pub fn mutation_bytedec( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytedec(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -217,12 +198,7 @@ where } } -pub fn mutation_byteneg( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_byteneg(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -240,12 +216,7 @@ where } } -pub fn mutation_byterand( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_byterand(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -263,12 +234,7 @@ where } } -pub fn mutation_byteadd( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_byteadd(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -291,12 +257,7 @@ where } } -pub fn mutation_wordadd( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_wordadd(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -321,12 +282,7 @@ where } } -pub fn mutation_dwordadd( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_dwordadd(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -351,12 +307,7 @@ where } } -pub fn mutation_qwordadd( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_qwordadd(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -381,9 +332,7 @@ where } } -pub fn mutation_byteinteresting( - _: &M, - +pub fn mutation_byteinteresting( state: &mut S, input: &mut I, ) -> Result @@ -405,9 +354,7 @@ where } } -pub fn mutation_wordinteresting( - _: &M, - +pub fn mutation_wordinteresting( state: &mut S, input: &mut I, ) -> Result @@ -435,9 +382,7 @@ where } } -pub fn mutation_dwordinteresting( - _: &M, - +pub fn mutation_dwordinteresting( state: &mut S, input: &mut I, ) -> Result @@ -465,12 +410,7 @@ where } } -pub fn mutation_bytesdelete( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytesdelete(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -488,25 +428,20 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesexpand( - mutator: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytesexpand(state: &mut S, input: &mut I) -> Result where - M: HasMaxSize, I: Input + HasBytesVec, - S: HasRand, + S: HasRand + HasMaxSize, R: Rand, { + let max_size = state.max_size(); let size = input.bytes().len(); let off = state.rand_mut().below((size + 1) as u64) as usize; let mut len = 1 + state.rand_mut().below(16) as usize; - if size + len > mutator.max_size() { - if mutator.max_size() > size { - len = mutator.max_size() - size; + if size + len > max_size { + if max_size > size { + len = max_size - size; } else { return Ok(MutationResult::Skipped); } @@ -518,25 +453,23 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesinsert( - mutator: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytesinsert(state: &mut S, input: &mut I) -> Result where - M: HasMaxSize, I: Input + HasBytesVec, - S: HasRand, + S: HasRand + HasMaxSize, R: Rand, { + let max_size = state.max_size(); 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 mut len = 1 + state.rand_mut().below(16) as usize; - if size + len > mutator.max_size() { - if mutator.max_size() > size { - len = mutator.max_size() - size; + if size + len > max_size { + if max_size > size { + len = max_size - size; } else { return Ok(MutationResult::Skipped); } @@ -551,25 +484,23 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesrandinsert( - mutator: &M, - +pub fn mutation_bytesrandinsert( state: &mut S, input: &mut I, ) -> Result where - M: HasMaxSize, I: Input + HasBytesVec, - S: HasRand, + S: HasRand + HasMaxSize, R: Rand, { + let max_size = state.max_size(); let size = input.bytes().len(); let off = state.rand_mut().below((size + 1) as u64) as usize; let mut len = 1 + state.rand_mut().below(16) as usize; - if size + len > mutator.max_size() { - if mutator.max_size() > size { - len = mutator.max_size() - size; + if size + len > max_size { + if max_size > size { + len = max_size - size; } else { return Ok(MutationResult::Skipped); } @@ -584,12 +515,7 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesset( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytesset(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -609,12 +535,7 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesrandset( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytesrandset(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -634,12 +555,7 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytescopy( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytescopy(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -659,12 +575,7 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesswap( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_bytesswap(state: &mut S, input: &mut I) -> Result where I: Input + HasBytesVec, S: HasRand, @@ -687,18 +598,15 @@ where } /// Crossover insert mutation -pub fn mutation_crossover_insert( - mutator: &M, - +pub fn mutation_crossover_insert( state: &mut S, input: &mut I, ) -> Result where - M: HasMaxSize, C: Corpus, I: Input + HasBytesVec, R: Rand, - S: HasRand + HasCorpus, + S: HasRand + HasCorpus + HasMaxSize, { let size = input.bytes().len(); @@ -722,6 +630,7 @@ where return Ok(MutationResult::Skipped); } + let max_size = state.max_size(); let from = state.rand_mut().below(other_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; @@ -729,9 +638,9 @@ where let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let other = other_testcase.load_input()?; - if size + len > mutator.max_size() { - if mutator.max_size() > size { - len = mutator.max_size() - size; + if size + len > max_size { + if max_size > size { + len = max_size - size; } else { return Ok(MutationResult::Skipped); } @@ -745,9 +654,7 @@ where } /// Crossover replace mutation -pub fn mutation_crossover_replace( - _: &M, - +pub fn mutation_crossover_replace( state: &mut S, input: &mut I, ) -> Result @@ -808,12 +715,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { } /// Splicing mutation from AFL -pub fn mutation_splice( - _: &M, - - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_splice(state: &mut S, input: &mut I) -> Result where C: Corpus, I: Input + HasBytesVec, @@ -970,7 +872,6 @@ pub fn read_tokens_file(f: &str, tokens: &mut Vec>) -> Result usize { - 16000 as usize - } - - fn set_max_size(&mut self, _max_size: usize) { - todo!("Not needed"); - } - } - #[test] fn test_mutators() { let mut inputs = vec![ @@ -1030,16 +920,16 @@ token2="B" 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); - let mut corpus: InMemoryCorpus<_, StdRand> = InMemoryCorpus::new(); + corpus + .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> = vec![]; + let mut mutations: Vec> = vec![]; mutations.push(mutation_bitflip); mutations.push(mutation_byteflip); @@ -1072,7 +962,7 @@ token2="B" for mutation in &mutations { for input in inputs.iter() { 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::Skipped => (), }; @@ -1087,4 +977,3 @@ token2="B" */ } } -*/ diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 7192eedfb8..961e266b8c 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -1,13 +1,15 @@ -use crate::inputs::HasBytesVec; use alloc::vec::Vec; -use core::{default::Default, fmt, marker::PhantomData}; -use fmt::Debug; +use core::{ + default::Default, + fmt::{self, Debug}, + marker::PhantomData, +}; use crate::{ corpus::Corpus, - inputs::Input, - mutators::{HasMaxSize, Mutator, DEFAULT_MAX_SIZE}, - state::{HasCorpus, HasMetadata, HasRand}, + inputs::{HasBytesVec, Input}, + mutators::Mutator, + state::{HasCorpus, HasMaxSize, HasMetadata, HasRand}, utils::Rand, Error, }; @@ -31,7 +33,7 @@ where let num = self.iterations(state, input); for _ in 0..num { 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(()) } @@ -43,8 +45,7 @@ where S: HasRand, R: Rand, { - mutations: Vec>, - max_size: usize, + mutations: Vec>, phantom: PhantomData, } @@ -57,9 +58,8 @@ where fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "StdScheduledMutator with {} Mutations, max_size: {}, for Input type {}", + "StdScheduledMutator with {} Mutations for Input type {}", self.mutations.len(), - self.max_size, core::any::type_name::() ) } @@ -83,7 +83,7 @@ where R: Rand, { #[inline] - fn mutation_by_idx(&self, index: usize) -> MutationFunction { + fn mutation_by_idx(&self, index: usize) -> MutationFunction { self.mutations[index] } @@ -93,7 +93,7 @@ where } #[inline] - fn add_mutation(&mut self, mutation: MutationFunction) { + fn add_mutation(&mut self, mutation: MutationFunction) { self.mutations.push(mutation) } } @@ -116,23 +116,6 @@ where } } -impl HasMaxSize for StdScheduledMutator -where - I: Input, - S: HasRand, - 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 StdScheduledMutator where I: Input, @@ -143,16 +126,14 @@ where pub fn new() -> Self { Self { mutations: vec![], - max_size: DEFAULT_MAX_SIZE, phantom: PhantomData, } } /// Create a new StdScheduledMutator instance specifying mutations - pub fn with_mutations(mutations: Vec>) -> Self { + pub fn with_mutations(mutations: Vec>) -> Self { StdScheduledMutator { mutations: mutations, - max_size: DEFAULT_MAX_SIZE, phantom: PhantomData, } } @@ -162,9 +143,9 @@ where #[derive(Clone, Debug)] pub struct HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator, I: Input + HasBytesVec, - S: HasRand + HasCorpus + HasMetadata, + S: HasRand + HasCorpus + HasMetadata + HasMaxSize, C: Corpus, R: Rand, { @@ -174,9 +155,9 @@ where impl Mutator for HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator, I: Input + HasBytesVec, - S: HasRand + HasCorpus + HasMetadata, + S: HasRand + HasCorpus + HasMetadata + HasMaxSize, C: Corpus, R: Rand, { @@ -208,30 +189,11 @@ where } } -impl HasMaxSize for HavocBytesMutator -where - SM: ScheduledMutator + HasMaxSize, - I: Input + HasBytesVec, - S: HasRand + HasCorpus + HasMetadata, - C: Corpus, - 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 HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator, I: Input + HasBytesVec, - S: HasRand + HasCorpus + HasMetadata, + S: HasRand + HasCorpus + HasMetadata + HasMaxSize, C: Corpus, R: Rand, { @@ -249,7 +211,7 @@ where impl Default for HavocBytesMutator> where I: Input + HasBytesVec, - S: HasRand + HasCorpus + HasMetadata, + S: HasRand + HasCorpus + HasMetadata + HasMaxSize, C: Corpus, R: Rand, { diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index f0d6ff352a..1b189acebc 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -4,7 +4,7 @@ use crate::{ inputs::{HasBytesVec, Input}, mutators::*, - state::{HasMetadata, HasRand}, + state::{HasMaxSize, HasMetadata, HasRand}, utils::Rand, Error, }; @@ -30,17 +30,13 @@ impl TokensMetadata { } /// Insert a dictionary token -pub fn mutation_tokeninsert( - mutator: &M, - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_tokeninsert(state: &mut S, input: &mut I) -> Result where - M: HasMaxSize, I: Input + HasBytesVec, - S: HasMetadata + HasRand, + S: HasMetadata + HasRand + HasMaxSize, R: Rand, { + let max_size = state.max_size(); let tokens_len = { let meta = state.metadata().get::(); if meta.is_none() { @@ -60,9 +56,9 @@ where let token = &meta.tokens[token_idx]; let mut len = token.len(); - if size + len > mutator.max_size() { - if mutator.max_size() > size { - len = mutator.max_size() - size; + if size + len > max_size { + if max_size > size { + len = max_size - size; } else { return Ok(MutationResult::Skipped); } @@ -76,13 +72,8 @@ where } /// Overwrite with a dictionary token -pub fn mutation_tokenreplace( - _: &M, - state: &mut S, - input: &mut I, -) -> Result +pub fn mutation_tokenreplace(state: &mut S, input: &mut I) -> Result where - M: HasMaxSize, I: Input + HasBytesVec, S: HasMetadata + HasRand, R: Rand, diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 0bdc3dd1d1..d82b8d4e73 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -24,6 +24,9 @@ use crate::{ #[cfg(feature = "std")] use crate::inputs::bytes::BytesInput; +/// The maximum size of a testcase +pub const DEFAULT_MAX_SIZE: usize = 1048576; + /// Trait for elements offering a corpus pub trait HasCorpus where @@ -36,6 +39,14 @@ where 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 pub trait HasSolutions where @@ -204,6 +215,8 @@ where objectives: OFT, /// Metadata stored for this state by one of the components metadata: SerdeAnyMap, + /// MaxSize testcase size for mutators that appreciate it + max_size: usize, phantom: PhantomData, } @@ -362,6 +375,24 @@ where } } +impl HasMaxSize for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + fn max_size(&self) -> usize { + self.max_size + } + + fn set_max_size(&mut self, max_size: usize) { + self.max_size = max_size + } +} + impl HasStartTime for State where C: Corpus, @@ -638,6 +669,7 @@ where feedbacks, solutions, objectives, + max_size: DEFAULT_MAX_SIZE, phantom: PhantomData, } }