diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs index 40fc47785e..09009bd561 100644 --- a/afl/src/mutators/mutations.rs +++ b/afl/src/mutators/mutations.rs @@ -120,7 +120,7 @@ pub fn buffer_copy(dst: &mut [u8], src: &[u8], from: usize, to: usize, len: usiz #[inline] fn buffer_set(data: &mut [u8], from: usize, len: usize, val: u8) { debug_assert!(from + len <= data.len()); - for p in &mut data[from..from + len] { + for p in &mut data[from..(from + len)] { *p = val } } @@ -491,12 +491,20 @@ where if size == 0 { return Ok(MutationResult::Skipped); } - let off = rand.below(size as u64 - 1) as usize; - let len = rand.below(min(16, mutator.max_size() as u64 - 1) + 1) as usize; + let off = rand.below(size as u64) as usize; + let mut len = 1 + rand.below(16) 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(size + len, 0); - buffer_self_copy(input.bytes_mut(), 0, 0 + off, len); - + buffer_self_copy(input.bytes_mut(), off, off + len, size - off); + Ok(MutationResult::Mutated) } @@ -511,21 +519,25 @@ where I: Input + HasBytesVec, R: Rand, { - let mut size = input.bytes().len(); + let size = input.bytes().len(); if size == 0 { - // Generate random bytes if we're empty. - input - .bytes_mut() - .append(&mut rand.next().to_be_bytes().to_vec()); - size = input.bytes().len(); + return Ok(MutationResult::Skipped); } - let off = rand.below(size as u64 - 1) as usize; - let len = rand.below(max(16, mutator.max_size() as u64)) as usize; + let off = rand.below(size as u64) as usize; + let mut len = 1 + rand.below(16) as usize; + if size + len > mutator.max_size() { + if mutator.max_size() > size { + len = mutator.max_size() - size; + } else { + return Ok(MutationResult::Skipped); + } + } + let val = input.bytes()[rand.below(size as u64) as usize]; - input.bytes_mut().resize(max(size, off + (2 * len) + 1), 0); - buffer_self_copy(input.bytes_mut(), off, off + len, len); + input.bytes_mut().resize(size + len, 0); + buffer_self_copy(input.bytes_mut(), off, off + len, size - off); buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) @@ -542,20 +554,25 @@ where I: Input + HasBytesVec, R: Rand, { - let mut size = input.bytes().len(); + let size = input.bytes().len(); if size == 0 { - input - .bytes_mut() - .append(&mut rand.next().to_le_bytes().to_vec()); - size = input.bytes().len(); + return Ok(MutationResult::Skipped); } - let off = rand.below(size as u64 - 1) as usize; - let len = rand.below(core::cmp::min(16, mutator.max_size() as u64)) as usize; + let off = rand.below(size as u64) as usize; + let mut len = 1 + rand.below(16) as usize; + if size + len > mutator.max_size() { + if mutator.max_size() > size { + len = mutator.max_size() - size; + } else { + return Ok(MutationResult::Skipped); + } + } + let val = rand.below(256) as u8; - input.bytes_mut().resize(max(size, off + (2 * len) + 1), 0); - buffer_self_copy(input.bytes_mut(), off, off + len, len); + input.bytes_mut().resize(size + len, 0); + buffer_self_copy(input.bytes_mut(), off, off + len, size - off); buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) @@ -575,16 +592,12 @@ where if size == 0 { return Ok(MutationResult::Skipped); } + let off = rand.below(size as u64) as usize; + let len = 1 + rand.below(min(16, size - off) as u64) as usize; let val = input.bytes()[rand.below(size as u64) as usize]; - let start = if size == 1 { - 0 - } else { - rand.below(size as u64 - 1) as usize - }; - let end = rand.between(start as u64, size as u64) as usize; - buffer_set(input.bytes_mut(), start, end - start, val); + buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) } @@ -603,16 +616,12 @@ where if size == 0 { return Ok(MutationResult::Skipped); } - + let off = rand.below(size as u64) as usize; + let len = 1 + rand.below(min(16, size - off) as u64) as usize; + let val = rand.below(256) as u8; - let start = if size == 1 { - 0 - } else { - rand.below(size as u64 - 1) as usize - }; - let len = rand.below((size - start) as u64) as usize; - buffer_set(input.bytes_mut(), start, len, val); + buffer_set(input.bytes_mut(), off, len, val); Ok(MutationResult::Mutated) } @@ -632,9 +641,9 @@ where return Ok(MutationResult::Skipped); } - let from = rand.below(input.bytes().len() as u64 - 1) as usize; - let to = rand.below(input.bytes().len() as u64 - 1) as usize; - let len = rand.below((size - core::cmp::max(from, to)) as u64) as usize; + let from = rand.below(input.bytes().len() as u64) as usize; + let to = rand.below(input.bytes().len() as u64) as usize; + let len = 1 + rand.below((size - max(from, to)) as u64) as usize; buffer_self_copy(input.bytes_mut(), from, to, len); @@ -656,11 +665,11 @@ where return Ok(MutationResult::Skipped); } - let first = rand.below(input.bytes().len() as u64 - 1) as usize; - let second = rand.below(input.bytes().len() as u64 - 1) as usize; - let len = max(rand.below((size - max(first, second)) as u64) as usize, 1); + let first = rand.below(input.bytes().len() as u64) as usize; + let second = rand.below(input.bytes().len() as u64) as usize; + let len = 1 + rand.below((size - max(first, second)) as u64) as usize; - let tmp = input.bytes()[first..=first + len].to_vec(); + let tmp = input.bytes()[first..(first + len)].to_vec(); buffer_self_copy(input.bytes_mut(), second, first, len); buffer_copy(input.bytes_mut(), &tmp, 0, second, len); diff --git a/fuzzers/libfuzzer_libpng/corpus/not_kitty.png b/fuzzers/libfuzzer_libpng/corpus/not_kitty.png new file mode 100644 index 0000000000..eff7c1707b Binary files /dev/null and b/fuzzers/libfuzzer_libpng/corpus/not_kitty.png differ diff --git a/fuzzers/libfuzzer_libpng/corpus/not_kitty_alpha.png b/fuzzers/libfuzzer_libpng/corpus/not_kitty_alpha.png new file mode 100644 index 0000000000..2fb8da2c8f Binary files /dev/null and b/fuzzers/libfuzzer_libpng/corpus/not_kitty_alpha.png differ diff --git a/fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png b/fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png new file mode 100644 index 0000000000..939d9d29a9 Binary files /dev/null and b/fuzzers/libfuzzer_libpng/corpus/not_kitty_gamma.png differ diff --git a/fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png b/fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png new file mode 100644 index 0000000000..f0c7804d99 Binary files /dev/null and b/fuzzers/libfuzzer_libpng/corpus/not_kitty_icc.png differ diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index d18702a311..c8f120c1a9 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -1,12 +1,8 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -#[macro_use] -extern crate clap; - // extern crate libc; -use clap::{App, Arg}; use std::{env, path::PathBuf}; use afl::{ @@ -55,69 +51,12 @@ where /// The main fn, parsing parameters, and starting the fuzzer pub fn main() { - let matches = App::new("libAFLrs fuzzer harness") - .about("libAFLrs fuzzer harness help options.") - .arg( - Arg::with_name("port") - .short("p") - .value_name("PORT") - .takes_value(true) - .help("Broker TCP port to use."), - ) - .arg( - Arg::with_name("dictionary") - .short("x") - .value_name("DICTIONARY") - .takes_value(true) - .multiple(true) - .help("Dictionary file to use, can be specified multiple times."), - ) - .arg( - Arg::with_name("statstime") - .short("T") - .value_name("STATSTIME") - .takes_value(true) - .help("How often to print statistics in seconds [default: 5, disable: 0]"), - ) - .arg(Arg::with_name("workdir") - .help("Where to write the corpus, also reads the data on start. If more than one is supplied the first will be the work directory, all others will just be initially read from.") - .multiple(true) - .value_name("WORKDIR") - ) - .get_matches(); - - let _ = value_t!(matches, "statstime", u32).unwrap_or(5); - let broker_port = value_t!(matches, "port", u16).unwrap_or(1337); - - let workdir = if matches.is_present("workdir") { - matches.value_of("workdir").unwrap().to_string() - } else { - env::current_dir().unwrap().to_string_lossy().to_string() - }; - - let mut dictionary: Option> = None; - - if matches.is_present("dictionary") { - dictionary = Some(values_t!(matches, "dictionary", PathBuf).unwrap_or_else(|e| e.exit())); - } - - let mut input: Option> = None; - if matches.is_present("workdir") { - input = Some(values_t!(matches, "workdir", PathBuf).unwrap_or_else(|e| e.exit())); - } - - if dictionary != None || input != None { - println!("Information: the first process started is the broker and only processes the \'-p PORT\' option if present."); - } - - println!("Workdir: {:?}", workdir); - - fuzz(Some(vec![PathBuf::from("./in1")]), broker_port).expect("An error occurred while fuzzing"); - //fuzz(input, broker_port).expect("An error occurred while fuzzing"); + println!("Workdir: {:?}", env::current_dir().unwrap().to_string_lossy().to_string()); + fuzz(vec![PathBuf::from("./corpus")], 1337).expect("An error occurred while fuzzing"); } /// The actual fuzzer -fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { +fn fuzz(corpus_dirs: Vec, broker_port: u16) -> Result<(), AflError> { let mut rand = StdRand::new(0); // 'While the stats are state, they are usually used in the broker - which is likely never restarted let stats = SimpleStats::new(|s| println!("{}", s)); @@ -165,36 +104,13 @@ fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { } } - /* - // TODO close fds in a rusty way - unsafe { - let null_fname = std::ffi::CString::new("/dev/null").unwrap(); - let null_file = libc::open(null_fname.as_ptr(), libc::O_RDWR); - libc::dup2(null_file, 1); - libc::dup2(null_file, 2); - } - */ - // in case the corpus is empty (on first run), reset if state.corpus().count() < 1 { - match input { - Some(x) => state - .load_initial_inputs(&mut executor, &mut restarting_mgr, &x) - .expect(&format!("Failed to load initial corpus at {:?}", &x)), - None => (), - } + state + .load_initial_inputs(&mut executor, &mut restarting_mgr, &corpus_dirs) + .expect(&format!("Failed to load initial corpus at {:?}", &corpus_dirs)); println!("We imported {} inputs from disk.", state.corpus().count()); } - /* - if state.corpus().count() < 1 { - println!("Generating random inputs"); - let mut generator = RandPrintablesGenerator::new(32); - state - .generate_initial_inputs(&mut rand, &mut executor, &mut generator, &mut restarting_mgr, 4) - .expect("Failed to generate initial inputs"); - println!("We generated {} inputs.", state.corpus().count()); - } - */ fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr) } diff --git a/fuzzers/libfuzzer_libpng/test.sh b/fuzzers/libfuzzer_libpng/test.sh old mode 100644 new mode 100755 index c115d14436..5f5b2b7176 --- a/fuzzers/libfuzzer_libpng/test.sh +++ b/fuzzers/libfuzzer_libpng/test.sh @@ -1,18 +1,8 @@ #!/bin/sh cargo build --release || exit 1 -cp ./target/release/libfuzzer ./.libfuzzer_test.elf +cp ../../target/release/libfuzzer ./.libfuzzer_test.elf -RUST_BACKTRACE=full taskset -c 0 ./.libfuzzer_test.elf & +RUST_BACKTRACE=full ./.libfuzzer_test.elf -test "$!" -gt 0 && { - - usleep 250 - RUST_BACKTRACE=full taskset -c 1 ./.libfuzzer_test.elf & - -} - -sleep 20 -echo "[+] Done" -killall .libfuzzer_test.elf rm -rf ./.libfuzzer_test.elf