CustomBuf Events to exchange any data between fuzzers (#672)

* custom buf events

* clippy, nits

* nostd

* testcase

* maturin build

* fmt

* pybind imports cleanup

* remove unneded lifetime annotation

* docs
This commit is contained in:
Dominik Maier 2022-06-14 11:10:08 +02:00 committed by GitHub
parent a2388d4400
commit f7c997ec65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 306 additions and 132 deletions

View File

@ -1,4 +1,5 @@
use libafl; use libafl;
#[cfg(target_os = "linux")]
use libafl_qemu; use libafl_qemu;
use libafl_sugar; use libafl_sugar;
use pyo3::prelude::*; use pyo3::prelude::*;
@ -92,10 +93,14 @@ pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
modules.set_item("pylibafl.sugar", sugar_module)?; modules.set_item("pylibafl.sugar", sugar_module)?;
#[cfg(target_os = "linux")]
let qemu_module = PyModule::new(py, "qemu")?; let qemu_module = PyModule::new(py, "qemu")?;
#[cfg(target_os = "linux")]
libafl_qemu::python_module(py, qemu_module)?; libafl_qemu::python_module(py, qemu_module)?;
#[cfg(target_os = "linux")]
m.add_submodule(qemu_module)?; m.add_submodule(qemu_module)?;
#[cfg(target_os = "linux")]
modules.set_item("pylibafl.qemu", qemu_module)?; modules.set_item("pylibafl.qemu", qemu_module)?;
let libafl_module = PyModule::new(py, "libafl")?; let libafl_module = PyModule::new(py, "libafl")?;

View File

@ -137,9 +137,7 @@ where
/// ``CachedOnDiskCorpus`` Python bindings /// ``CachedOnDiskCorpus`` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
pub mod pybind { pub mod pybind {
use crate::corpus::pybind::PythonCorpus; use crate::{corpus::pybind::PythonCorpus, corpus::CachedOnDiskCorpus, inputs::BytesInput};
use crate::corpus::CachedOnDiskCorpus;
use crate::inputs::BytesInput;
use alloc::string::String; use alloc::string::String;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -91,9 +91,10 @@ where
/// `InMemoryCorpus` Python bindings /// `InMemoryCorpus` Python bindings
#[cfg(feature = "python")] #[cfg(feature = "python")]
pub mod pybind { pub mod pybind {
use crate::corpus::pybind::PythonCorpus; use crate::{
use crate::corpus::InMemoryCorpus; corpus::{pybind::PythonCorpus, InMemoryCorpus},
use crate::inputs::BytesInput; inputs::BytesInput,
};
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -56,18 +56,19 @@ where
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::corpus::inmemory::pybind::PythonInMemoryCorpus; use crate::{
use crate::corpus::testcase::pybind::PythonTestcaseWrapper; corpus::{
use crate::corpus::{Corpus, Testcase}; cached::pybind::PythonCachedOnDiskCorpus, inmemory::pybind::PythonInMemoryCorpus,
use crate::inputs::BytesInput; ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus,
use crate::Error; Testcase,
},
inputs::BytesInput,
Error,
};
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cell::RefCell; use std::cell::RefCell;
use super::cached::pybind::PythonCachedOnDiskCorpus;
use super::ondisk::pybind::PythonOnDiskCorpus;
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
enum PythonCorpusWrapper { enum PythonCorpusWrapper {
InMemory(Py<PythonInMemoryCorpus>), InMemory(Py<PythonInMemoryCorpus>),

View File

@ -208,9 +208,10 @@ where
#[cfg(feature = "python")] #[cfg(feature = "python")]
/// `OnDiskCorpus` Python bindings /// `OnDiskCorpus` Python bindings
pub mod pybind { pub mod pybind {
use crate::corpus::pybind::PythonCorpus; use crate::{
use crate::corpus::OnDiskCorpus; corpus::{pybind::PythonCorpus, OnDiskCorpus},
use crate::inputs::BytesInput; inputs::BytesInput,
};
use alloc::string::String; use alloc::string::String;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -351,12 +351,13 @@ crate::impl_serdeany!(SchedulerTestcaseMetaData);
/// `Testcase` Python bindings /// `Testcase` Python bindings
pub mod pybind { pub mod pybind {
use super::{HasMetadata, Testcase}; use super::{HasMetadata, Testcase};
use crate::bolts::ownedref::OwnedPtrMut; use crate::{
use crate::inputs::{BytesInput, HasBytesVec}; bolts::ownedref::OwnedPtrMut,
use crate::pybind::PythonMetadata; inputs::{BytesInput, HasBytesVec},
pybind::PythonMetadata,
};
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use pyo3::prelude::*; use pyo3::{prelude::*, types::PyDict};
use pyo3::types::PyDict;
/// `PythonTestcase` with fixed generics /// `PythonTestcase` with fixed generics
pub type PythonTestcase = Testcase<BytesInput>; pub type PythonTestcase = Testcase<BytesInput>;

View File

@ -20,7 +20,7 @@ use crate::{
}, },
events::{ events::{
BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId, BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId,
EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter, EventProcessor, EventRestarter, HasCustomBufHandlers, HasEventManagerId, ProgressReporter,
}, },
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
fuzzer::{EvaluatorObservers, ExecutionProcessor}, fuzzer::{EvaluatorObservers, ExecutionProcessor},
@ -29,7 +29,11 @@ use crate::{
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
}; };
use alloc::string::ToString; use alloc::{
boxed::Box,
string::{String, ToString},
vec::Vec,
};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use core::{marker::PhantomData, time::Duration}; use core::{marker::PhantomData, time::Duration};
@ -41,6 +45,8 @@ use std::net::{SocketAddr, ToSocketAddrs};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use super::{CustomBufEventResult, CustomBufHandlerFn};
/// Forward this to the client /// Forward this to the client
const _LLMP_TAG_EVENT_TO_CLIENT: Tag = 0x2C11E471; const _LLMP_TAG_EVENT_TO_CLIENT: Tag = 0x2C11E471;
/// Only handle this in the broker /// Only handle this in the broker
@ -228,14 +234,15 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
println!("[LOG {}]: {}", severity_level, message); println!("[LOG {}]: {}", severity_level, message);
Ok(BrokerEventResult::Handled) Ok(BrokerEventResult::Handled)
} //_ => Ok(BrokerEventResult::Forward), }
Event::CustomBuf { .. } => Ok(BrokerEventResult::Forward),
//_ => Ok(BrokerEventResult::Forward),
} }
} }
} }
/// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp, /// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp,
/// using low-level message passing, [`crate::bolts::llmp`]. /// using low-level message passing, [`crate::bolts::llmp`].
#[derive(Debug)]
pub struct LlmpEventManager<I, OT, S, SP> pub struct LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
@ -244,12 +251,33 @@ where
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
llmp: LlmpClient<SP>, llmp: LlmpClient<SP>,
/// The custom buf handler
custom_buf_handlers: Vec<Box<CustomBufHandlerFn<S>>>,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor, compressor: GzipCompressor,
configuration: EventConfig, configuration: EventConfig,
phantom: PhantomData<(I, OT, S)>, phantom: PhantomData<(I, OT, S)>,
} }
impl<I, OT, S, SP> core::fmt::Debug for LlmpEventManager<I, OT, S, SP>
where
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut debug_struct = f.debug_struct("LlmpEventManager");
let debug = debug_struct.field("llmp", &self.llmp);
//.field("custom_buf_handlers", &self.custom_buf_handlers)
#[cfg(feature = "llmp_compression")]
let debug = debug.field("compressor", &self.compressor);
debug
.field("configuration", &self.configuration)
.field("phantom", &self.phantom)
.finish_non_exhaustive()
}
}
impl<I, OT, S, SP> Drop for LlmpEventManager<I, OT, S, SP> impl<I, OT, S, SP> Drop for LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
@ -276,6 +304,7 @@ where
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration, configuration,
phantom: PhantomData, phantom: PhantomData,
custom_buf_handlers: vec![],
}) })
} }
@ -294,6 +323,7 @@ where
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration, configuration,
phantom: PhantomData, phantom: PhantomData,
custom_buf_handlers: vec![],
}) })
} }
@ -310,6 +340,7 @@ where
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration, configuration,
phantom: PhantomData, phantom: PhantomData,
custom_buf_handlers: vec![],
}) })
} }
@ -330,6 +361,7 @@ where
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration, configuration,
phantom: PhantomData, phantom: PhantomData,
custom_buf_handlers: vec![],
}) })
} }
@ -384,6 +416,14 @@ where
} }
Ok(()) Ok(())
} }
Event::CustomBuf { tag, buf } => {
for handler in &mut self.custom_buf_handlers {
if handler(state, &tag, &buf)? == CustomBufEventResult::Handled {
break;
}
}
Ok(())
}
_ => Err(Error::unknown(format!( _ => Err(Error::unknown(format!(
"Received illegal message that message should not have arrived: {:?}.", "Received illegal message that message should not have arrived: {:?}.",
event.name() event.name()
@ -496,6 +536,20 @@ where
{ {
} }
impl<I, OT, S, SP> HasCustomBufHandlers<S> for LlmpEventManager<I, OT, S, SP>
where
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider,
{
fn add_custom_buf_handler(
&mut self,
handler: Box<dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>>,
) {
self.custom_buf_handlers.push(handler);
}
}
impl<I, OT, S, SP> ProgressReporter<I> for LlmpEventManager<I, OT, S, SP> impl<I, OT, S, SP> ProgressReporter<I> for LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,

View File

@ -7,6 +7,7 @@ pub use llmp::*;
use ahash::AHasher; use ahash::AHasher;
use alloc::{ use alloc::{
boxed::Box,
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
@ -36,8 +37,6 @@ pub struct EventManagerId {
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::monitors::ClientPerfMonitor; use crate::monitors::ClientPerfMonitor;
#[cfg(feature = "introspection")]
use alloc::boxed::Box;
/// The log event severity /// The log event severity
#[derive(Serialize, Deserialize, Debug, Clone, Copy)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
@ -63,6 +62,15 @@ impl fmt::Display for LogSeverity {
} }
} }
/// The result of a custom buf handler added using [`HasCustomBufHandlers::add_custom_buf_handler`]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CustomBufEventResult {
/// Exit early from event handling
Handled,
/// Call the next handler, if available
Next,
}
/// Indicate if an event worked or not /// Indicate if an event worked or not
#[derive(Serialize, Deserialize, Debug, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub enum BrokerEventResult { pub enum BrokerEventResult {
@ -231,6 +239,13 @@ where
/// `PhantomData` /// `PhantomData`
phantom: PhantomData<I>, phantom: PhantomData<I>,
}, },
/// Sends a custom buffer to other clients
CustomBuf {
/// The buffer
buf: Vec<u8>,
/// Tag of this buffer
tag: String,
},
/*/// A custom type /*/// A custom type
Custom { Custom {
// TODO: Allow custom events // TODO: Allow custom events
@ -270,12 +285,13 @@ where
introspection_monitor: _, introspection_monitor: _,
phantom: _, phantom: _,
} => "PerfMonitor", } => "PerfMonitor",
Event::Objective { objective_size: _ } => "Objective", Event::Objective { .. } => "Objective",
Event::Log { Event::Log {
severity_level: _, severity_level: _,
message: _, message: _,
phantom: _, phantom: _,
} => "Log", } => "Log",
Event::CustomBuf { .. } => "CustomBuf",
/*Event::Custom { /*Event::Custom {
sender_id: _, /*custom_event} => custom_event.name()*/ sender_id: _, /*custom_event} => custom_event.name()*/
} => "todo",*/ } => "todo",*/
@ -451,6 +467,16 @@ where
{ {
} }
/// The handler function for custom buffers exchanged via [`EventManager`]
type CustomBufHandlerFn<S> =
dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>;
/// Supports custom buf handlers to handle `CustomBuf` events.
pub trait HasCustomBufHandlers<S> {
/// Adds a custom buffer handler that will run for each incoming `CustomBuf` event.
fn add_custom_buf_handler(&mut self, handler: Box<CustomBufHandlerFn<S>>);
}
/// An eventmgr for tests, and as placeholder if you really don't need an event manager. /// An eventmgr for tests, and as placeholder if you really don't need an event manager.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct NopEventManager {} pub struct NopEventManager {}
@ -479,6 +505,14 @@ impl<E, I, S, Z> EventProcessor<E, I, S, Z> for NopEventManager {
impl<E, I, S, Z> EventManager<E, I, S, Z> for NopEventManager where I: Input {} impl<E, I, S, Z> EventManager<E, I, S, Z> for NopEventManager where I: Input {}
impl<S> HasCustomBufHandlers<S> for NopEventManager {
fn add_custom_buf_handler(
&mut self,
_handler: Box<dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>>,
) {
}
}
impl<I> ProgressReporter<I> for NopEventManager where I: Input {} impl<I> ProgressReporter<I> for NopEventManager where I: Input {}
impl HasEventManagerId for NopEventManager { impl HasEventManagerId for NopEventManager {
@ -548,16 +582,17 @@ mod tests {
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::events::simple::pybind::PythonSimpleEventManager; use crate::{
use crate::events::{ events::{
Event, EventFirer, EventManager, EventManagerId, EventProcessor, EventRestarter, simple::pybind::PythonSimpleEventManager, Event, EventFirer, EventManager,
HasEventManagerId, ProgressReporter, EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter,
},
executors::pybind::PythonExecutor,
fuzzer::pybind::PythonStdFuzzer,
inputs::BytesInput,
state::pybind::PythonStdState,
Error,
}; };
use crate::executors::pybind::PythonExecutor;
use crate::fuzzer::pybind::PythonStdFuzzer;
use crate::inputs::BytesInput;
use crate::state::pybind::PythonStdState;
use crate::Error;
use pyo3::prelude::*; use pyo3::prelude::*;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -9,9 +9,14 @@ use crate::{
monitors::Monitor, monitors::Monitor,
Error, Error,
}; };
use alloc::{string::ToString, vec::Vec}; use alloc::{
boxed::Box,
string::{String, ToString},
vec::Vec,
};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use core::{fmt::Debug, marker::PhantomData};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
@ -23,10 +28,11 @@ use crate::bolts::os::{fork, ForkResult};
use crate::{ use crate::{
bolts::{shmem::ShMemProvider, staterestore::StateRestorer}, bolts::{shmem::ShMemProvider, staterestore::StateRestorer},
corpus::Corpus, corpus::Corpus,
executors::Executor,
state::{HasCorpus, HasSolutions}, state::{HasCorpus, HasSolutions},
}; };
use super::ProgressReporter; use super::{CustomBufEventResult, CustomBufHandlerFn, HasCustomBufHandlers, ProgressReporter};
/// The llmp connection from the actual fuzzer to the process supervising it /// The llmp connection from the actual fuzzer to the process supervising it
const _ENV_FUZZER_SENDER: &str = "_AFL_ENV_FUZZER_SENDER"; const _ENV_FUZZER_SENDER: &str = "_AFL_ENV_FUZZER_SENDER";
@ -35,24 +41,40 @@ const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER";
const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT";
/// A simple, single-threaded event manager that just logs /// A simple, single-threaded event manager that just logs
#[derive(Clone, Debug)] pub struct SimpleEventManager<I, MT, S>
pub struct SimpleEventManager<I, MT>
where where
I: Input, I: Input,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
/// The monitor /// The monitor
monitor: MT, monitor: MT,
/// The events that happened since the last handle_in_broker /// The events that happened since the last handle_in_broker
events: Vec<Event<I>>, events: Vec<Event<I>>,
/// The custom buf handler
custom_buf_handlers: Vec<Box<CustomBufHandlerFn<S>>>,
phantom: PhantomData<S>,
} }
impl<I, MT> EventFirer<I> for SimpleEventManager<I, MT> impl<I, MT, S> Debug for SimpleEventManager<I, MT, S>
where where
I: Input, I: Input,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug,
{ {
fn fire<S>(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SimpleEventManager")
//.field("custom_buf_handlers", self.custom_buf_handlers)
.field("monitor", &self.monitor)
.field("events", &self.events)
.finish_non_exhaustive()
}
}
impl<I, MT, S> EventFirer<I> for SimpleEventManager<I, MT, S>
where
I: Input,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{
fn fire<S2>(&mut self, _state: &mut S2, event: Event<I>) -> Result<(), Error> {
match Self::handle_in_broker(&mut self.monitor, &event)? { match Self::handle_in_broker(&mut self.monitor, &event)? {
BrokerEventResult::Forward => self.events.push(event), BrokerEventResult::Forward => self.events.push(event),
BrokerEventResult::Handled => (), BrokerEventResult::Handled => (),
@ -61,17 +83,17 @@ where
} }
} }
impl<I, MT, S> EventRestarter<S> for SimpleEventManager<I, MT> impl<I, MT, S> EventRestarter<S> for SimpleEventManager<I, MT, S>
where where
I: Input, I: Input,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
} }
impl<E, I, MT, S, Z> EventProcessor<E, I, S, Z> for SimpleEventManager<I, MT> impl<E, I, MT, S, Z> EventProcessor<E, I, S, Z> for SimpleEventManager<I, MT, S>
where where
I: Input, I: Input,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
fn process( fn process(
&mut self, &mut self,
@ -88,44 +110,60 @@ where
} }
} }
impl<E, I, MT, S, Z> EventManager<E, I, S, Z> for SimpleEventManager<I, MT> impl<E, I, MT, S, Z> EventManager<E, I, S, Z> for SimpleEventManager<I, MT, S>
where where
I: Input, I: Input,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
} }
impl<I, MT> ProgressReporter<I> for SimpleEventManager<I, MT> impl<I, MT, S> HasCustomBufHandlers<S> for SimpleEventManager<I, MT, S>
where where
I: Input, I: Input,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{
/// Adds a custom buffer handler that will run for each incoming `CustomBuf` event.
fn add_custom_buf_handler(
&mut self,
handler: Box<dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>>,
) {
self.custom_buf_handlers.push(handler);
}
}
impl<I, MT, S> ProgressReporter<I> for SimpleEventManager<I, MT, S>
where
I: Input,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
} }
impl<I, MT> HasEventManagerId for SimpleEventManager<I, MT> impl<I, MT, S> HasEventManagerId for SimpleEventManager<I, MT, S>
where where
I: Input, I: Input,
MT: Monitor, MT: Monitor + Debug,
{ {
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
EventManagerId { id: 0 } EventManagerId { id: 0 }
} }
} }
impl<I, MT> SimpleEventManager<I, MT> impl<I, MT, S> SimpleEventManager<I, MT, S>
where where
I: Input, I: Input,
MT: Monitor, //TODO CE: CustomEvent, MT: Monitor + Debug, //TODO CE: CustomEvent,
{ {
/// Creates a new [`SimpleEventManager`]. /// Creates a new [`SimpleEventManager`].
pub fn new(monitor: MT) -> Self { pub fn new(monitor: MT) -> Self {
Self { Self {
monitor, monitor,
events: vec![], events: vec![],
custom_buf_handlers: vec![],
phantom: PhantomData,
} }
} }
// Handle arriving events in the broker /// Handle arriving events in the broker
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn handle_in_broker(monitor: &mut MT, event: &Event<I>) -> Result<BrokerEventResult, Error> { fn handle_in_broker(monitor: &mut MT, event: &Event<I>) -> Result<BrokerEventResult, Error> {
match event { match event {
@ -201,17 +239,26 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
println!("[LOG {}]: {}", severity_level, message); println!("[LOG {}]: {}", severity_level, message);
Ok(BrokerEventResult::Handled) Ok(BrokerEventResult::Handled)
} //_ => Ok(BrokerEventResult::Forward), }
Event::CustomBuf { .. } => Ok(BrokerEventResult::Forward),
//_ => Ok(BrokerEventResult::Forward),
} }
} }
// Handle arriving events in the client // Handle arriving events in the client
#[allow(clippy::needless_pass_by_value, clippy::unused_self)] #[allow(clippy::needless_pass_by_value, clippy::unused_self)]
fn handle_in_client<S>(&mut self, _state: &mut S, event: Event<I>) -> Result<(), Error> { fn handle_in_client(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error> {
Err(Error::unknown(format!( if let Event::CustomBuf { tag, buf } = &event {
"Received illegal message that message should not have arrived: {:?}.", for handler in &mut self.custom_buf_handlers {
event handler(state, tag, buf)?;
))) }
Ok(())
} else {
Err(Error::unknown(format!(
"Received illegal message that message should not have arrived: {:?}.",
event
)))
}
} }
} }
@ -220,25 +267,25 @@ where
/// `restarter` will start a new process each time the child crashes or times out. /// `restarter` will start a new process each time the child crashes or times out.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(clippy::default_trait_access)] #[allow(clippy::default_trait_access)]
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct SimpleRestartingEventManager<I, MT, SP> pub struct SimpleRestartingEventManager<I, MT, S, SP>
where where
I: Input, I: Input,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
/// The actual simple event mgr /// The actual simple event mgr
simple_event_mgr: SimpleEventManager<I, MT>, simple_event_mgr: SimpleEventManager<I, MT, S>,
/// [`StateRestorer`] for restarts /// [`StateRestorer`] for restarts
staterestorer: StateRestorer<SP>, staterestorer: StateRestorer<SP>,
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, SP> EventFirer<I> for SimpleRestartingEventManager<I, MT, SP> impl<I, MT, S, SP> EventFirer<I> for SimpleRestartingEventManager<I, MT, S, SP>
where where
I: Input, I: Input,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
fn fire<S2>(&mut self, _state: &mut S2, event: Event<I>) -> Result<(), Error> { fn fire<S2>(&mut self, _state: &mut S2, event: Event<I>) -> Result<(), Error> {
self.simple_event_mgr.fire(_state, event) self.simple_event_mgr.fire(_state, event)
@ -246,12 +293,12 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, S, SP> EventRestarter<S> for SimpleRestartingEventManager<I, MT, SP> impl<I, MT, S, SP> EventRestarter<S> for SimpleRestartingEventManager<I, MT, S, SP>
where where
I: Input, I: Input,
S: Serialize, S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
/// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner.
fn on_restart(&mut self, state: &mut S) -> Result<(), Error> { fn on_restart(&mut self, state: &mut S) -> Result<(), Error> {
@ -262,12 +309,12 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<E, I, S, SP, MT, Z> EventProcessor<E, I, S, Z> for SimpleRestartingEventManager<I, MT, SP> impl<E, I, S, SP, MT, Z> EventProcessor<E, I, S, Z> for SimpleRestartingEventManager<I, MT, S, SP>
where where
I: Input, I: Input,
S: Serialize, S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> { fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> {
self.simple_event_mgr.process(fuzzer, state, executor) self.simple_event_mgr.process(fuzzer, state, executor)
@ -275,30 +322,46 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<E, I, S, SP, MT, Z> EventManager<E, I, S, Z> for SimpleRestartingEventManager<I, MT, SP> impl<E, I, S, SP, MT, Z> EventManager<E, I, S, Z> for SimpleRestartingEventManager<I, MT, S, SP>
where where
E: Executor<Self, I, S, Z>,
I: Input, I: Input,
S: Serialize, S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, SP> ProgressReporter<I> for SimpleRestartingEventManager<I, MT, SP> impl<I, MT, S, SP> HasCustomBufHandlers<S> for SimpleRestartingEventManager<I, MT, S, SP>
where where
I: Input, I: Input,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, //CE: CustomEvent<I, OT>, MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{
fn add_custom_buf_handler(
&mut self,
handler: Box<dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>>,
) {
self.simple_event_mgr.add_custom_buf_handler(handler);
}
}
#[cfg(feature = "std")]
impl<I, MT, S, SP> ProgressReporter<I> for SimpleRestartingEventManager<I, MT, S, SP>
where
I: Input,
SP: ShMemProvider,
MT: Monitor + Debug, //CE: CustomEvent<I, OT>,
{ {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<I, MT, SP> HasEventManagerId for SimpleRestartingEventManager<I, MT, SP> impl<I, MT, S, SP> HasEventManagerId for SimpleRestartingEventManager<I, MT, S, SP>
where where
I: Input, I: Input,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, MT: Monitor + Debug,
{ {
fn mgr_id(&self) -> EventManagerId { fn mgr_id(&self) -> EventManagerId {
self.simple_event_mgr.mgr_id() self.simple_event_mgr.mgr_id()
@ -307,11 +370,11 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow(clippy::type_complexity, clippy::too_many_lines)] #[allow(clippy::type_complexity, clippy::too_many_lines)]
impl<I, MT, SP> SimpleRestartingEventManager<I, MT, SP> impl<I, MT, S, SP> SimpleRestartingEventManager<I, MT, S, SP>
where where
I: Input, I: Input,
SP: ShMemProvider, SP: ShMemProvider,
MT: Monitor, //TODO CE: CustomEvent, MT: Monitor + Debug, //TODO CE: CustomEvent,
{ {
/// Creates a new [`SimpleEventManager`]. /// Creates a new [`SimpleEventManager`].
fn new_launched(monitor: MT, staterestorer: StateRestorer<SP>) -> Self { fn new_launched(monitor: MT, staterestorer: StateRestorer<SP>) -> Self {
@ -325,9 +388,10 @@ where
/// This [`EventManager`] is simple and single threaded, /// This [`EventManager`] is simple and single threaded,
/// but can still used shared maps to recover from crashes and timeouts. /// but can still used shared maps to recover from crashes and timeouts.
#[allow(clippy::similar_names)] #[allow(clippy::similar_names)]
pub fn launch<S>(mut monitor: MT, shmem_provider: &mut SP) -> Result<(Option<S>, Self), Error> pub fn launch(mut monitor: MT, shmem_provider: &mut SP) -> Result<(Option<S>, Self), Error>
where where
S: DeserializeOwned + Serialize + HasCorpus<I> + HasSolutions<I>, S: DeserializeOwned + Serialize + HasCorpus<I> + HasSolutions<I>,
MT: Debug,
{ {
// We start ourself as child process to actually fuzz // We start ourself as child process to actually fuzz
let mut staterestorer = if std::env::var(_ENV_FUZZER_SENDER).is_err() { let mut staterestorer = if std::env::var(_ENV_FUZZER_SENDER).is_err() {
@ -430,18 +494,18 @@ where
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::events::pybind::PythonEventManager; use crate::{
use crate::events::SimpleEventManager; events::pybind::PythonEventManager, events::SimpleEventManager, inputs::BytesInput,
use crate::inputs::BytesInput; monitors::pybind::PythonMonitor, state::pybind::PythonStdState,
use crate::monitors::pybind::PythonMonitor; };
use pyo3::prelude::*; use pyo3::prelude::*;
#[pyclass(unsendable, name = "SimpleEventManager")] #[pyclass(unsendable, name = "SimpleEventManager")]
#[derive(Debug, Clone)] #[derive(Debug)]
/// Python class for SimpleEventManager /// Python class for SimpleEventManager
pub struct PythonSimpleEventManager { pub struct PythonSimpleEventManager {
/// Rust wrapped SimpleEventManager object /// Rust wrapped SimpleEventManager object
pub inner: SimpleEventManager<BytesInput, PythonMonitor>, pub inner: SimpleEventManager<BytesInput, PythonMonitor, PythonStdState>,
} }
#[pymethods] #[pymethods]

View File

@ -674,7 +674,7 @@ mod tests {
#[test] #[test]
#[cfg(unix)] #[cfg(unix)]
fn test_builder() { fn test_builder() {
let mut mgr = SimpleEventManager::<BytesInput, _>::new(SimpleMonitor::new(|status| { let mut mgr = SimpleEventManager::<BytesInput, _, ()>::new(SimpleMonitor::new(|status| {
println!("{}", status); println!("{}", status);
})); }));
@ -700,7 +700,7 @@ mod tests {
fn test_parse_afl_cmdline() { fn test_parse_afl_cmdline() {
use alloc::string::ToString; use alloc::string::ToString;
let mut mgr = SimpleEventManager::<BytesInput, _>::new(SimpleMonitor::new(|status| { let mut mgr = SimpleEventManager::<BytesInput, _, ()>::new(SimpleMonitor::new(|status| {
println!("{}", status); println!("{}", status);
})); }));

View File

@ -1689,16 +1689,16 @@ mod tests {
#[allow(missing_docs)] #[allow(missing_docs)]
/// `InProcess` Python bindings /// `InProcess` Python bindings
pub mod pybind { pub mod pybind {
use crate::events::pybind::PythonEventManager; use crate::{
use crate::executors::pybind::PythonExecutor; events::pybind::PythonEventManager,
use crate::executors::{inprocess::OwnedInProcessExecutor, ExitKind}; executors::{inprocess::OwnedInProcessExecutor, pybind::PythonExecutor, ExitKind},
use crate::fuzzer::pybind::PythonStdFuzzerWrapper; fuzzer::pybind::PythonStdFuzzerWrapper,
use crate::inputs::{BytesInput, HasBytesVec}; inputs::{BytesInput, HasBytesVec},
use crate::observers::pybind::PythonObserversTuple; observers::pybind::PythonObserversTuple,
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper}; state::pybind::{PythonStdState, PythonStdStateWrapper},
};
use alloc::boxed::Box; use alloc::boxed::Box;
use pyo3::prelude::*; use pyo3::{prelude::*, types::PyBytes};
use pyo3::types::PyBytes;
#[pyclass(unsendable, name = "InProcessExecutor")] #[pyclass(unsendable, name = "InProcessExecutor")]
#[derive(Debug)] #[derive(Debug)]

View File

@ -12,7 +12,7 @@ pub mod disk;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use disk::OnDiskTOMLMonitor; pub use disk::OnDiskTOMLMonitor;
use alloc::{string::String, vec::Vec}; use alloc::{fmt::Debug, string::String, vec::Vec};
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use alloc::string::ToString; use alloc::string::ToString;
@ -282,7 +282,7 @@ impl Default for NopMonitor {
} }
/// Tracking monitor during fuzzing. /// Tracking monitor during fuzzing.
#[derive(Clone, Debug)] #[derive(Clone)]
pub struct SimpleMonitor<F> pub struct SimpleMonitor<F>
where where
F: FnMut(String), F: FnMut(String),
@ -292,6 +292,18 @@ where
client_stats: Vec<ClientStats>, client_stats: Vec<ClientStats>,
} }
impl<F> Debug for SimpleMonitor<F>
where
F: FnMut(String),
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SimpleMonitor")
.field("start_time", &self.start_time)
.field("client_stats", &self.client_stats)
.finish()
}
}
impl<F> Monitor for SimpleMonitor<F> impl<F> Monitor for SimpleMonitor<F>
where where
F: FnMut(String), F: FnMut(String),

View File

@ -261,13 +261,14 @@ where
#[cfg(feature = "python")] #[cfg(feature = "python")]
#[allow(missing_docs)] #[allow(missing_docs)]
pub mod pybind { pub mod pybind {
use crate::events::pybind::PythonEventManager; use crate::{
use crate::executors::pybind::PythonExecutor; events::pybind::PythonEventManager,
use crate::fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper}; executors::pybind::PythonExecutor,
use crate::stages::mutational::pybind::PythonStdMutationalStage; fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper},
use crate::stages::{Stage, StagesTuple}; stages::{mutational::pybind::PythonStdMutationalStage, Stage, StagesTuple},
use crate::state::pybind::{PythonStdState, PythonStdStateWrapper}; state::pybind::{PythonStdState, PythonStdStateWrapper},
use crate::Error; Error,
};
use alloc::vec::Vec; use alloc::vec::Vec;
use pyo3::prelude::*; use pyo3::prelude::*;

View File

@ -166,14 +166,15 @@ where
#[allow(missing_docs)] #[allow(missing_docs)]
/// `StdMutationalStage` Python bindings /// `StdMutationalStage` Python bindings
pub mod pybind { pub mod pybind {
use crate::events::pybind::PythonEventManager; use crate::{
use crate::executors::pybind::PythonExecutor; events::pybind::PythonEventManager,
use crate::fuzzer::pybind::PythonStdFuzzer; executors::pybind::PythonExecutor,
use crate::inputs::BytesInput; fuzzer::pybind::PythonStdFuzzer,
use crate::mutators::pybind::PythonMutator; inputs::BytesInput,
use crate::stages::pybind::PythonStage; mutators::pybind::PythonMutator,
use crate::stages::StdMutationalStage; stages::{pybind::PythonStage, StdMutationalStage},
use crate::state::pybind::PythonStdState; state::pybind::PythonStdState,
};
use pyo3::prelude::*; use pyo3::prelude::*;
#[pyclass(unsendable, name = "StdMutationalStage")] #[pyclass(unsendable, name = "StdMutationalStage")]

View File

@ -655,22 +655,22 @@ where
#[allow(missing_docs)] #[allow(missing_docs)]
/// `State` Python bindings /// `State` Python bindings
pub mod pybind { pub mod pybind {
use crate::bolts::ownedref::OwnedPtrMut; use crate::{
use crate::bolts::rands::pybind::PythonRand; bolts::{ownedref::OwnedPtrMut, rands::pybind::PythonRand},
use crate::corpus::pybind::PythonCorpus; corpus::pybind::PythonCorpus,
use crate::events::pybind::PythonEventManager; events::pybind::PythonEventManager,
use crate::executors::pybind::PythonExecutor; executors::pybind::PythonExecutor,
use crate::feedbacks::pybind::PythonFeedback; feedbacks::pybind::PythonFeedback,
use crate::fuzzer::pybind::PythonStdFuzzerWrapper; fuzzer::pybind::PythonStdFuzzerWrapper,
use crate::generators::pybind::PythonGenerator; generators::pybind::PythonGenerator,
use crate::inputs::BytesInput; inputs::BytesInput,
use crate::pybind::PythonMetadata; pybind::PythonMetadata,
use crate::state::{ state::{
HasCorpus, HasExecutions, HasMaxSize, HasMetadata, HasRand, HasSolutions, StdState, HasCorpus, HasExecutions, HasMaxSize, HasMetadata, HasRand, HasSolutions, StdState,
},
}; };
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use pyo3::prelude::*; use pyo3::{prelude::*, types::PyDict};
use pyo3::types::PyDict;
use std::path::PathBuf; use std::path::PathBuf;
/// `StdState` with fixed generics /// `StdState` with fixed generics