From a0550b31542b703aea82fa2ea53497e8fee49075 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 25 Mar 2021 18:50:40 +0100 Subject: [PATCH] compile libfuzzer_libpng on windows --- fuzzers/libfuzzer_libpng/src/lib.rs | 15 +--- libafl/src/bolts/shmem.rs | 8 +- libafl/src/executors/mod.rs | 3 - libafl/src/executors/timeout.rs | 7 -- libafl_targets/libfuzzer_compatibility.c | 89 +++++++++++++++---- libafl_targets/src/libfuzzer_compatibility.rs | 8 +- 6 files changed, 87 insertions(+), 43 deletions(-) diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index 56dfdead1a..15d55b30a3 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -1,12 +1,11 @@ //! 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}; use libafl::{ - bolts::{shmem::UnixShMem, tuples::tuple_list}, + bolts::{shmem::StdShMem, tuples::tuple_list}, corpus::{ Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler, @@ -46,21 +45,14 @@ pub fn main() { .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) { + match setup_restarting_mgr::<_, _, StdShMem, _>(stats, broker_port) { Ok(res) => res, Err(err) => match err { Error::ShuttingDown => { @@ -139,7 +131,8 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // The actual target run starts here. // Call LLVMFUzzerInitialize() if present. - if libfuzzer_initialize() == -1 { + let args: Vec = env::args().collect(); + if libfuzzer_initialize(&args) == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1") } diff --git a/libafl/src/bolts/shmem.rs b/libafl/src/bolts/shmem.rs index f3a95d6092..3c704be519 100644 --- a/libafl/src/bolts/shmem.rs +++ b/libafl/src/bolts/shmem.rs @@ -3,9 +3,13 @@ #[cfg(all(feature = "std", unix))] pub use unix_shmem::UnixShMem; +#[cfg(all(feature = "std", unix))] +pub type StdShMem = UnixShMem; #[cfg(all(windows, feature = "std"))] -pub use shmem::Win32ShMem; +pub use win32_shmem::Win32ShMem; +#[cfg(all(windows, feature = "std"))] +pub type StdShMem = Win32ShMem; use alloc::string::{String, ToString}; use core::fmt::Debug; @@ -442,7 +446,7 @@ pub mod unix_shmem { } #[cfg(all(feature = "std", windows))] -pub mod shmem { +pub mod win32_shmem { use super::ShMem; use crate::{ diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index 705b317d33..3c751e080e 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -3,10 +3,7 @@ pub mod inprocess; pub use inprocess::InProcessExecutor; pub mod timeout; -#[cfg(unix)] pub use timeout::TimeoutExecutor; -#[cfg(feature = "runtime")] -pub mod runtime; use core::cmp::PartialEq; use core::marker::PhantomData; diff --git a/libafl/src/executors/timeout.rs b/libafl/src/executors/timeout.rs index dd88613455..6acb753032 100644 --- a/libafl/src/executors/timeout.rs +++ b/libafl/src/executors/timeout.rs @@ -1,9 +1,7 @@ //! A TimeoutExecutor set a timeout before each target run -#[cfg(unix)] use core::{marker::PhantomData, time::Duration}; -#[cfg(unix)] use crate::{ bolts::tuples::Named, events::EventManager, @@ -41,7 +39,6 @@ extern "C" { const ITIMER_REAL: c_int = 0; /// The timeout excutor is a wrapper that set a timeout before each run -#[cfg(unix)] pub struct TimeoutExecutor where E: Executor + HasObservers, @@ -53,7 +50,6 @@ where phantom: PhantomData<(I, OT)>, } -#[cfg(unix)] impl Named for TimeoutExecutor where E: Executor + HasObservers, @@ -65,7 +61,6 @@ where } } -#[cfg(unix)] impl HasObservers for TimeoutExecutor where E: Executor + HasObservers, @@ -83,7 +78,6 @@ where } } -#[cfg(unix)] impl TimeoutExecutor where E: Executor + HasObservers, @@ -99,7 +93,6 @@ where } } -#[cfg(unix)] impl Executor for TimeoutExecutor where E: Executor + HasObservers, diff --git a/libafl_targets/libfuzzer_compatibility.c b/libafl_targets/libfuzzer_compatibility.c index d5a304348a..79d2391b4a 100644 --- a/libafl_targets/libfuzzer_compatibility.c +++ b/libafl_targets/libfuzzer_compatibility.c @@ -1,25 +1,80 @@ -static int orig_argc; -static char **orig_argv; -static char **orig_envp; +#include +#include +#include -static void save_main_args(int argc, char** argv, char** envp) { - orig_argc = argc; - orig_argv = argv; - orig_envp = envp; +#define true 1 +#define false 0 + +#ifdef _WIN32 + +#ifdef _MSC_VER +#define LIBFUZZER_MSVC 1 +#else +#define LIBFUZZER_MSVC 0 +#endif // _MSC_VER + +// From Libfuzzer +// Intermediate macro to ensure the parameter is expanded before stringified. +#define STRINGIFY_(A) #A +#define STRINGIFY(A) STRINGIFY_(A) + +#if LIBFUZZER_MSVC +// Copied from compiler-rt/lib/sanitizer_common/sanitizer_win_defs.h +#if defined(_M_IX86) || defined(__i386__) +#define WIN_SYM_PREFIX "_" +#else +#define WIN_SYM_PREFIX +#endif + +// Declare external functions as having alternativenames, so that we can +// determine if they are not defined. +#define EXTERNAL_FUNC(Name, Default) \ + __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY( \ + Name) "=" WIN_SYM_PREFIX STRINGIFY(Default))) +#else +// Declare external functions as weak to allow them to default to a specified +// function if not defined explicitly. We must use weak symbols because clang's +// support for alternatename is not 100%, see +// https://bugs.llvm.org/show_bug.cgi?id=40218 for more details. +#define EXTERNAL_FUNC(Name, Default) \ + __attribute__((weak, alias(STRINGIFY(Default)))) +#endif // LIBFUZZER_MSVC + +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + RETURN_TYPE NAME##Def FUNC_SIG { \ + printf("ERROR: Function \"%s\" not defined.\n", #NAME); \ + exit(1); \ + } \ + EXTERNAL_FUNC(NAME, NAME##Def) RETURN_TYPE NAME FUNC_SIG + +#else + +// Declare these symbols as weak to allow them to be optionally defined. +#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \ + __attribute__((weak, visibility("default"))) RETURN_TYPE NAME FUNC_SIG + +#endif + +EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false); +EXT_FUNC(LLVMFuzzerCustomMutator, size_t, + (uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed), + false); +EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, + (const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize, unsigned int Seed), + false); + +#undef EXT_FUNC + +int libafl_targets_has_libfuzzer_init() { + return LLVMFuzzerInitialize != NULL; } -__attribute__((section(".init_array"))) -void (*p_libafl_targets_save_main_args)(int, char*[], char*[]) = &save_main_args; - -__attribute__((weak)) -int LLVMFuzzerInitialize(int *argc, char ***argv); - -int libafl_targets_libfuzzer_init() { - +int libafl_targets_libfuzzer_init(int *argc, char ***argv) { if (LLVMFuzzerInitialize) { - return LLVMFuzzerInitialize(&orig_argc, &orig_argv); + return LLVMFuzzerInitialize(argc, argv); } else { return 0; } - } diff --git a/libafl_targets/src/libfuzzer_compatibility.rs b/libafl_targets/src/libfuzzer_compatibility.rs index a4a29fd362..f17eade2d9 100644 --- a/libafl_targets/src/libfuzzer_compatibility.rs +++ b/libafl_targets/src/libfuzzer_compatibility.rs @@ -4,11 +4,13 @@ extern "C" { fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32; // libafl_targets_libfuzzer_init calls LLVMFUzzerInitialize() - fn libafl_targets_libfuzzer_init() -> i32; + fn libafl_targets_libfuzzer_init(argc: *const i32, argv: *const *const *const u8) -> i32; } -pub fn libfuzzer_initialize() -> i32 { - unsafe { libafl_targets_libfuzzer_init() } +pub fn libfuzzer_initialize(args: &[String]) -> i32 { + let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect(); + let argc = argv.len() as i32; + unsafe { libafl_targets_libfuzzer_init(&argc as *const i32, &argv.as_ptr() as *const *const *const u8) } } pub fn libfuzzer_test_one_input(buf: &[u8]) -> i32 {