trying to get things to work

This commit is contained in:
Dominik Maier 2021-01-04 14:06:43 +01:00
parent bade18eaf3
commit da5ffd6c14
13 changed files with 210 additions and 68 deletions

View File

@ -29,9 +29,10 @@ opt-level = 3
debug = true debug = true
[features] [features]
default = ["std"] default = ["std", "anymapdbg"]
std = [] # print, sharedmap, ... support std = [] # print, sharedmap, ... support
runtime = [] # a runtime for clang inmem-executor runtime = [] # a runtime for clang inmem-executor
anymapdbg = [] # uses serde_json to Debug the anymap trait. Disable for smaller footprint.
[[example]] [[example]]
name = "llmp_test" name = "llmp_test"
@ -48,4 +49,5 @@ serde = { version = "1.0", default-features = false, features = ["alloc"] } # se
erased-serde = "0.3.12" erased-serde = "0.3.12"
postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat
static_assertions = "1.1.0" 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 #TODO: for llmp brotli = { version = "3.3.0", default-features = false } # brotli compression

View File

@ -119,7 +119,7 @@ where
} }
/// A corpus handling all important fuzzing in memory. /// A corpus handling all important fuzzing in memory.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct InMemoryCorpus<I, R> pub struct InMemoryCorpus<I, R>
where where
@ -185,7 +185,7 @@ where
/// A corpus able to store testcases to dis, and load them from disk, when they are being used. /// A corpus able to store testcases to dis, and load them from disk, when they are being used.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct OnDiskCorpus<I, R> pub struct OnDiskCorpus<I, R>
where where
@ -273,7 +273,7 @@ where
} }
/// A Queue-like corpus, wrapping an existing Corpus instance /// A Queue-like corpus, wrapping an existing Corpus instance
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct QueueCorpus<C, I, R> pub struct QueueCorpus<C, I, R>
where where

View File

@ -9,7 +9,7 @@ use crate::serde_anymap::{SerdeAny, SerdeAnyMap};
use crate::AflError; use crate::AflError;
/// An entry in the Testcase Corpus /// An entry in the Testcase Corpus
#[derive(Default, Serialize, Deserialize)] #[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct Testcase<I> pub struct Testcase<I>
where where

View File

