trying to get things to work
This commit is contained in:
parent
bade18eaf3
commit
da5ffd6c14
@ -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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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| {
|
||||||
|
@ -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: _ } => {
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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>),
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user