diff --git a/Cargo.toml b/Cargo.toml index 306fabede1..1c364ac8eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,5 @@ members = [ #example fuzzers "fuzzers/libfuzzer_libpng", "fuzzers/libfuzzer_libmozjpeg", + "fuzzers/libfuzzer_libpng_cmpalloc", ] diff --git a/README.md b/README.md index 0ff353378b..290967aae0 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ We're still working on the documentation. In the meantime, you can watch the Vid + ~~Minset corpus scheduler~~ still doc missing + Win32 shared mem and crash handler to have Windows in-process executor -+ Other feedbacks examples (e.g. maximize allocations to spot OOMs) ++ ~~Other feedbacks examples (e.g. maximize allocations to spot OOMs)~~ + Other objectives examples (e.g. execution of a given program point) + ~~A macro crate with derive directives (e.g. for SerdeAny impl)~~ just `derive(SerdeAny)`, missing doc. + Good documentation diff --git a/TODO.md b/TODO.md index c5a59e1a49..92c16f6403 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,7 @@ - [x] ~~Minset corpus scheduler~~ still doc missing - [ ] Win32 shared mem and crash handler to have Windows in-process executor -- [ ] Other feedbacks examples (e.g. maximize allocations to spot OOMs) +- [x] Other feedbacks examples (e.g. maximize allocations to spot OOMs) - [ ] Other objectives examples (e.g. execution of a given program point) - [ ] Objective-Specific Corpuses (named per objective) - [x] A macro crate with derive directives (e.g. for SerdeAny impl). diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/.gitignore b/fuzzers/libfuzzer_libpng_cmpalloc/.gitignore new file mode 100644 index 0000000000..a977a2ca5b --- /dev/null +++ b/fuzzers/libfuzzer_libpng_cmpalloc/.gitignore @@ -0,0 +1 @@ +libpng-* \ No newline at end of file diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/Cargo.toml b/fuzzers/libfuzzer_libpng_cmpalloc/Cargo.toml new file mode 100644 index 0000000000..16e498bb93 --- /dev/null +++ b/fuzzers/libfuzzer_libpng_cmpalloc/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "libfuzzer_libpng_cmpalloc" +version = "0.1.0" +authors = ["Andrea Fioraldi ", "Dominik Maier "] +edition = "2018" +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +default = ["std"] +std = [] + +#[profile.release] +#lto = true +#codegen-units = 1 +#opt-level = 3 +#debug = true + +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +num_cpus = "1.0" + +[dependencies] +libafl = { path = "../../libafl/" } + +[[example]] +name = "libfuzzer_libpng_cmpalloc" +path = "./src/fuzzer.rs" +test = false +bench = false diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/README.md b/fuzzers/libfuzzer_libpng_cmpalloc/README.md new file mode 100644 index 0000000000..bfd858fbcb --- /dev/null +++ b/fuzzers/libfuzzer_libpng_cmpalloc/README.md @@ -0,0 +1,28 @@ +# Libfuzzer for libpng (cmp+alloc) + +This folder contains an example fuzzer for libpng, using LLMP for fast multi-process fuzzing and crash detection. +To show off crash detection, we added a ud2 instruction to the harness, edit harness.cc if you want a non-crashing example. +It has been tested on Linux. + +The difference between the normal Libfuzzer for libpng example here is that this fuzzer is not just using edge coverage as feedback but also comparisons values (-value-profile like) and allocations sizes. +This is an example how multiple feedbacks can be combined in a fuzzer. + +## Build + +To build this example, run `cargo build --example libfuzzer_libpng_cmpalloc --release`. +This will call (the build.rs)[./builld.rs], which in turn downloads a libpng archive from the web. +Then, it will link (the fuzzer)[./src/fuzzer.rs] against (the C++ harness)[./harness.cc] and the instrumented `libpng`. +Afterwards, the fuzzer will be ready to run, from `../../target/examples/libfuzzer_libpng_cmpalloc`. + +## Run + +The first time you run the binary, the broker will open a tcp port (currently on port `1337`), waiting for fuzzer clients to connect. This port is local and only used for the initial handshake. All further communication happens via shared map, to be independent of the kernel. + +Each following execution will run a fuzzer client. +As this example uses in-process fuzzing, we added a Restarting Event Manager (`setup_restarting_mgr`). +This means each client will start itself again to listen for crashes and timeouts. +By restarting the actual fuzzer, it can recover from these exit conditions. + +In any real-world scenario, you should use `taskset` to pin each client to an empty CPU core, the lib does not pick an empty core automatically (yet). + +For convenience, you may just run `./test.sh` in this folder to test it. diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/build.rs b/fuzzers/libfuzzer_libpng_cmpalloc/build.rs new file mode 100644 index 0000000000..49f3cfba94 --- /dev/null +++ b/fuzzers/libfuzzer_libpng_cmpalloc/build.rs @@ -0,0 +1,109 @@ +// build.rs + +use std::{ + env, + path::Path, + process::{exit, Command}, +}; + +const LIBPNG_URL: &str = + "https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz"; + +fn main() { + if cfg!(windows) { + println!("cargo:warning=Skipping libpng example on Windows"); + exit(0); + } + + let out_dir = env::var_os("OUT_DIR").unwrap(); + let cwd = env::current_dir().unwrap().to_string_lossy().to_string(); + let out_dir = out_dir.to_string_lossy().to_string(); + let out_dir_path = Path::new(&out_dir); + + println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",); + println!("cargo:rerun-if-changed=harness.cc"); + + let libpng = format!("{}/libpng-1.6.37", &out_dir); + let libpng_path = Path::new(&libpng); + let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd); + + // Enforce clang for its -fsanitize-coverage support. + std::env::set_var("CC", "clang"); + std::env::set_var("CXX", "clang++"); + let ldflags = match env::var("LDFLAGS") { + Ok(val) => val, + Err(_) => "".to_string(), + }; + + if !libpng_path.is_dir() { + if !Path::new(&libpng_tar).is_file() { + println!("cargo:warning=Libpng not found, downloading..."); + // Download libpng + Command::new("wget") + .arg("-c") + .arg(LIBPNG_URL) + .arg("-O") + .arg(&libpng_tar) + .status() + .unwrap(); + } + Command::new("tar") + .current_dir(&out_dir_path) + .arg("-xvf") + .arg(&libpng_tar) + .status() + .unwrap(); + Command::new(format!("{}/configure", &libpng)) + .current_dir(&libpng_path) + .args(&[ + "--disable-shared", + &format!("--host={}", env::var("TARGET").unwrap())[..], + ]) + .env("CC", "clang") + .env("CXX", "clang++") + .env( + "CFLAGS", + "-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard", + ) + .env( + "CXXFLAGS", + "-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard", + ) + .env( + "LDFLAGS", + format!("-g -fPIE -fsanitize-coverage=trace-pc-guard {}", ldflags), + ) + .status() + .unwrap(); + Command::new("make") + .current_dir(&libpng_path) + .status() + .unwrap(); + } + + cc::Build::new() + .file("../libfuzzer_runtime/rt.c") + .compile("libfuzzer-sys"); + + cc::Build::new() + .include(&libpng_path) + .cpp(true) + .flag("-fsanitize-coverage=trace-pc-guard") + // .define("HAS_DUMMY_CRASH", "1") + .file("./harness.cc") + .compile("libfuzzer-harness"); + + println!("cargo:rustc-link-search=native={}", &out_dir); + println!("cargo:rustc-link-search=native={}/.libs", &libpng); + println!("cargo:rustc-link-lib=static=png16"); + + //Deps for libpng: -pthread -lz -lm + println!("cargo:rustc-link-lib=dylib=m"); + println!("cargo:rustc-link-lib=dylib=z"); + + //For the C++ harness + //must by dylib for android + println!("cargo:rustc-link-lib=dylib=stdc++"); + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty.png b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty.png new file mode 100644 index 0000000000..eff7c1707b Binary files /dev/null and b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty.png differ diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_alpha.png b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_alpha.png new file mode 100644 index 0000000000..2fb8da2c8f Binary files /dev/null and b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_alpha.png differ diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_gamma.png b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_gamma.png new file mode 100644 index 0000000000..939d9d29a9 Binary files /dev/null and b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_gamma.png differ diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_icc.png b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_icc.png new file mode 100644 index 0000000000..f0c7804d99 Binary files /dev/null and b/fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_icc.png differ diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/harness.cc b/fuzzers/libfuzzer_libpng_cmpalloc/harness.cc new file mode 100644 index 0000000000..65faff685d --- /dev/null +++ b/fuzzers/libfuzzer_libpng_cmpalloc/harness.cc @@ -0,0 +1,197 @@ +// libpng_read_fuzzer.cc +// Copyright 2017-2018 Glenn Randers-Pehrson +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that may +// be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE + +// Last changed in libpng 1.6.35 [July 15, 2018] + +// The modifications in 2017 by Glenn Randers-Pehrson include +// 1. addition of a PNG_CLEANUP macro, +// 2. setting the option to ignore ADLER32 checksums, +// 3. adding "#include " which is needed on some platforms +// to provide memcpy(). +// 4. adding read_end_info() and creating an end_info structure. +// 5. adding calls to png_set_*() transforms commonly used by browsers. + +#include +#include +#include + +#include + +#define PNG_INTERNAL +#include "png.h" + +#define PNG_CLEANUP \ + if(png_handler.png_ptr) \ + { \ + if (png_handler.row_ptr) \ + png_free(png_handler.png_ptr, png_handler.row_ptr); \ + if (png_handler.end_info_ptr) \ + png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ + &png_handler.end_info_ptr); \ + else if (png_handler.info_ptr) \ + png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ + nullptr); \ + else \ + png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \ + png_handler.png_ptr = nullptr; \ + png_handler.row_ptr = nullptr; \ + png_handler.info_ptr = nullptr; \ + png_handler.end_info_ptr = nullptr; \ + } + +struct BufState { + const uint8_t* data; + size_t bytes_left; +}; + +struct PngObjectHandler { + png_infop info_ptr = nullptr; + png_structp png_ptr = nullptr; + png_infop end_info_ptr = nullptr; + png_voidp row_ptr = nullptr; + BufState* buf_state = nullptr; + + ~PngObjectHandler() { + if (row_ptr) + png_free(png_ptr, row_ptr); + if (end_info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); + else if (info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + else + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + delete buf_state; + } +}; + +void user_read_data(png_structp png_ptr, png_bytep data, size_t length) { + BufState* buf_state = static_cast(png_get_io_ptr(png_ptr)); + if (length > buf_state->bytes_left) { + png_error(png_ptr, "read error"); + } + memcpy(data, buf_state->data, length); + buf_state->bytes_left -= length; + buf_state->data += length; +} + +static const int kPngHeaderSize = 8; + +// Entry point for LibFuzzer. +// Roughly follows the libpng book example: +// http://www.libpng.org/pub/png/book/chapter13.html +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < kPngHeaderSize) { + return 0; + } + + std::vector v(data, data + size); + if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { + // not a PNG. + return 0; + } + + PngObjectHandler png_handler; + png_handler.png_ptr = nullptr; + png_handler.row_ptr = nullptr; + png_handler.info_ptr = nullptr; + png_handler.end_info_ptr = nullptr; + + png_handler.png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_handler.png_ptr) { + return 0; + } + + png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.info_ptr) { + PNG_CLEANUP + return 0; + } + + png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.end_info_ptr) { + PNG_CLEANUP + return 0; + } + + png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); +#ifdef PNG_IGNORE_ADLER32 + png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); +#endif + + // Setting up reading from buffer. + png_handler.buf_state = new BufState(); + png_handler.buf_state->data = data + kPngHeaderSize; + png_handler.buf_state->bytes_left = size - kPngHeaderSize; + png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); + png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); + + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + // Reading. + png_read_info(png_handler.png_ptr, png_handler.info_ptr); + + // reset error handler to put png_deleter into scope. + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type; + int filter_type; + + if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, + &height, &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type)) { + PNG_CLEANUP + return 0; + } + + // This is going to be too slow. + if (width && height > 100000000 / width) { + PNG_CLEANUP +#ifdef HAS_DUMMY_CRASH + #ifdef __aarch64__ + asm volatile (".word 0xf7f0a000\n"); + #else + asm("ud2"); + #endif +#endif + return 0; + } + + // Set several transforms that browsers typically use: + png_set_gray_to_rgb(png_handler.png_ptr); + png_set_expand(png_handler.png_ptr); + png_set_packing(png_handler.png_ptr); + png_set_scale_16(png_handler.png_ptr); + png_set_tRNS_to_alpha(png_handler.png_ptr); + + int passes = png_set_interlace_handling(png_handler.png_ptr); + + png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); + + png_handler.row_ptr = png_malloc( + png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, + png_handler.info_ptr)); + + for (int pass = 0; pass < passes; ++pass) { + for (png_uint_32 y = 0; y < height; ++y) { + png_read_row(png_handler.png_ptr, + static_cast(png_handler.row_ptr), nullptr); + } + } + + png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); + + PNG_CLEANUP + return 0; +} + diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/src/fuzzer.rs b/fuzzers/libfuzzer_libpng_cmpalloc/src/fuzzer.rs new file mode 100644 index 0000000000..58215afc63 --- /dev/null +++ b/fuzzers/libfuzzer_libpng_cmpalloc/src/fuzzer.rs @@ -0,0 +1,199 @@ +//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts +//! The example harness is built for libpng. + +use std::{env, path::PathBuf}; + +#[cfg(unix)] +use libafl::{ + bolts::{shmem::UnixShMem, tuples::tuple_list}, + corpus::{ + Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, + QueueCorpusScheduler, + }, + events::setup_restarting_mgr, + executors::{inprocess::InProcessExecutor, Executor, ExitKind}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, + fuzzer::{Fuzzer, HasCorpusScheduler, StdFuzzer}, + inputs::Input, + mutators::{scheduled::HavocBytesMutator, token_mutations::Tokens}, + observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + stages::mutational::StdMutationalStage, + state::{HasCorpus, HasMetadata, State}, + stats::SimpleStats, + utils::{current_nanos, StdRand}, + Error, +}; + +const MAP_SIZE: usize = 16 * 1024; + +/// We will interact with a C++ target, so use external c functionality +#[cfg(unix)] +extern "C" { + /// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) + fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32; + + // afl_libfuzzer_init calls LLVMFUzzerInitialize() + fn afl_libfuzzer_init() -> i32; + + static __lafl_edges_map: *mut u8; + static __lafl_cmp_map: *mut u8; + static __lafl_alloc_map: *mut usize; + static __lafl_max_edges_size: u32; +} + +/// The wrapped harness function, calling out to the LLVM-style harness +#[cfg(unix)] +fn harness(_executor: &E, buf: &[u8]) -> ExitKind +where + E: Executor, + I: Input, +{ + // println!("{:?}", buf); + unsafe { + LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()); + } + ExitKind::Ok +} + +/// The main fn, usually parsing parameters, and starting the fuzzer +pub fn main() { + // Registry the metadata types used in this fuzzer + // Needed only on no_std + //RegistryBuilder::register::(); + + println!( + "Workdir: {:?}", + env::current_dir().unwrap().to_string_lossy().to_string() + ); + fuzz( + vec![PathBuf::from("./corpus")], + PathBuf::from("./crashes"), + 1337, + ) + .expect("An error occurred while fuzzing"); +} + +/// Not supported on windows right now +#[cfg(windows)] +fn fuzz(_corpus_dirs: Vec, _objective_dir: PathBuf, _broker_port: u16) -> Result<(), ()> { + todo!("Example not supported on Windows"); +} + +/// The actual fuzzer +#[cfg(unix)] +fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> { + // '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 restarted it each time it crashes. + let (state, mut restarting_mgr) = + match setup_restarting_mgr::<_, _, UnixShMem, _>(stats, broker_port) { + Ok(res) => res, + Err(err) => match err { + Error::ShuttingDown => { + return Ok(()); + } + _ => { + panic!("Failed to setup the restarter: {}", err); + } + }, + }; + + // Create an observation channel using the coverage map + let edges_observer = HitcountsMapObserver::new(unsafe { + StdMapObserver::new_from_ptr("edges", __lafl_edges_map, __lafl_max_edges_size as usize) + }); + + // Create an observation channel using the cmp map + let cmps_observer = unsafe { StdMapObserver::new_from_ptr("cmps", __lafl_cmp_map, MAP_SIZE) }; + + // Create an observation channel using the allocations map + let allocs_observer = + unsafe { StdMapObserver::new_from_ptr("allocs", __lafl_alloc_map, MAP_SIZE) }; + + // If not restarting, create a State from scratch + let mut state = state.unwrap_or_else(|| { + State::new( + // RNG + StdRand::with_seed(current_nanos()), + // Corpus that will be evolved, we keep it in memory for performance + InMemoryCorpus::new(), + // Feedbacks to rate the interestingness of an input + tuple_list!( + MaxMapFeedback::new_with_observer_track(&edges_observer, true, false), + MaxMapFeedback::new_with_observer(&cmps_observer), + MaxMapFeedback::new_with_observer(&allocs_observer), + TimeFeedback::new() + ), + // Corpus in which we store solutions (crashes in this example), + // on disk so the user can get them after stopping the fuzzer + OnDiskCorpus::new(objective_dir).unwrap(), + // Feedbacks to recognize an input as solution + tuple_list!(CrashFeedback::new()), + ) + }); + + println!("We're a client, let's fuzz :)"); + + // Create a PNG dictionary if not existing + if state.metadata().get::().is_none() { + state.add_metadata(Tokens::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::default(); + let stage = StdMutationalStage::new(mutator); + + // A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus + let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new()); + let fuzzer = StdFuzzer::new(scheduler, tuple_list!(stage)); + + // Create the executor for an in-process function with just one observer for edge coverage + let mut executor = InProcessExecutor::new( + "in-process(edges,cmps,allocs)", + harness, + tuple_list!( + edges_observer, + cmps_observer, + allocs_observer, + TimeObserver::new("time") + ), + &mut state, + &mut restarting_mgr, + )?; + + // The actual target run starts here. + // Call LLVMFUzzerInitialize() if present. + unsafe { + if afl_libfuzzer_init() == -1 { + println!("Warning: LLVMFuzzerInitialize failed with -1") + } + } + + // In case the corpus is empty (on first run), reset + if state.corpus().count() < 1 { + state + .load_initial_inputs( + &mut executor, + &mut restarting_mgr, + fuzzer.scheduler(), + &corpus_dirs, + ) + .expect(&format!( + "Failed to load initial corpus at {:?}", + &corpus_dirs + )); + println!("We imported {} inputs from disk.", state.corpus().count()); + } + + fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?; + + // Never reached + Ok(()) +} diff --git a/fuzzers/libfuzzer_libpng_cmpalloc/test.sh b/fuzzers/libfuzzer_libpng_cmpalloc/test.sh new file mode 100755 index 0000000000..f707f77271 --- /dev/null +++ b/fuzzers/libfuzzer_libpng_cmpalloc/test.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +mkdir -p ./crashes + +cargo build --example libfuzzer_libpng --release || exit 1 +cp ../../target/release/examples/libfuzzer_libpng ./.libfuzzer_test.elf + +# The broker +RUST_BACKTRACE=full taskset 0 ./.libfuzzer_test.elf & +# Give the broker time to spawn +sleep 2 +echo "Spawning client" +# The 1st fuzzer client, pin to cpu 0x1 +RUST_BACKTRACE=full taskset 1 ./.libfuzzer_test.elf 2>/dev/null + +killall .libfuzzer_test.elf +rm -rf ./.libfuzzer_test.elf diff --git a/fuzzers/libfuzzer_runtime/rt.c b/fuzzers/libfuzzer_runtime/rt.c index 21c308a8d4..8379132732 100644 --- a/fuzzers/libfuzzer_runtime/rt.c +++ b/fuzzers/libfuzzer_runtime/rt.c @@ -3,7 +3,7 @@ #include #include -#define MAP_SIZE 65536 +#define MAP_SIZE (16*1024) int orig_argc; char **orig_argv; @@ -156,9 +156,10 @@ void *calloc(size_t nmemb, size_t size) { k &= MAP_SIZE - 1; __lafl_alloc_map[k] = MAX(__lafl_alloc_map[k], size); - void *result = realloc(NULL, size); - memset(result, 0, size); - return result; + void *ret = NULL; + posix_memalign(&ret, 1<<6, size); + memset(ret, 0, size); + return ret; }