diff --git a/afl/Cargo.toml b/afl/Cargo.toml index ee1d628249..012828f0fb 100644 --- a/afl/Cargo.toml +++ b/afl/Cargo.toml @@ -29,9 +29,10 @@ opt-level = 3 debug = true [features] -default = ["std"] +default = ["std", "anymapdbg"] std = [] # print, sharedmap, ... support runtime = [] # a runtime for clang inmem-executor +anymapdbg = [] # uses serde_json to Debug the anymap trait. Disable for smaller footprint. [[example]] name = "llmp_test" @@ -48,4 +49,5 @@ serde = { version = "1.0", default-features = false, features = ["alloc"] } # se erased-serde = "0.3.12" postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat static_assertions = "1.1.0" +serde_json = { version = "1.0", default-features = false, features = ["alloc"] } # an easy way to debug print SerdeAnyMap #TODO: for llmp brotli = { version = "3.3.0", default-features = false } # brotli compression \ No newline at end of file diff --git a/afl/src/corpus/mod.rs b/afl/src/corpus/mod.rs index 070fd496a7..1bbb14170b 100644 --- a/afl/src/corpus/mod.rs +++ b/afl/src/corpus/mod.rs @@ -119,7 +119,7 @@ where } /// A corpus handling all important fuzzing in memory. -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] pub struct InMemoryCorpus where @@ -185,7 +185,7 @@ where /// A corpus able to store testcases to dis, and load them from disk, when they are being used. #[cfg(feature = "std")] -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] pub struct OnDiskCorpus where @@ -273,7 +273,7 @@ where } /// A Queue-like corpus, wrapping an existing Corpus instance -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] pub struct QueueCorpus where diff --git a/afl/src/corpus/testcase.rs b/afl/src/corpus/testcase.rs index 2e9bd1d182..50d6c78a9c 100644 --- a/afl/src/corpus/testcase.rs +++ b/afl/src/corpus/testcase.rs @@ -9,7 +9,7 @@ use crate::serde_anymap::{SerdeAny, SerdeAnyMap}; use crate::AflError; /// An entry in the Testcase Corpus -#[derive(Default, Serialize, Deserialize)] +#[derive(Default, Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] pub struct Testcase where diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index 483eeb3d2b..64d27e7b4d 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -31,7 +31,7 @@ pub trait StateMetadata: Debug { } /// The state a fuzz run. -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "FT: serde::de::DeserializeOwned")] pub struct State where @@ -322,6 +322,7 @@ where } } +#[derive(Clone, Debug)] pub struct Engine where E: Executor + HasObservers, @@ -432,6 +433,7 @@ where } } +#[derive(Clone, Debug)] pub struct StdFuzzer where ST: StagesTuple, @@ -519,7 +521,7 @@ mod tests { let testcase = Testcase::new(vec![0; 4]).into(); corpus.add(testcase); - let executor = InMemoryExecutor::::new("main", harness, tuple_list!()); + let executor = InMemoryExecutor::::new("main", harness, tuple_list!(), None); let mut state = State::new(tuple_list!()); let mut events_manager = LoggerEventManager::new(SimpleStats::new(|s| { diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index 3fab16dc4e..3fc73242bf 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -280,7 +280,7 @@ where // TODO Custom event fire (dyn CustomEvent or similar) } -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum LoggerEvent where I: Input, @@ -404,6 +404,7 @@ where } } +#[derive(Clone, Debug)] pub struct LoggerEventManager where C: Corpus, @@ -532,7 +533,7 @@ where } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] pub enum LLMPEventKind<'a, I> where @@ -568,7 +569,7 @@ where },*/ } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] pub struct LLMPEvent<'a, I> where @@ -704,6 +705,7 @@ const _LLMP_TAG_EVENT_TO_BROKER: llmp::Tag = 0x2B80438; /// Handle in both const LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741; +#[derive(Clone, Debug)] pub struct LlmpEventManager where C: Corpus, @@ -732,10 +734,10 @@ where R: Rand, ST: Stats, { - #[cfg(feature = "std")] /// Create llmp on a port /// If the port is not yet bound, it will act as broker /// Else, it will act as client. + #[cfg(feature = "std")] pub fn new_on_port_std(port: u16, stats: ST) -> Result { Ok(Self { llmp: llmp::LlmpConnection::on_port(port)?, @@ -746,6 +748,7 @@ where /// If a client respawns, it may reuse the existing connection, previously stored by LlmpClient::to_env /// Std uses AflShmem. + #[cfg(feature = "std")] pub fn existing_client_from_env_std(env_name: &str, stats: ST) -> Result { Self::existing_client_from_env(env_name, stats) } @@ -762,10 +765,10 @@ where SH: ShMem, ST: Stats, { - #[cfg(feature = "std")] /// Create llmp on a port /// If the port is not yet bound, it will act as broker /// Else, it will act as client. + #[cfg(feature = "std")] pub fn new_on_port(port: u16, stats: ST) -> Result { Ok(Self { llmp: llmp::LlmpConnection::on_port(port)?, @@ -775,6 +778,7 @@ where } /// If a client respawns, it may reuse the existing connection, previously stored by LlmpClient::to_env + #[cfg(features = "std")] pub fn existing_client_from_env(env_name: &str, stats: ST) -> Result { Ok(Self { llmp: llmp::LlmpConnection::IsClient { @@ -796,8 +800,8 @@ where } } - #[cfg(feature = "std")] /// Write the config for a client eventmgr to env vars, a new client can reattach using existing_client_from_env + #[cfg(feature = "std")] pub fn to_env(&self, env_name: &str) { match &self.llmp { llmp::LlmpConnection::IsBroker { broker: _ } => { diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index dbb88bed74..d98d121d3c 100644 --- a/afl/src/executors/inmemory.rs +++ b/afl/src/executors/inmemory.rs @@ -1,15 +1,18 @@ -use core::ffi::c_void; -use core::ptr; +use alloc::boxed::Box; +use core::{ffi::c_void, ptr}; -use crate::executors::{Executor, ExitKind, HasObservers}; -use crate::inputs::{HasTargetBytes, Input}; -use crate::observers::ObserversTuple; -use crate::tuples::Named; -use crate::AflError; +use crate::{ + executors::{Executor, ExitKind, HasObservers}, + inputs::{HasTargetBytes, Input}, + observers::ObserversTuple, + tuples::Named, + AflError, +}; /// The (unsafe) pointer to the current inmem input, for the current run. /// This is neede for certain non-rust side effects, as well as unix signal handling. static mut CURRENT_INPUT_PTR: *const c_void = ptr::null(); +static mut CURRENT_ON_CRASH_FN: *const Box = ptr::null(); /// The inmem executor harness type HarnessFunction = fn(&dyn Executor, &[u8]) -> ExitKind; @@ -26,10 +29,8 @@ where harness: HarnessFunction, /// The observers, observing each run observers: OT, - /* /// A special function being called right before the process crashes. It may save state to restore fuzzing after respawn. - on_crash_fn: Option>, - */ + on_crash_fn: Box, } impl Executor for InMemoryExecutor @@ -41,10 +42,12 @@ where fn run_target(&mut self, input: &I) -> Result { let bytes = input.target_bytes(); unsafe { + CURRENT_ON_CRASH_FN = &self.on_crash_fn as *const _; CURRENT_INPUT_PTR = input as *const _ as *const c_void; } let ret = (self.harness)(self, bytes.as_slice()); unsafe { + CURRENT_ON_CRASH_FN = ptr::null(); CURRENT_INPUT_PTR = ptr::null(); } Ok(ret) @@ -91,11 +94,12 @@ where pub fn new( name: &'static str, harness_fn: HarnessFunction, - observers: OT, /*on_crash_fn: Option*/ + observers: OT, + on_crash_fn: Box, ) -> Self { Self { harness: harness_fn, - //on_crash_fn, + on_crash_fn, observers, name, } @@ -107,22 +111,32 @@ where pub mod unix_signals { extern crate libc; - use self::libc::{c_int, c_void, sigaction, siginfo_t}; - // Unhandled signals: SIGALRM, SIGHUP, SIGINT, SIGKILL, SIGQUIT, SIGTERM - use self::libc::{ - SA_NODEFER, SA_SIGINFO, SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGPIPE, SIGSEGV, SIGUSR2, - }; - use std::io::{stdout, Write}; // Write brings flush() into scope - use std::{mem, process, ptr}; - use crate::corpus::Corpus; - use crate::events::EventManager; - use crate::executors::inmemory::CURRENT_INPUT_PTR; - use crate::executors::Executor; - use crate::feedbacks::FeedbacksTuple; - use crate::inputs::Input; - use crate::observers::ObserversTuple; - use crate::utils::Rand; + // Unhandled signals: SIGALRM, SIGHUP, SIGINT, SIGKILL, SIGQUIT, SIGTERM + use libc::{ + c_int, c_void, sigaction, siginfo_t, SA_NODEFER, SA_SIGINFO, SIGABRT, SIGBUS, SIGFPE, + SIGILL, SIGPIPE, SIGSEGV, SIGUSR2, + }; + + use std::{ + io::{stdout, Write}, // Write brings flush() into scope + mem, + process, + ptr, + }; + + use crate::{ + corpus::Corpus, + events::EventManager, + executors::{ + inmemory::{ExitKind, CURRENT_INPUT_PTR, CURRENT_ON_CRASH_FN}, + Executor, + }, + feedbacks::FeedbacksTuple, + inputs::Input, + observers::ObserversTuple, + utils::Rand, + }; static mut EVENT_MANAGER_PTR: *mut c_void = ptr::null_mut(); @@ -156,6 +170,10 @@ pub mod unix_signals { manager.crash(input).expect("Error in sending Crash event"); + if !CURRENT_ON_CRASH_FN.is_null() { + (*CURRENT_ON_CRASH_FN)(ExitKind::Crash); + } + std::process::exit(139); } @@ -173,7 +191,7 @@ pub mod unix_signals { R: Rand, { dbg!("TIMEOUT/SIGUSR2 received"); - if CURRENT_INPUT_PTR == ptr::null() { + if CURRENT_INPUT_PTR.is_null() { dbg!("TIMEOUT or SIGUSR2 happened, but currently not fuzzing."); return; } @@ -185,6 +203,10 @@ pub mod unix_signals { .timeout(input) .expect("Error in sending Timeout event"); + if !CURRENT_ON_CRASH_FN.is_null() { + (*CURRENT_ON_CRASH_FN)(ExitKind::Timeout); + } + // TODO: send LLMP. println!("Timeout in fuzz run."); let _ = stdout().flush(); @@ -238,6 +260,8 @@ pub mod unix_signals { #[cfg(test)] mod tests { + use alloc::boxed::Box; + use crate::executors::inmemory::InMemoryExecutor; use crate::executors::{Executor, ExitKind}; use crate::inputs::{HasTargetBytes, Input, TargetBytes}; @@ -267,7 +291,8 @@ mod tests { #[test] fn test_inmem_exec() { - let mut in_mem_executor = InMemoryExecutor::new("main", test_harness_fn_nop, tuple_list!()); + let mut in_mem_executor = + InMemoryExecutor::new("main", test_harness_fn_nop, tuple_list!(), Box::new(|_| ())); let mut input = NopInput {}; assert!(in_mem_executor.run_target(&mut input).is_ok()); } diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index 9500dc4848..80f5afbde6 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -41,6 +41,30 @@ where fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> { Ok(()) } + + /* + /// Serialize this feedback's state only, to be restored later using deserialize_state + /// As opposed to completely serializing the observer, this is only needed when the fuzzer is to be restarted + /// If no state is needed to be kept, just return an empty vec. + /// Example: + /// >> The virgin_bits map in AFL needs to be in sync with the corpus + #[inline] + fn serialize_state(&mut self) -> Result, AflError> { + Ok(vec![]) + } + + /// Restore the state from a given vec, priviously stored using `serialize_state` + #[inline] + fn deserialize_state(&mut self, serialized_state: &[u8]) -> Result<(), AflError> { + let _ = serialized_state; + Ok(()) + } + + // TODO: Restore_from + fn restore_from(&mut self, restore_from: Self) -> Result<(), AflError> { + Ok(()) + } + */ } pub trait FeedbacksTuple: serde::Serialize + serde::de::DeserializeOwned @@ -59,25 +83,38 @@ where /// Discards metadata - the end of this input's execution fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>; + + /* + /// Restores the state from each of the containing feedbacks in a list of the same shape. + /// Used (prette exclusively) to restore the feedback states after a crash. + fn restore_state_from_all(&mut self, restore_from: &Self) -> Result<(), AflError>; + */ } impl FeedbacksTuple for () where I: Input, { - fn is_interesting_all( - &mut self, - _input: &I, - _observers: &OT, - ) -> Result { + #[inline] + fn is_interesting_all(&mut self, _: &I, _: &OT) -> Result { Ok(0) } + + #[inline] fn append_metadata_all(&mut self, _testcase: &mut Testcase) -> Result<(), AflError> { Ok(()) } + + #[inline] fn discard_metadata_all(&mut self, _input: &I) -> Result<(), AflError> { Ok(()) } + + /* + fn restore_state_from_all(&mut self, restore_from: &Self) -> Result<(), AflError> { + Ok(()) + } + */ } impl FeedbacksTuple for (Head, Tail) @@ -104,6 +141,13 @@ where self.0.discard_metadata(input)?; self.1.discard_metadata_all(input) } + + /* + fn restore_state_from_all(&mut self, restore_from: &Self) -> Result<(), AflError> { + self.0.restore_from(restore_from.0)?; + self.1.restore_state_from_all(restore_from.1)?; + } + */ } /// A Reducer function is used to aggregate values for the novelty search @@ -114,7 +158,7 @@ where fn reduce(first: T, second: T) -> T; } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct MaxReducer where T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, @@ -136,7 +180,7 @@ where } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct MinReducer where T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, @@ -159,7 +203,7 @@ where } /// The most common AFL-like feedback type -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "T: serde::de::DeserializeOwned")] pub struct MapFeedback where diff --git a/afl/src/generators/mod.rs b/afl/src/generators/mod.rs index 64f1f3d2ac..f0a076b565 100644 --- a/afl/src/generators/mod.rs +++ b/afl/src/generators/mod.rs @@ -23,6 +23,7 @@ where fn generate_dummy(&self) -> I; } +#[derive(Clone, Debug)] /// Generates random bytes pub struct RandBytesGenerator where @@ -64,6 +65,7 @@ where } } +#[derive(Clone, Debug)] /// Generates random printable characters pub struct RandPrintablesGenerator { max_size: usize, diff --git a/afl/src/mutators/scheduled.rs b/afl/src/mutators/scheduled.rs index 82eae0ea1b..6a8f206607 100644 --- a/afl/src/mutators/scheduled.rs +++ b/afl/src/mutators/scheduled.rs @@ -44,6 +44,7 @@ where } } +#[derive(Clone)] pub struct StdScheduledMutator where C: Corpus, @@ -142,6 +143,7 @@ where } } +#[derive(Clone, Debug)] /// Schedule some selected byte level mutations given a ScheduledMutator type pub struct HavocBytesMutator where diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index 7bb9fd94b3..23d7deb8de 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -17,12 +17,31 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st Ok(()) } + /// Resets the observer fn reset(&mut self) -> Result<(), AflError>; + /// This function is executed after each fuzz run #[inline] fn post_exec(&mut self) -> Result<(), AflError> { Ok(()) } + + /// Serialize this observer's state only, to be restored later using deserialize_state + /// As opposed to completely serializing the observer, this is only needed when the fuzzer is to be restarted + /// If no state is needed to be kept, just return an empty vec. + /// Example: + /// >> The virgin_bits map in AFL needs to be in sync with the corpus + #[inline] + fn serialize_state(&mut self) -> Result, AflError> { + Ok(vec![]) + } + + /// Restore the state from a given vec, priviously stored using `serialize_state` + #[inline] + fn deserialize_state(&mut self, serialized_state: &[u8]) -> Result<(), AflError> { + let _ = serialized_state; + Ok(()) + } } pub trait ObserversTuple: @@ -124,7 +143,7 @@ where /// The Map Observer retrieves the state of a map, /// that will get updated by the target. /// A well-known example is the AFL-Style coverage map. -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "T: serde::de::DeserializeOwned")] pub struct StdMapObserver where @@ -212,7 +231,7 @@ where } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "T: serde::de::DeserializeOwned")] pub struct VariableMapObserver where diff --git a/afl/src/serde_anymap.rs b/afl/src/serde_anymap.rs index d5993b8c7a..fd12c5f28b 100644 --- a/afl/src/serde_anymap.rs +++ b/afl/src/serde_anymap.rs @@ -1,8 +1,9 @@ use serde::Deserialize; -use alloc::boxed::Box; -use alloc::vec::Vec; +use alloc::{boxed::Box, vec::Vec}; use core::any::{Any, TypeId}; +#[cfg(fature = "anymap_debug")] +use serde_json; // yolo @@ -16,8 +17,11 @@ pub fn unpack_type_id(id: TypeId) -> u64 { unsafe { *(&id as *const _ as *const u64) } } +/// An any object pub trait SerdeAny: Any + erased_serde::Serialize { + /// returns this as Any trait fn as_any(&self) -> &dyn Any; + /// returns this as mutable Any trait fn as_any_mut(&mut self) -> &mut dyn Any; } @@ -68,6 +72,7 @@ macro_rules! create_serde_registry_for_trait { use alloc::string::String; use core::any::{Any, TypeId}; use core::fmt; + use postcard; use serde::{Deserialize, Serialize}; use hashbrown::hash_map::{Keys, Values, ValuesMut}; @@ -159,6 +164,30 @@ macro_rules! create_serde_registry_for_trait { map: HashMap>, } + // Cloning by serializing and deserializing. It ain't fast, but it's honest work. + // We unwrap postcard, it should not have a reason to fail. + impl Clone for SerdeAnyMap { + fn clone(&self) -> Self { + let serialized = postcard::to_allocvec(&self).unwrap(); + postcard::from_bytes(&serialized).unwrap() + } + } + + #[cfg(fature = "anymapdbg")] + impl fmt::Debug for SerdeAnyMap { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let json = serde_json::to_string(&self); + write!(f, "SerdeAnyMap: [{}]", json) + } + } + + #[cfg(not(fature = "anymapdbg"))] + impl fmt::Debug for SerdeAnyMap { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "SerdeAnymap with {} elements", self.len()) + } + } + impl SerdeAnyMap { #[inline] pub fn get(&self) -> Option<&T> @@ -463,6 +492,7 @@ macro_rules! create_serde_registry_for_trait { create_serde_registry_for_trait!(serdeany_serde, crate::serde_anymap::SerdeAny); pub use serdeany_serde::*; +#[derive(Clone, Debug)] pub enum Ptr<'a, T: 'a + ?Sized> { Ref(&'a T), Owned(Box), @@ -629,6 +659,7 @@ impl<'a, T: Sized> SliceMut<'a, T> { } } +#[derive(Clone, Debug)] pub enum Cptr { Cptr(*const T), Owned(Box), @@ -741,6 +772,7 @@ impl Array { } } +#[derive(Clone, Debug)] pub enum ArrayMut { Cptr((*mut T, usize)), Owned(Vec), diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index 4b3d620d6f..0ba30a8e37 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -84,6 +84,7 @@ where } } +#[derive(Clone, Debug)] /// The default mutational stage pub struct StdMutationalStage where diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index 660ea7c049..07a8e51285 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -105,6 +105,11 @@ fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { let mut receiver = LlmpReceiver::::on_existing_from_env(ENV_FUZZER_RECEIVER)?; let mut sender = LlmpSender::::on_existing_from_env(ENV_FUZZER_SENDER)?; + let edges_observer = + StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe { + __lafl_max_edges_size as usize + }); + // Call LLVMFUzzerInitialize() if present. unsafe { if afl_libfuzzer_init() == -1 { @@ -113,28 +118,32 @@ fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { } // If we're restarting, deserialize the old corpus. - let mut corpus = match receiver.recv_buf()? { + let (mut state, mut corpus) = match receiver.recv_buf()? { None => { - // Initial execution, read or generate initial inputs - InMemoryCorpus::new() + // Initial execution, read or generate initial state, corpus, and feedbacks + let edges_feedback = MaxMapFeedback::new_with_observer(&NAME_COV_MAP, &edges_observer); + let state = State::new(tuple_list!(edges_feedback)); + let corpus = InMemoryCorpus::new(); + (state, corpus) } + // Restoring from a previous run, deserialize state and corpus. Some((_sender, _tag, msg)) => postcard::from_bytes(msg)?, }; // We reset the sender, the next sender and receiver (after crash) will reuse the page from the initial message. unsafe { sender.reset_last_page() }; - // TODO: How to restore the observer state? - let edges_observer = - StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe { - __lafl_max_edges_size as usize - }); - let edges_feedback = MaxMapFeedback::new_with_observer(&NAME_COV_MAP, &edges_observer); - - let executor = InMemoryExecutor::new("Libfuzzer", harness, tuple_list!(edges_observer)); - let mut state = State::new(tuple_list!(edges_feedback)); + // Create the engine + let executor = InMemoryExecutor::new("Libfuzzer", harness, tuple_list!(edges_observer), Some(Box::new(|exit_kind| { + // TODO: How to access state, corpus? Unsafe is fine? + /* + let serialized = postcard::to_allocvec(&(state, corpus)).unwrap(); + sender.send_buf(0x1, &serialized).unwrap(); + */ + }))); let mut engine = Engine::new(executor); + // in case the corpus is empty (on first run), reset if corpus.count() < 1 { match input { Some(x) => state @@ -142,6 +151,7 @@ fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { .expect(&format!("Failed to load initial corpus at {:?}", &x)), None => (), } + println!("We imported {} inputs from disk.", corpus.count()); } if corpus.count() < 1 { println!("Generating random inputs"); @@ -155,10 +165,9 @@ fn fuzz(input: Option>, broker_port: u16) -> Result<(), AflError> { 4, ) .expect("Failed to generate initial inputs"); + println!("We generated {} inputs.", corpus.count()); } - println!("We have {} inputs.", corpus.count()); - let mut mutator = HavocBytesMutator::new_default(); mutator.set_max_size(4096);