compile libfuzzer_libpng on windows

This commit is contained in:
root 2021-03-25 18:50:40 +01:00
parent 82f5dad784
commit a0550b3154
6 changed files with 87 additions and 43 deletions

View File

@ -1,12 +1,11 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng. //! The example harness is built for libpng.
#[cfg(unix)]
use core::time::Duration; use core::time::Duration;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use libafl::{ use libafl::{
bolts::{shmem::UnixShMem, tuples::tuple_list}, bolts::{shmem::StdShMem, tuples::tuple_list},
corpus::{ corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
QueueCorpusScheduler, QueueCorpusScheduler,
@ -46,21 +45,14 @@ pub fn main() {
.expect("An error occurred while fuzzing"); .expect("An error occurred while fuzzing");
} }
/// Not supported on windows right now
#[cfg(windows)]
fn fuzz(_corpus_dirs: Vec<PathBuf>, _objective_dir: PathBuf, _broker_port: u16) -> Result<(), ()> {
todo!("Example not supported on Windows");
}
/// The actual fuzzer /// The actual fuzzer
#[cfg(unix)]
fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> { fn fuzz(corpus_dirs: Vec<PathBuf>, 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 // 'While the stats are state, they are usually used in the broker - which is likely never restarted
let stats = SimpleStats::new(|s| println!("{}", s)); 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. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) = let (state, mut restarting_mgr) =
match setup_restarting_mgr::<_, _, UnixShMem, _>(stats, broker_port) { match setup_restarting_mgr::<_, _, StdShMem, _>(stats, broker_port) {
Ok(res) => res, Ok(res) => res,
Err(err) => match err { Err(err) => match err {
Error::ShuttingDown => { Error::ShuttingDown => {
@ -139,7 +131,8 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
if libfuzzer_initialize() == -1 { let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1") println!("Warning: LLVMFuzzerInitialize failed with -1")
} }

View File

@ -3,9 +3,13 @@
#[cfg(all(feature = "std", unix))] #[cfg(all(feature = "std", unix))]
pub use unix_shmem::UnixShMem; pub use unix_shmem::UnixShMem;
#[cfg(all(feature = "std", unix))]
pub type StdShMem = UnixShMem;
#[cfg(all(windows, feature = "std"))] #[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 alloc::string::{String, ToString};
use core::fmt::Debug; use core::fmt::Debug;
@ -442,7 +446,7 @@ pub mod unix_shmem {
} }
#[cfg(all(feature = "std", windows))] #[cfg(all(feature = "std", windows))]
pub mod shmem { pub mod win32_shmem {
use super::ShMem; use super::ShMem;
use crate::{ use crate::{

View File

@ -3,10 +3,7 @@
pub mod inprocess; pub mod inprocess;
pub use inprocess::InProcessExecutor; pub use inprocess::InProcessExecutor;
pub mod timeout; pub mod timeout;
#[cfg(unix)]
pub use timeout::TimeoutExecutor; pub use timeout::TimeoutExecutor;
#[cfg(feature = "runtime")]
pub mod runtime;
use core::cmp::PartialEq; use core::cmp::PartialEq;
use core::marker::PhantomData; use core::marker::PhantomData;

View File

@ -1,9 +1,7 @@
//! A TimeoutExecutor set a timeout before each target run //! A TimeoutExecutor set a timeout before each target run
#[cfg(unix)]
use core::{marker::PhantomData, time::Duration}; use core::{marker::PhantomData, time::Duration};
#[cfg(unix)]
use crate::{ use crate::{
bolts::tuples::Named, bolts::tuples::Named,
events::EventManager, events::EventManager,
@ -41,7 +39,6 @@ extern "C" {
const ITIMER_REAL: c_int = 0; const ITIMER_REAL: c_int = 0;
/// The timeout excutor is a wrapper that set a timeout before each run /// The timeout excutor is a wrapper that set a timeout before each run
#[cfg(unix)]
pub struct TimeoutExecutor<E, I, OT> pub struct TimeoutExecutor<E, I, OT>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
@ -53,7 +50,6 @@ where
phantom: PhantomData<(I, OT)>, phantom: PhantomData<(I, OT)>,
} }
#[cfg(unix)]
impl<E, I, OT> Named for TimeoutExecutor<E, I, OT> impl<E, I, OT> Named for TimeoutExecutor<E, I, OT>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
@ -65,7 +61,6 @@ where
} }
} }
#[cfg(unix)]
impl<E, I, OT> HasObservers<OT> for TimeoutExecutor<E, I, OT> impl<E, I, OT> HasObservers<OT> for TimeoutExecutor<E, I, OT>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
@ -83,7 +78,6 @@ where
} }
} }
#[cfg(unix)]
impl<E, I, OT> TimeoutExecutor<E, I, OT> impl<E, I, OT> TimeoutExecutor<E, I, OT>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
@ -99,7 +93,6 @@ where
} }
} }
#[cfg(unix)]
impl<E, I, OT> Executor<I> for TimeoutExecutor<E, I, OT> impl<E, I, OT> Executor<I> for TimeoutExecutor<E, I, OT>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,

View File

@ -1,25 +1,80 @@
static int orig_argc; #include <stdio.h>
static char **orig_argv; #include <stdlib.h>
static char **orig_envp; #include <stdint.h>
static void save_main_args(int argc, char** argv, char** envp) { #define true 1
orig_argc = argc; #define false 0
orig_argv = argv;
orig_envp = envp; #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"))) int libafl_targets_libfuzzer_init(int *argc, char ***argv) {
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() {
if (LLVMFuzzerInitialize) { if (LLVMFuzzerInitialize) {
return LLVMFuzzerInitialize(&orig_argc, &orig_argv); return LLVMFuzzerInitialize(argc, argv);
} else { } else {
return 0; return 0;
} }
} }

View File

@ -4,11 +4,13 @@ extern "C" {
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32; fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32;
// libafl_targets_libfuzzer_init calls LLVMFUzzerInitialize() // 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 { pub fn libfuzzer_initialize(args: &[String]) -> i32 {
unsafe { libafl_targets_libfuzzer_init() } 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 { pub fn libfuzzer_test_one_input(buf: &[u8]) -> i32 {