diff --git a/Cargo.toml b/Cargo.toml index 519d09a76f..cc9355c666 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,12 +12,13 @@ members = [ "libafl_targets", #example fuzzers - "fuzzers/frida_libpng", "fuzzers/libfuzzer_libmozjpeg", "fuzzers/libfuzzer_libpng_cmpalloc", "fuzzers/libfuzzer_windows", ] exclude = [ "fuzzers/libfuzzer_libpng", - "fuzzers/libfuzzer_stb_image", + "fuzzers/libfuzzer_stb_image", + "fuzzers/frida_libpng", + "fuzzers/qemu_user", ] diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index 2fd07e7c74..4fe870bfdc 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -5,18 +5,16 @@ authors = ["Andrea Fioraldi ", "Dominik Maier ", "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" -path = "./src/fuzzer.rs" -test = false -bench = false diff --git a/fuzzers/libfuzzer_libpng_old/README.md b/fuzzers/libfuzzer_libpng_old/README.md deleted file mode 100644 index f56138c2b5..0000000000 --- a/fuzzers/libfuzzer_libpng_old/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Libfuzzer for libpng - -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. - -## Build - -To build this example, run `cargo build --example libfuzzer_libpng --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`. - -## 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_old/build.rs b/fuzzers/libfuzzer_libpng_old/build.rs deleted file mode 100644 index 5e68b3bc46..0000000000 --- a/fuzzers/libfuzzer_libpng_old/build.rs +++ /dev/null @@ -1,113 +0,0 @@ -// 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") - .flag("-Wno-void-pointer-to-int-cast") - .flag("-Wno-int-to-pointer-cast") - .flag("-Wno-sign-compare") - .flag("-Wno-format") - // .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_old/corpus/not_kitty.png b/fuzzers/libfuzzer_libpng_old/corpus/not_kitty.png deleted file mode 100644 index eff7c1707b..0000000000 Binary files a/fuzzers/libfuzzer_libpng_old/corpus/not_kitty.png and /dev/null differ diff --git a/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_alpha.png b/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_alpha.png deleted file mode 100644 index 2fb8da2c8f..0000000000 Binary files a/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_alpha.png and /dev/null differ diff --git a/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_gamma.png b/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_gamma.png deleted file mode 100644 index 939d9d29a9..0000000000 Binary files a/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_gamma.png and /dev/null differ diff --git a/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_icc.png b/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_icc.png deleted file mode 100644 index f0c7804d99..0000000000 Binary files a/fuzzers/libfuzzer_libpng_old/corpus/not_kitty_icc.png and /dev/null differ diff --git a/fuzzers/libfuzzer_libpng_old/harness.cc b/fuzzers/libfuzzer_libpng_old/harness.cc deleted file mode 100644 index 65faff685d..0000000000 --- a/fuzzers/libfuzzer_libpng_old/harness.cc +++ /dev/null @@ -1,197 +0,0 @@ -// 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_old/src/fuzzer.rs b/fuzzers/libfuzzer_libpng_old/src/fuzzer.rs deleted file mode 100644 index 8653a61586..0000000000 --- a/fuzzers/libfuzzer_libpng_old/src/fuzzer.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts -//! The example harness is built for libpng. - -#[cfg(unix)] -use core::time::Duration; -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, ExitKind, TimeoutExecutor}, - feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, - fuzzer::{Fuzzer, StdFuzzer}, - mutators::{scheduled::HavocBytesMutator, token_mutations::Tokens}, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, - stages::mutational::StdMutationalStage, - state::{HasCorpus, HasMetadata, State}, - stats::SimpleStats, - utils::{current_nanos, StdRand}, - Error, -}; - -/// 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_max_edges_size: u32; -} - -/// 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) - }); - - // 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), - 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(), TimeoutFeedback::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 = StdScheduledMutator::new(havoc_mutations()); - 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 mut fuzzer = StdFuzzer::new(tuple_list!(stage)); - - // The wrapped harness function, calling out to the LLVM-style harness - let mut harness = |buf: &[u8]| { - unsafe { LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()) }; - ExitKind::Ok - }; - - // Create the executor for an in-process function with just one observer for edge coverage - let mut executor = TimeoutExecutor::new( - InProcessExecutor::new( - "in-process(edges)", - &mut harness, - tuple_list!(edges_observer, TimeObserver::new("time")), - &mut state, - &mut restarting_mgr, - )?, - // 10 seconds timeout - Duration::new(10, 0), - ); - - // 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, &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, &scheduler)?; - - // Never reached - Ok(()) -} diff --git a/fuzzers/libfuzzer_libpng_old/test.sh b/fuzzers/libfuzzer_libpng_old/test.sh deleted file mode 100755 index 156cf1de04..0000000000 --- a/fuzzers/libfuzzer_libpng_old/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -mkdir -p ./crashes -rm -rf ./.libfuzzer_test.elf - -cargo build --example libfuzzer_libpng --release || exit 1 -cp ../../target/release/examples/libfuzzer_libpng ./.libfuzzer_test.elf - -# The broker -RUST_BACKTRACE=full taskset -c 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 -c 1 ./.libfuzzer_test.elf 2>/dev/null - -killall .libfuzzer_test.elf -rm -rf ./.libfuzzer_test.elf diff --git a/fuzzers/libfuzzer_stb_image/Cargo.toml b/fuzzers/libfuzzer_stb_image/Cargo.toml index 6328090379..1ec1ab28ba 100644 --- a/fuzzers/libfuzzer_stb_image/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image/Cargo.toml @@ -17,8 +17,8 @@ debug = true [dependencies] libafl = { path = "../../libafl/" } -libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_edges", "libfuzzer"] } +libafl_targets = { path = "../../libafl_targets/", features = ["pcguard_edges", "value_profile", "libfuzzer"] } [build-dependencies] cc = { version = "1.0", features = ["parallel"] } -num_cpus = "1.0" \ No newline at end of file +num_cpus = "1.0" diff --git a/fuzzers/libfuzzer_stb_image/build.rs b/fuzzers/libfuzzer_stb_image/build.rs index 50cb1582bc..27c140f6df 100644 --- a/fuzzers/libfuzzer_stb_image/build.rs +++ b/fuzzers/libfuzzer_stb_image/build.rs @@ -14,7 +14,7 @@ fn main() { cc::Build::new() // Use sanitizer coverage to track the edges in the PUT - .flag("-fsanitize-coverage=trace-pc-guard") + .flag("-fsanitize-coverage=trace-pc-guard,trace-cmp") // Take advantage of LTO (needs lld-link set in your cargo config) //.flag("-flto=thin") .flag("-Wno-sign-compare") diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index cbf30ef790..67d4e88e64 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -9,6 +9,7 @@ default = [] pcguard_edges = [] pcguard_hitcounts = [] libfuzzer = [] +value_profile = [] pcguard = ["pcguard_hitcounts"] [build-dependencies] diff --git a/libafl_targets/build.rs b/libafl_targets/build.rs index fb5a37f045..8062540719 100644 --- a/libafl_targets/build.rs +++ b/libafl_targets/build.rs @@ -1,10 +1,12 @@ // build.rs use std::env; +use std::path::Path; fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = out_dir.to_string_lossy().to_string(); + let src_dir = Path::new("src"); //let out_dir_path = Path::new(&out_dir); //std::env::set_var("CC", "clang"); @@ -12,12 +14,21 @@ fn main() { #[cfg(feature = "libfuzzer")] { - println!("cargo:rerun-if-changed=libfuzzer_compatibility.c"); + println!("cargo:rerun-if-changed=src/libfuzzer_compatibility.c"); cc::Build::new() - .file("libfuzzer_compatibility.c") + .file(src_dir.join("libfuzzer_compatibility.c")) .compile("libfuzzer_compatibility"); } + + #[cfg(feature = "value_profile")] + { + println!("cargo:rerun-if-changed=src/value_profile.c"); + + cc::Build::new() + .file(src_dir.join("value_profile.c")) + .compile("value_profile"); + } println!("cargo:rustc-link-search=native={}", &out_dir); diff --git a/libafl_targets/src/lib.rs b/libafl_targets/src/lib.rs index d1ccae18c4..e817b8a57c 100644 --- a/libafl_targets/src/lib.rs +++ b/libafl_targets/src/lib.rs @@ -3,6 +3,11 @@ pub mod pcguard; #[cfg(any(feature = "pcguard_edges", feature = "pcguard_hitcounts"))] pub use pcguard::*; +#[cfg(feature = "value_profile")] +pub mod value_profile; +#[cfg(feature = "value_profile")] +pub use value_profile::*; + #[cfg(feature = "libfuzzer")] pub mod libfuzzer; #[cfg(feature = "libfuzzer")] diff --git a/libafl_targets/libfuzzer_compatibility.c b/libafl_targets/src/libfuzzer_compatibility.c similarity index 100% rename from libafl_targets/libfuzzer_compatibility.c rename to libafl_targets/src/libfuzzer_compatibility.c diff --git a/libafl_targets/src/value_profile.c b/libafl_targets/src/value_profile.c new file mode 100644 index 0000000000..5f093f5420 --- /dev/null +++ b/libafl_targets/src/value_profile.c @@ -0,0 +1,97 @@ +#include +#include +#include + +// TODO compile time flag +#define MAP_SIZE 65536 + +extern uint8_t libafl_cmp_map[MAP_SIZE]; + +#define MAX(a, b) \ + ({ \ + \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a > _b ? _a : _b; \ + \ + }) + +#if defined(__APPLE__) + #pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1 + #pragma weak __sanitizer_cov_trace_const_cmp2 = __sanitizer_cov_trace_cmp2 + #pragma weak __sanitizer_cov_trace_const_cmp4 = __sanitizer_cov_trace_cmp4 + #pragma weak __sanitizer_cov_trace_const_cmp8 = __sanitizer_cov_trace_cmp8 +#else +void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__sanitizer_cov_trace_cmp1"))); +void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2) + __attribute__((alias("__sanitizer_cov_trace_cmp2"))); +void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) + __attribute__((alias("__sanitizer_cov_trace_cmp4"))); +void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) + __attribute__((alias("__sanitizer_cov_trace_cmp8"))); +#endif + +void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) { + + uintptr_t k = (uintptr_t)__builtin_return_address(0); + k = (k >> 4) ^ (k << 8); + k &= MAP_SIZE - 1; + libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2)))); + +} + +void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) { + + uintptr_t k = (uintptr_t)__builtin_return_address(0); + k = (k >> 4) ^ (k << 8); + k &= MAP_SIZE - 1; + libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2)))); + +} + +void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) { + + uintptr_t k = (uintptr_t)__builtin_return_address(0); + k = (k >> 4) ^ (k << 8); + k &= MAP_SIZE - 1; + libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2)))); + +} + +void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) { + + uintptr_t k = (uintptr_t)__builtin_return_address(0); + k = (k >> 4) ^ (k << 8); + k &= MAP_SIZE - 1; + libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcountll(~(arg1 ^ arg2)))); + +} + +void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { + + uintptr_t rt = (uintptr_t)__builtin_return_address(0); + if (cases[1] == 64) { + + for (uint64_t i = 0; i < cases[0]; i++) { + + uintptr_t k = rt + i; + k = (k >> 4) ^ (k << 8); + k &= MAP_SIZE - 1; + libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcountll(~(val ^ cases[i + 2])))); + + } + + } else { + + for (uint64_t i = 0; i < cases[0]; i++) { + + uintptr_t k = rt + i; + k = (k >> 4) ^ (k << 8); + k &= MAP_SIZE - 1; + libafl_cmp_map[k] = MAX(libafl_cmp_map[k], (__builtin_popcount(~(val ^ cases[i + 2])))); + + } + + } + +} diff --git a/libafl_targets/src/value_profile.rs b/libafl_targets/src/value_profile.rs new file mode 100644 index 0000000000..d5aabd8872 --- /dev/null +++ b/libafl_targets/src/value_profile.rs @@ -0,0 +1,24 @@ +// TODO compile time flag +pub const MAP_SIZE: usize = 65536; + +#[no_mangle] +pub static mut libafl_cmp_map: [u8; MAP_SIZE] = [0; MAP_SIZE]; + +pub use libafl_cmp_map as CMP_MAP; + +/* +extern { + #[link_name = "llvm.returnaddress"] + fn return_address() -> usize; +} + +#[no_mangle] +pub unsafe extern "C" fn __sanitizer_cov_trace_cmp1(arg1: u8, arg2: u8) { + let mut pos = return_address(); + pos = (pos >> 4) ^ (pos << 8); + pos &= MAP_SIZE - 1; + *CMP_MAP.get_unchecked_mut(pos) = core::cmp::max(*CMP_MAP.get_unchecked(pos), (!(arg1 ^ arg2)).count_ones() as u8); +} +*/ + +// TODO complete when linking to LLVM intrinsic will land to stable Rust