diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs index d9d70b49e1..b43963370d 100644 --- a/afl/src/mutators/mutations.rs +++ b/afl/src/mutators/mutations.rs @@ -488,10 +488,7 @@ where R: Rand, { let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - let off = rand.below(size as u64) as usize; + let off = rand.below((size +1) as u64) as usize; let mut len = 1 + rand.below(16) as usize; if size + len > mutator.max_size() { @@ -520,10 +517,7 @@ where R: Rand, { let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - let off = rand.below(size as u64) as usize; + let off = rand.below((size +1) as u64) as usize; let mut len = 1 + rand.below(16) as usize; if size + len > mutator.max_size() { @@ -555,10 +549,7 @@ where R: Rand, { let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - let off = rand.below(size as u64) as usize; + let off = rand.below((size +1) as u64) as usize; let mut len = 1 + rand.below(16) as usize; if size + len > mutator.max_size() { @@ -678,12 +669,13 @@ where /// Crossover insert mutation pub fn mutation_crossover_insert( - _: &mut M, + mutator: &mut M, rand: &mut R, state: &mut S, input: &mut I, ) -> Result where + M: HasMaxSize, C: Corpus, I: Input + HasBytesVec, R: Rand, @@ -705,12 +697,20 @@ where return Ok(MutationResult::Skipped); } - let from = rand.below(other_size as u64 - 1) as usize; - let to = rand.below(size as u64 - 1) as usize; - let len = rand.below((other_size - from) as u64) as usize; + let from = rand.below(other_size as u64) as usize; + let to = rand.below(size as u64) as usize; + let mut len = rand.below((other_size - from) as u64) as usize; + + if size + len > mutator.max_size() { + if mutator.max_size() > size { + len = mutator.max_size() - size; + } else { + return Ok(MutationResult::Skipped); + } + } - input.bytes_mut().resize(max(size, to + (2 * len) + 1), 0); - buffer_self_copy(input.bytes_mut(), to, to + len, len); + input.bytes_mut().resize(size + len, 0); + buffer_self_copy(input.bytes_mut(), to, to + len, size - to); buffer_copy(input.bytes_mut(), other.bytes(), from, to, len); Ok(MutationResult::Mutated) @@ -745,9 +745,9 @@ where return Ok(MutationResult::Skipped); } - let from = rand.below(other_size as u64 - 1) as usize; + let from = rand.below(other_size as u64) as usize; let len = rand.below(min(other_size - from, size) as u64) as usize; - let to = rand.below((size - len) as u64 - 1) as usize; + let to = rand.below((size - len) as u64) as usize; buffer_copy(input.bytes_mut(), other.bytes(), from, to, len); diff --git a/afl/src/mutators/scheduled.rs b/afl/src/mutators/scheduled.rs index f402a46bd9..22a510f286 100644 --- a/afl/src/mutators/scheduled.rs +++ b/afl/src/mutators/scheduled.rs @@ -303,9 +303,8 @@ where scheduled.add_mutation(mutation_bytescopy); scheduled.add_mutation(mutation_bytesswap); - /* TODO scheduled.add_mutation(mutation_tokeninsert); - scheduled.add_mutation(mutation_tokenreplace); + /*scheduled.add_mutation(mutation_tokenreplace); */ scheduled.add_mutation(mutation_crossover_insert); diff --git a/afl/src/mutators/token_mutations.rs b/afl/src/mutators/token_mutations.rs index 6a2eebe013..93bd0fe9db 100644 --- a/afl/src/mutators/token_mutations.rs +++ b/afl/src/mutators/token_mutations.rs @@ -30,6 +30,14 @@ impl SerdeAny for TokensMetadata { } } +impl TokensMetadata { + pub fn new(tokens: Vec>) -> Self { + Self { + tokens: tokens + } + } +} + /// Insert a dictionary token pub fn mutation_tokeninsert( mutator: &mut M, @@ -56,36 +64,43 @@ where return Ok(MutationResult::Skipped); } let token = &meta.tokens[rand.below(meta.tokens.len() as u64) as usize]; - let token_len = token.len(); + let size = input.bytes().len(); - let off = if size == 0 { - 0 - } else { - rand.below(core::cmp::min( - size as u64, - (mutator.max_size() - token_len) as u64, - )) as usize - } as usize; + let off = rand.below((size +1) as u64) as usize; + let mut len = token.len(); - input.bytes_mut().resize(size + token_len, 0); - buffer_copy(input.bytes_mut(), token, 0, off, size); + if size + len > mutator.max_size() { + if mutator.max_size() > size { + len = mutator.max_size() - size; + } else { + return Ok(MutationResult::Skipped); + } + } + input.bytes_mut().resize(size + len, 0); + buffer_self_copy(input.bytes_mut(), off, off + len, size - off); + buffer_copy(input.bytes_mut(), token, 0, off, len); + Ok(MutationResult::Mutated) } /// Overwrite with a dictionary token pub fn mutation_tokenreplace( - mutator: &mut M, + _: &mut M, rand: &mut R, state: &S, input: &mut I, ) -> Result where - M: HasMaxSize, I: Input + HasBytesVec, R: Rand, S: HasMetadata, { + let size = input.bytes().len(); + if size == 0 { + return Ok(MutationResult::Skipped); + } + let meta; match state.metadata().get::() { Some(t) => { @@ -99,11 +114,15 @@ where return Ok(MutationResult::Skipped); } let token = &meta.tokens[rand.below(meta.tokens.len() as u64) as usize]; - let token_len = token.len(); - let size = input.bytes().len(); - let off = rand.below((mutator.max_size() - token_len) as u64) as usize; + + let off = rand.below(size as u64) as usize; + + let mut len = token.len(); + if off + len > size { + len = size - off; + } - buffer_copy(input.bytes_mut(), token, 0, off, size); + buffer_copy(input.bytes_mut(), token, 0, off, len); Ok(MutationResult::Mutated) } diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index fe2646db5b..aa649261f6 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -1,12 +1,10 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -// extern crate libc; - use std::{env, path::PathBuf}; use afl::{ - bolts::{shmem::AflShmem, tuples::tuple_list}, + bolts::{shmem::AflShmem, tuples::tuple_list, serdeany::RegistryBuilder}, corpus::{Corpus, InMemoryCorpus}, events::setup_restarting_mgr, events::SimpleStats, @@ -14,9 +12,10 @@ use afl::{ feedbacks::MaxMapFeedback, inputs::Input, mutators::scheduled::HavocBytesMutator, + mutators::token_mutations::TokensMetadata, observers::StdMapObserver, stages::mutational::StdMutationalStage, - state::{HasCorpus, State}, + state::{HasCorpus, HasMetadata, State}, utils::StdRand, AflError, Fuzzer, StdFuzzer, }; @@ -43,6 +42,7 @@ where E: Executor, I: Input, { + // println!("{:?}", buf); unsafe { LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()); } @@ -51,6 +51,10 @@ where /// The main fn, parsing parameters, and starting the fuzzer pub fn main() { + // Registry the metadata types used in this fuzzer + RegistryBuilder::register::(); + RegistryBuilder::finalize(); + println!( "Workdir: {:?}", env::current_dir().unwrap().to_string_lossy().to_string() @@ -64,16 +68,18 @@ fn fuzz(corpus_dirs: Vec, broker_port: u16) -> Result<(), AflError> { // 'While the stats are state, they are usually used in the broker - which is likely never restarted let stats = SimpleStats::new(|s| println!("{}", s)); - // The restarting state will spawn the same process again as child, then restartet it each time it crashes. + // The restarting state will spawn the same process again as child, then restarted it each time it crashes. let (state, mut restarting_mgr) = setup_restarting_mgr::<_, _, _, _, AflShmem, _>(stats, broker_port) .expect("Failed to setup the restarter".into()); + // Create an observation channel using the coverage map let edges_observer = StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe { __lafl_max_edges_size as usize }); + // If not retsrating, create a State from scratch let mut state = state.unwrap_or(State::new( InMemoryCorpus::new(), tuple_list!(MaxMapFeedback::new_with_observer( @@ -84,6 +90,20 @@ fn fuzz(corpus_dirs: Vec, broker_port: u16) -> Result<(), AflError> { println!("We're a client, let's fuzz :)"); + // Create a PNG dictionary of not existing + if state.metadata().get::().is_none() { + state.add_metadata(TokensMetadata::new( + vec![ + vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header + "IHDR".as_bytes().to_vec(), + "IDAT".as_bytes().to_vec(), + "PLTE".as_bytes().to_vec(), + "IEND".as_bytes().to_vec(), + ] + )); + } + + // Setup a basic mutator with a mutational stage let mutator = HavocBytesMutator::new_default(); let stage = StdMutationalStage::new(mutator); let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); @@ -98,7 +118,6 @@ fn fuzz(corpus_dirs: Vec, broker_port: u16) -> Result<(), AflError> { ); // The actual target run starts here. - // Call LLVMFUzzerInitialize() if present. unsafe { if afl_libfuzzer_init() == -1 {