@ -31,7 +31,7 @@ pub trait StateMetadata: Debug {
} }
/// The state a fuzz run. /// The state a fuzz run.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "FT: serde::de::DeserializeOwned")] #[serde(bound = "FT: serde::de::DeserializeOwned")]
pub struct State<I, R, FT, OT> pub struct State<I, R, FT, OT>
where where
@ -322,6 +322,7 @@ where
} }
} }
#[derive(Clone, Debug)]
pub struct Engine<E, OT, ET, I> pub struct Engine<E, OT, ET, I>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
@ -432,6 +433,7 @@ where
} }
} }
#[derive(Clone, Debug)]
pub struct StdFuzzer<ST, EM, E, OT, FT, ET, C, I, R> pub struct StdFuzzer<ST, EM, E, OT, FT, ET, C, I, R>
where where
ST: StagesTuple<EM, E, OT, FT, ET, C, I, R>, ST: StagesTuple<EM, E, OT, FT, ET, C, I, R>,
@ -519,7 +521,7 @@ mod tests {
let testcase = Testcase::new(vec![0; 4]).into(); let testcase = Testcase::new(vec![0; 4]).into();
corpus.add(testcase); corpus.add(testcase);
let executor = InMemoryExecutor::<BytesInput, _>::new("main", harness, tuple_list!()); let executor = InMemoryExecutor::<BytesInput, _>::new("main", harness, tuple_list!(), None);
let mut state = State::new(tuple_list!()); let mut state = State::new(tuple_list!());
let mut events_manager = LoggerEventManager::new(SimpleStats::new(|s| { let mut events_manager = LoggerEventManager::new(SimpleStats::new(|s| {

View File

@ -280,7 +280,7 @@ where
// TODO Custom event fire (dyn CustomEvent or similar) // TODO Custom event fire (dyn CustomEvent or similar)
} }
#[derive(Debug)] #[derive(Clone, Debug)]
pub enum LoggerEvent<I> pub enum LoggerEvent<I>
where where
I: Input, I: Input,
@ -404,6 +404,7 @@ where
} }
} }
#[derive(Clone, Debug)]
pub struct LoggerEventManager<C, E, OT, FT, I, R, ST> pub struct LoggerEventManager<C, E, OT, FT, I, R, ST>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
@ -532,7 +533,7 @@ where
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub enum LLMPEventKind<'a, I> pub enum LLMPEventKind<'a, I>
where where
@ -568,7 +569,7 @@ where
},*/ },*/
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct LLMPEvent<'a, I> pub struct LLMPEvent<'a, I>
where where
@ -704,6 +705,7 @@ const _LLMP_TAG_EVENT_TO_BROKER: llmp::Tag = 0x2B80438;
/// Handle in both /// Handle in both
const LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741; const LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741;
#[derive(Clone, Debug)]
pub struct LlmpEventManager<C, E, OT, FT, I, R, SH, ST> pub struct LlmpEventManager<C, E, OT, FT, I, R, SH, ST>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
@ -732,10 +734,10 @@ where
R: Rand, R: Rand,
ST: Stats, ST: Stats,
{ {
#[cfg(feature = "std")]
/// Create llmp on a port /// Create llmp on a port
/// If the port is not yet bound, it will act as broker /// If the port is not yet bound, it will act as broker
/// Else, it will act as client. /// Else, it will act as client.
#[cfg(feature = "std")]
pub fn new_on_port_std(port: u16, stats: ST) -> Result<Self, AflError> { pub fn new_on_port_std(port: u16, stats: ST) -> Result<Self, AflError> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpConnection::on_port(port)?, 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 /// If a client respawns, it may reuse the existing connection, previously stored by LlmpClient::to_env
/// Std uses AflShmem. /// Std uses AflShmem.
#[cfg(feature = "std")]
pub fn existing_client_from_env_std(env_name: &str, stats: ST) -> Result<Self, AflError> { pub fn existing_client_from_env_std(env_name: &str, stats: ST) -> Result<Self, AflError> {
Self::existing_client_from_env(env_name, stats) Self::existing_client_from_env(env_name, stats)
} }
@ -762,10 +765,10 @@ where
SH: ShMem, SH: ShMem,
ST: Stats, ST: Stats,
{ {
#[cfg(feature = "std")]
/// Create llmp on a port /// Create llmp on a port
/// If the port is not yet bound, it will act as broker /// If the port is not yet bound, it will act as broker
/// Else, it will act as client. /// Else, it will act as client.
#[cfg(feature = "std")]
pub fn new_on_port(port: u16, stats: ST) -> Result<Self, AflError> { pub fn new_on_port(port: u16, stats: ST) -> Result<Self, AflError> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpConnection::on_port(port)?, 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 /// 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<Self, AflError> { pub fn existing_client_from_env(env_name: &str, stats: ST) -> Result<Self, AflError> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpConnection::IsClient { 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 /// 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) { pub fn to_env(&self, env_name: &str) {
match &self.llmp { match &self.llmp {
llmp::LlmpConnection::IsBroker { broker: _ } => { llmp::LlmpConnection::IsBroker { broker: _ } => {

View File

@ -1,15 +1,18 @@
use core::ffi::c_void; use alloc::boxed::Box;
use core::ptr; use core::{ffi::c_void, ptr};
use crate::executors::{Executor, ExitKind, HasObservers}; use crate::{
use crate::inputs::{HasTargetBytes, Input}; executors::{Executor, ExitKind, HasObservers},
use crate::observers::ObserversTuple; inputs::{HasTargetBytes, Input},
use crate::tuples::Named; observers::ObserversTuple,
use crate::AflError; tuples::Named,
AflError,
};
/// The (unsafe) pointer to the current inmem input, for the current run. /// 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. /// 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_INPUT_PTR: *const c_void = ptr::null();
static mut CURRENT_ON_CRASH_FN: *const Box<dyn FnOnce(ExitKind)> = ptr::null();
/// The inmem executor harness /// The inmem executor harness
type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind; type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
@ -26,10 +29,8 @@ where
harness: HarnessFunction<I>, harness: HarnessFunction<I>,
/// The observers, observing each run /// The observers, observing each run
observers: OT, observers: OT,
/*
/// A special function being called right before the process crashes. It may save state to restore fuzzing after respawn. /// A special function being called right before the process crashes. It may save state to restore fuzzing after respawn.
on_crash_fn: Option<Box<dyn FnOnce(ExitKind)>>, on_crash_fn: Box<dyn FnOnce(ExitKind)>,
*/
} }
impl<I, OT> Executor<I> for InMemoryExecutor<I, OT> impl<I, OT> Executor<I> for InMemoryExecutor<I, OT>
@ -41,10 +42,12 @@ where
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> { fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> {
let bytes = input.target_bytes(); let bytes = input.target_bytes();
unsafe { unsafe {
CURRENT_ON_CRASH_FN = &self.on_crash_fn as *const _;
CURRENT_INPUT_PTR = input as *const _ as *const c_void; CURRENT_INPUT_PTR = input as *const _ as *const c_void;
} }
let ret = (self.harness)(self, bytes.as_slice()); let ret = (self.harness)(self, bytes.as_slice());
unsafe { unsafe {
CURRENT_ON_CRASH_FN = ptr::null();
CURRENT_INPUT_PTR = ptr::null(); CURRENT_INPUT_PTR = ptr::null();
} }
Ok(ret) Ok(ret)
@ -91,11 +94,12 @@ where
pub fn new( pub fn new(
name: &'static str, name: &'static str,
harness_fn: HarnessFunction<I>, harness_fn: HarnessFunction<I>,
observers: OT, /*on_crash_fn: Option<Box<dyn FnOnce(ExitKind)>*/ observers: OT,
on_crash_fn: Box<dyn FnOnce(ExitKind)>,
) -> Self { ) -> Self {
Self { Self {
harness: harness_fn, harness: harness_fn,
//on_crash_fn, on_crash_fn,
observers, observers,
name, name,
} }
@ -107,22 +111,32 @@ where
pub mod unix_signals { pub mod unix_signals {
extern crate libc; 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; // Unhandled signals: SIGALRM, SIGHUP, SIGINT, SIGKILL, SIGQUIT, SIGTERM
use crate::events::EventManager; use libc::{
use crate::executors::inmemory::CURRENT_INPUT_PTR; c_int, c_void, sigaction, siginfo_t, SA_NODEFER, SA_SIGINFO, SIGABRT, SIGBUS, SIGFPE,
use crate::executors::Executor; SIGILL, SIGPIPE, SIGSEGV, SIGUSR2,
use crate::feedbacks::FeedbacksTuple; };
use crate::inputs::Input;
use crate::observers::ObserversTuple; use std::{
use crate::utils::Rand; 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(); 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"); 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); std::process::exit(139);
} }
@ -173,7 +191,7 @@ pub mod unix_signals {
R: Rand, R: Rand,
{ {
dbg!("TIMEOUT/SIGUSR2 received"); 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."); dbg!("TIMEOUT or SIGUSR2 happened, but currently not fuzzing.");
return; return;
} }
@ -185,6 +203,10 @@ pub mod unix_signals {
.timeout(input) .timeout(input)
.expect("Error in sending Timeout event"); .expect("Error in sending Timeout event");
if !CURRENT_ON_CRASH_FN.is_null() {
(*CURRENT_ON_CRASH_FN)(ExitKind::Timeout);
}
// TODO: send LLMP. // TODO: send LLMP.
println!("Timeout in fuzz run."); println!("Timeout in fuzz run.");
let _ = stdout().flush(); let _ = stdout().flush();
@ -238,6 +260,8 @@ pub mod unix_signals {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use alloc::boxed::Box;
use crate::executors::inmemory::InMemoryExecutor; use crate::executors::inmemory::InMemoryExecutor;
use crate::executors::{Executor, ExitKind}; use crate::executors::{Executor, ExitKind};
use crate::inputs::{HasTargetBytes, Input, TargetBytes}; use crate::inputs::{HasTargetBytes, Input, TargetBytes};
@ -267,7 +291,8 @@ mod tests {
#[test] #[test]
fn test_inmem_exec() { 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 {}; let mut input = NopInput {};
assert!(in_mem_executor.run_target(&mut input).is_ok()); assert!(in_mem_executor.run_target(&mut input).is_ok());
} }

View File

@ -41,6 +41,30 @@ where
fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> { fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> {
Ok(()) 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<Vec<u8>, 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<I>: serde::Serialize + serde::de::DeserializeOwned pub trait FeedbacksTuple<I>: serde::Serialize + serde::de::DeserializeOwned
@ -59,25 +83,38 @@ where
/// Discards metadata - the end of this input's execution /// Discards metadata - the end of this input's execution
fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>; 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<I> FeedbacksTuple<I> for () impl<I> FeedbacksTuple<I> for ()
where where
I: Input, I: Input,
{ {
fn is_interesting_all<OT: ObserversTuple>( #[inline]
&mut self, fn is_interesting_all<OT: ObserversTuple>(&mut self, _: &I, _: &OT) -> Result<u32, AflError> {
_input: &I,
_observers: &OT,
) -> Result<u32, AflError> {
Ok(0) Ok(0)
} }
#[inline]
fn append_metadata_all(&mut self, _testcase: &mut Testcase<I>) -> Result<(), AflError> { fn append_metadata_all(&mut self, _testcase: &mut Testcase<I>) -> Result<(), AflError> {
Ok(()) Ok(())
} }
#[inline]
fn discard_metadata_all(&mut self, _input: &I) -> Result<(), AflError> { fn discard_metadata_all(&mut self, _input: &I) -> Result<(), AflError> {
Ok(()) Ok(())
} }
/*
fn restore_state_from_all(&mut self, restore_from: &Self) -> Result<(), AflError> {
Ok(())
}
*/
} }
impl<Head, Tail, I> FeedbacksTuple<I> for (Head, Tail) impl<Head, Tail, I> FeedbacksTuple<I> for (Head, Tail)
@ -104,6 +141,13 @@ where
self.0.discard_metadata(input)?; self.0.discard_metadata(input)?;
self.1.discard_metadata_all(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 /// A Reducer function is used to aggregate values for the novelty search
@ -114,7 +158,7 @@ where
fn reduce(first: T, second: T) -> T; fn reduce(first: T, second: T) -> T;
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MaxReducer<T> pub struct MaxReducer<T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, 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<T> pub struct MinReducer<T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
@ -159,7 +203,7 @@ where
} }
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct MapFeedback<T, R, O> pub struct MapFeedback<T, R, O>
where where

View File

@ -23,6 +23,7 @@ where
fn generate_dummy(&self) -> I; fn generate_dummy(&self) -> I;
} }
#[derive(Clone, Debug)]
/// Generates random bytes /// Generates random bytes
pub struct RandBytesGenerator<R> pub struct RandBytesGenerator<R>
where where
@ -64,6 +65,7 @@ where
} }
} }
#[derive(Clone, Debug)]
/// Generates random printable characters /// Generates random printable characters
pub struct RandPrintablesGenerator<R> { pub struct RandPrintablesGenerator<R> {
max_size: usize, max_size: usize,

View File

@ -44,6 +44,7 @@ where
} }
} }
#[derive(Clone)]
pub struct StdScheduledMutator<C, I, R> pub struct StdScheduledMutator<C, I, R>
where where
C: Corpus<I, R>, C: Corpus<I, R>,
@ -142,6 +143,7 @@ where
} }
} }
#[derive(Clone, Debug)]
/// Schedule some selected byte level mutations given a ScheduledMutator type /// Schedule some selected byte level mutations given a ScheduledMutator type
pub struct HavocBytesMutator<SM, C, I, R> pub struct HavocBytesMutator<SM, C, I, R>
where where

View File

@ -17,12 +17,31 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st
Ok(()) Ok(())
} }
/// Resets the observer
fn reset(&mut self) -> Result<(), AflError>; fn reset(&mut self) -> Result<(), AflError>;
/// This function is executed after each fuzz run
#[inline] #[inline]
fn post_exec(&mut self) -> Result<(), AflError> { fn post_exec(&mut self) -> Result<(), AflError> {
Ok(()) 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<Vec<u8>, 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: pub trait ObserversTuple:
@ -124,7 +143,7 @@ where
/// The Map Observer retrieves the state of a map, /// The Map Observer retrieves the state of a map,
/// that will get updated by the target. /// that will get updated by the target.
/// A well-known example is the AFL-Style coverage map. /// A well-known example is the AFL-Style coverage map.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct StdMapObserver<T> pub struct StdMapObserver<T>
where where
@ -212,7 +231,7 @@ where
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct VariableMapObserver<T> pub struct VariableMapObserver<T>
where where

View File

@ -1,8 +1,9 @@
use serde::Deserialize; use serde::Deserialize;
use alloc::boxed::Box; use alloc::{boxed::Box, vec::Vec};
use alloc::vec::Vec;
use core::any::{Any, TypeId}; use core::any::{Any, TypeId};
#[cfg(fature = "anymap_debug")]
use serde_json;
// yolo // yolo
@ -16,8 +17,11 @@ pub fn unpack_type_id(id: TypeId) -> u64 {
unsafe { *(&id as *const _ as *const u64) } unsafe { *(&id as *const _ as *const u64) }
} }
/// An any object
pub trait SerdeAny: Any + erased_serde::Serialize { pub trait SerdeAny: Any + erased_serde::Serialize {
/// returns this as Any trait
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
/// returns this as mutable Any trait
fn as_any_mut(&mut self) -> &mut dyn Any; 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 alloc::string::String;
use core::any::{Any, TypeId}; use core::any::{Any, TypeId};
use core::fmt; use core::fmt;
use postcard;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use hashbrown::hash_map::{Keys, Values, ValuesMut}; use hashbrown::hash_map::{Keys, Values, ValuesMut};
@ -159,6 +164,30 @@ macro_rules! create_serde_registry_for_trait {
map: HashMap<u64, Box<dyn $trait_name>>, map: HashMap<u64, Box<dyn $trait_name>>,
} }
// 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 { impl SerdeAnyMap {
#[inline] #[inline]
pub fn get<T>(&self) -> Option<&T> pub fn get<T>(&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); create_serde_registry_for_trait!(serdeany_serde, crate::serde_anymap::SerdeAny);
pub use serdeany_serde::*; pub use serdeany_serde::*;
#[derive(Clone, Debug)]
pub enum Ptr<'a, T: 'a + ?Sized> { pub enum Ptr<'a, T: 'a + ?Sized> {
Ref(&'a T), Ref(&'a T),
Owned(Box<T>), Owned(Box<T>),
@ -629,6 +659,7 @@ impl<'a, T: Sized> SliceMut<'a, T> {
} }
} }
#[derive(Clone, Debug)]
pub enum Cptr<T: Sized> { pub enum Cptr<T: Sized> {
Cptr(*const T), Cptr(*const T),
Owned(Box<T>), Owned(Box<T>),
@ -741,6 +772,7 @@ impl<T: Sized> Array<T> {
} }
} }
#[derive(Clone, Debug)]
pub enum ArrayMut<T: Sized> { pub enum ArrayMut<T: Sized> {
Cptr((*mut T, usize)), Cptr((*mut T, usize)),
Owned(Vec<T>), Owned(Vec<T>),

View File

@ -84,6 +84,7 @@ where
} }
} }
#[derive(Clone, Debug)]
/// The default mutational stage /// The default mutational stage
pub struct StdMutationalStage<M, EM, E, OT, FT, ET, C, I, R> pub struct StdMutationalStage<M, EM, E, OT, FT, ET, C, I, R>
where where

View File

@ -105,6 +105,11 @@ fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
let mut receiver = LlmpReceiver::<AflShmem>::on_existing_from_env(ENV_FUZZER_RECEIVER)?; let mut receiver = LlmpReceiver::<AflShmem>::on_existing_from_env(ENV_FUZZER_RECEIVER)?;
let mut sender = LlmpSender::<AflShmem>::on_existing_from_env(ENV_FUZZER_SENDER)?; let mut sender = LlmpSender::<AflShmem>::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. // Call LLVMFUzzerInitialize() if present.
unsafe { unsafe {
if afl_libfuzzer_init() == -1 { if afl_libfuzzer_init() == -1 {
@ -113,28 +118,32 @@ fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
} }
// If we're restarting, deserialize the old corpus. // 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 => { None => {
// Initial execution, read or generate initial inputs // Initial execution, read or generate initial state, corpus, and feedbacks
InMemoryCorpus::new() 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)?, 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. // We reset the sender, the next sender and receiver (after crash) will reuse the page from the initial message.
unsafe { sender.reset_last_page() }; unsafe { sender.reset_last_page() };
// TODO: How to restore the observer state? // Create the engine
let edges_observer = let executor = InMemoryExecutor::new("Libfuzzer", harness, tuple_list!(edges_observer), Some(Box::new(|exit_kind| {
StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe { // TODO: How to access state, corpus? Unsafe is fine?
__lafl_max_edges_size as usize /*
}); let serialized = postcard::to_allocvec(&(state, corpus)).unwrap();
let edges_feedback = MaxMapFeedback::new_with_observer(&NAME_COV_MAP, &edges_observer); sender.send_buf(0x1, &serialized).unwrap();
*/
let executor = InMemoryExecutor::new("Libfuzzer", harness, tuple_list!(edges_observer)); })));
let mut state = State::new(tuple_list!(edges_feedback));
let mut engine = Engine::new(executor); let mut engine = Engine::new(executor);
// in case the corpus is empty (on first run), reset
if corpus.count() < 1 { if corpus.count() < 1 {
match input { match input {
Some(x) => state Some(x) => state
@ -142,6 +151,7 @@ fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
.expect(&format!("Failed to load initial corpus at {:?}", &x)), .expect(&format!("Failed to load initial corpus at {:?}", &x)),
None => (), None => (),
} }
println!("We imported {} inputs from disk.", corpus.count());
} }
if corpus.count() < 1 { if corpus.count() < 1 {
println!("Generating random inputs"); println!("Generating random inputs");
@ -155,10 +165,9 @@ fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
4, 4,
) )
.expect("Failed to generate initial inputs"); .expect("Failed to generate initial inputs");
println!("We generated {} inputs.", corpus.count());
} }
println!("We have {} inputs.", corpus.count());
let mut mutator = HavocBytesMutator::new_default(); let mut mutator = HavocBytesMutator::new_default();
mutator.set_max_size(4096); mutator.set_max_size(4096);