pub mod simple;
pub use simple::*;
pub mod centralized;
pub use centralized::*;
pub mod llmp;
use alloc::{boxed::Box, string::String, vec::Vec};
#[cfg(all(unix, feature = "std"))]
use core::ffi::c_void;
use core::{
fmt,
hash::{BuildHasher, Hasher},
marker::PhantomData,
time::Duration,
};
use ahash::RandomState;
pub use llmp::*;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use uuid::Uuid;
#[cfg(all(unix, feature = "std"))]
use crate::bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
#[cfg(all(unix, feature = "std"))]
use crate::bolts::{shmem::ShMemProvider, staterestore::StateRestorer};
use crate::{
bolts::{current_time, ClientId},
executors::ExitKind,
inputs::Input,
monitors::UserStats,
observers::ObserversTuple,
state::{HasClientPerfMonitor, HasExecutions, HasMetadata},
Error,
};
#[cfg(all(unix, feature = "std"))]
pub static mut SHUTDOWN_SIGHANDLER_DATA: ShutdownSignalData = ShutdownSignalData {
allocator_pid: 0,
staterestorer_ptr: core::ptr::null_mut(),
shutdown_handler: core::ptr::null(),
};
#[cfg(all(unix, feature = "std"))]
#[derive(Debug, Clone)]
pub struct ShutdownSignalData {
allocator_pid: usize,
staterestorer_ptr: *mut c_void,
shutdown_handler: *const c_void,
}
#[cfg(all(unix, feature = "std"))]
pub type ShutdownFuncPtr =
unsafe fn(Signal, siginfo_t, &mut ucontext_t, data: &mut ShutdownSignalData);
#[cfg(all(unix, feature = "std"))]
pub unsafe fn shutdown_handler<SP>(
signal: Signal,
_info: siginfo_t,
_context: &mut ucontext_t,
data: &mut ShutdownSignalData,
) where
SP: ShMemProvider,
{
log::info!(
"Fuzzer shutdown by Signal: {} Pid: {}",
signal,
std::process::id()
);
let ptr = data.staterestorer_ptr;
if ptr.is_null() || data.allocator_pid != std::process::id() as usize {
} else {
let sr = (ptr as *mut StateRestorer<SP>).as_mut().unwrap();
std::ptr::drop_in_place(sr);
}
log::info!("Bye!");
libc::_exit(0);
}
#[cfg(all(unix, feature = "std"))]
impl Handler for ShutdownSignalData {
fn handle(&mut self, signal: Signal, info: siginfo_t, context: &mut ucontext_t) {
unsafe {
let data = &mut SHUTDOWN_SIGHANDLER_DATA;
if !data.shutdown_handler.is_null() {
let func: ShutdownFuncPtr = std::mem::transmute(data.shutdown_handler);
(func)(signal, info, context, data);
}
}
}
fn signals(&self) -> Vec<Signal> {
vec![Signal::SigTerm, Signal::SigInterrupt, Signal::SigQuit]
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct EventManagerId(
pub usize,
);
#[cfg(feature = "introspection")]
use crate::monitors::ClientPerfMonitor;
use crate::{inputs::UsesInput, state::UsesState};
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub enum LogSeverity {
Debug,
Info,
Warn,
Error,
}
impl From<LogSeverity> for log::Level {
fn from(value: LogSeverity) -> Self {
match value {
LogSeverity::Debug => log::Level::Debug,
LogSeverity::Info => log::Level::Info,
LogSeverity::Warn => log::Level::Trace,
LogSeverity::Error => log::Level::Error,
}
}
}
impl fmt::Display for LogSeverity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LogSeverity::Debug => write!(f, "Debug"),
LogSeverity::Info => write!(f, "Info"),
LogSeverity::Warn => write!(f, "Warn"),
LogSeverity::Error => write!(f, "Error"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CustomBufEventResult {
Handled,
Next,
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub enum BrokerEventResult {
Handled,
Forward,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventConfig {
AlwaysUnique,
FromName {
name_hash: u64,
},
#[cfg(feature = "std")]
BuildID {
id: Uuid,
},
}
impl EventConfig {
#[must_use]
pub fn from_name(name: &str) -> Self {
let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); hasher.write(name.as_bytes());
EventConfig::FromName {
name_hash: hasher.finish(),
}
}
#[cfg(feature = "std")]
#[must_use]
pub fn from_build_id() -> Self {
EventConfig::BuildID {
id: crate::bolts::build_id::get(),
}
}
#[must_use]
pub fn match_with(&self, other: &EventConfig) -> bool {
match self {
EventConfig::AlwaysUnique => false,
EventConfig::FromName { name_hash: a } => match other {
#[cfg(not(feature = "std"))]
EventConfig::AlwaysUnique => false,
EventConfig::FromName { name_hash: b } => a == b,
#[cfg(feature = "std")]
EventConfig::AlwaysUnique | EventConfig::BuildID { id: _ } => false,
},
#[cfg(feature = "std")]
EventConfig::BuildID { id: a } => match other {
EventConfig::AlwaysUnique | EventConfig::FromName { name_hash: _ } => false,
EventConfig::BuildID { id: b } => a == b,
},
}
}
}
impl From<&str> for EventConfig {
#[must_use]
fn from(name: &str) -> Self {
Self::from_name(name)
}
}
impl From<String> for EventConfig {
#[must_use]
fn from(name: String) -> Self {
Self::from_name(&name)
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub enum Event<I>
where
I: Input,
{
NewTestcase {
input: I,
observers_buf: Option<Vec<u8>>,
exit_kind: ExitKind,
corpus_size: usize,
client_config: EventConfig,
time: Duration,
executions: usize,
forward_id: Option<ClientId>,
},
UpdateExecStats {
time: Duration,
executions: usize,
phantom: PhantomData<I>,
},
UpdateUserStats {
name: String,
value: UserStats,
phantom: PhantomData<I>,
},
#[cfg(feature = "introspection")]
UpdatePerfMonitor {
time: Duration,
executions: usize,
introspection_monitor: Box<ClientPerfMonitor>,
phantom: PhantomData<I>,
},
Objective {
objective_size: usize,
},
Log {
severity_level: LogSeverity,
message: String,
phantom: PhantomData<I>,
},
CustomBuf {
buf: Vec<u8>,
tag: String,
},
}
impl<I> Event<I>
where
I: Input,
{
fn name(&self) -> &str {
match self {
Event::NewTestcase {
input: _,
client_config: _,
corpus_size: _,
exit_kind: _,
observers_buf: _,
time: _,
executions: _,
forward_id: _,
} => "Testcase",
Event::UpdateExecStats {
time: _,
executions: _,
phantom: _,
}
| Event::UpdateUserStats {
name: _,
value: _,
phantom: _,
} => "Stats",
#[cfg(feature = "introspection")]
Event::UpdatePerfMonitor {
time: _,
executions: _,
introspection_monitor: _,
phantom: _,
} => "PerfMonitor",
Event::Objective { .. } => "Objective",
Event::Log {
severity_level: _,
message: _,
phantom: _,
} => "Log",
Event::CustomBuf { .. } => "CustomBuf",
}
}
}
pub trait EventFirer: UsesState {
fn fire(
&mut self,
state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error>;
fn log(
&mut self,
state: &mut Self::State,
severity_level: LogSeverity,
message: String,
) -> Result<(), Error> {
self.fire(
state,
Event::Log {
severity_level,
message,
phantom: PhantomData,
},
)
}
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
where
OT: ObserversTuple<Self::State> + Serialize,
{
Ok(postcard::to_allocvec(observers)?)
}
fn configuration(&self) -> EventConfig {
EventConfig::AlwaysUnique
}
}
pub trait ProgressReporter: EventFirer
where
Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions,
{
fn maybe_report_progress(
&mut self,
state: &mut Self::State,
last_report_time: Duration,
monitor_timeout: Duration,
) -> Result<Duration, Error> {
let executions = *state.executions();
let cur = current_time();
if cur.checked_sub(last_report_time).unwrap_or_default() > monitor_timeout {
#[cfg(not(feature = "introspection"))]
self.fire(
state,
Event::UpdateExecStats {
executions,
time: cur,
phantom: PhantomData,
},
)?;
#[cfg(feature = "introspection")]
{
state
.introspection_monitor_mut()
.set_current_time(crate::bolts::cpu::read_time_counter());
self.fire(
state,
Event::UpdatePerfMonitor {
executions,
time: cur,
introspection_monitor: Box::new(state.introspection_monitor().clone()),
phantom: PhantomData,
},
)?;
}
Ok(cur)
} else {
if cur.as_millis() % 1000 == 0 {}
Ok(last_report_time)
}
}
}
pub trait EventRestarter: UsesState {
#[inline]
fn on_restart(&mut self, _state: &mut Self::State) -> Result<(), Error> {
Ok(())
}
fn send_exiting(&mut self) -> Result<(), Error> {
Ok(())
}
#[inline]
fn await_restart_safe(&mut self) {}
}
pub trait EventProcessor<E, Z>: UsesState {
fn process(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
executor: &mut E,
) -> Result<usize, Error>;
}
pub trait HasEventManagerId {
fn mgr_id(&self) -> EventManagerId;
}
pub trait EventManager<E, Z>:
EventFirer + EventProcessor<E, Z> + EventRestarter + HasEventManagerId + ProgressReporter
where
Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions,
{
}
type CustomBufHandlerFn<S> =
dyn FnMut(&mut S, &String, &[u8]) -> Result<CustomBufEventResult, Error>;
pub trait HasCustomBufHandlers: UsesState {
fn add_custom_buf_handler(&mut self, handler: Box<CustomBufHandlerFn<Self::State>>);
}
#[derive(Copy, Clone, Debug, Default)]
pub struct NopEventManager<S> {
phantom: PhantomData<S>,
}
impl<S> NopEventManager<S> {
#[must_use]
pub fn new() -> Self {
NopEventManager {
phantom: PhantomData,
}
}
}
impl<S> UsesState for NopEventManager<S>
where
S: UsesInput,
{
type State = S;
}
impl<S> EventFirer for NopEventManager<S>
where
S: UsesInput,
{
fn fire(
&mut self,
_state: &mut Self::State,
_event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
Ok(())
}
}
impl<S> EventRestarter for NopEventManager<S> where S: UsesInput {}
impl<E, S, Z> EventProcessor<E, Z> for NopEventManager<S>
where
S: UsesInput + HasClientPerfMonitor + HasExecutions,
{
fn process(
&mut self,
_fuzzer: &mut Z,
_state: &mut Self::State,
_executor: &mut E,
) -> Result<usize, Error> {
Ok(0)
}
}
impl<E, S, Z> EventManager<E, Z> for NopEventManager<S> where
S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata
{
}
impl<S> HasCustomBufHandlers for NopEventManager<S>
where
S: UsesInput,
{
fn add_custom_buf_handler(
&mut self,
_handler: Box<
dyn FnMut(&mut Self::State, &String, &[u8]) -> Result<CustomBufEventResult, Error>,
>,
) {
}
}
impl<S> ProgressReporter for NopEventManager<S> where
S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata
{
}
impl<S> HasEventManagerId for NopEventManager<S> {
fn mgr_id(&self) -> EventManagerId {
EventManagerId(0)
}
}
#[cfg(test)]
mod tests {
use tuple_list::tuple_list_type;
use crate::{
bolts::{
current_time,
tuples::{tuple_list, Named},
},
events::{Event, EventConfig},
executors::ExitKind,
inputs::bytes::BytesInput,
observers::StdMapObserver,
};
static mut MAP: [u32; 4] = [0; 4];
#[test]
fn test_event_serde() {
let obv = unsafe { StdMapObserver::new("test", &mut MAP) };
let map = tuple_list!(obv);
let observers_buf = postcard::to_allocvec(&map).unwrap();
let i = BytesInput::new(vec![0]);
let e = Event::NewTestcase {
input: i,
observers_buf: Some(observers_buf),
exit_kind: ExitKind::Ok,
corpus_size: 123,
client_config: EventConfig::AlwaysUnique,
time: current_time(),
executions: 0,
forward_id: None,
};
let serialized = postcard::to_allocvec(&e).unwrap();
let d = postcard::from_bytes::<Event<BytesInput>>(&serialized).unwrap();
match d {
Event::NewTestcase {
input: _,
observers_buf,
corpus_size: _,
exit_kind: _,
client_config: _,
time: _,
executions: _,
forward_id: _,
} => {
let o: tuple_list_type!(StdMapObserver::<u32, false>) =
postcard::from_bytes(observers_buf.as_ref().unwrap()).unwrap();
assert_eq!("test", o.0.name());
}
_ => panic!("mistmatch"),
};
}
}
#[cfg(feature = "python")]
#[allow(missing_docs)]
pub mod pybind {
use pyo3::prelude::*;
use crate::{
events::{
simple::pybind::PythonSimpleEventManager, Event, EventFirer, EventManager,
EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, ProgressReporter,
},
executors::pybind::PythonExecutor,
fuzzer::pybind::PythonStdFuzzer,
inputs::BytesInput,
state::{pybind::PythonStdState, UsesState},
Error,
};
#[derive(Debug, Clone)]
pub enum PythonEventManagerWrapper {
Simple(Py<PythonSimpleEventManager>),
}
#[pyclass(unsendable, name = "EventManager")]
#[derive(Debug, Clone)]
pub struct PythonEventManager {
pub wrapper: PythonEventManagerWrapper,
}
macro_rules! unwrap_me {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_body!($wrapper, $name, $body, PythonEventManagerWrapper, {
Simple
})
};
}
macro_rules! unwrap_me_mut {
($wrapper:expr, $name:ident, $body:block) => {
crate::unwrap_me_mut_body!($wrapper, $name, $body, PythonEventManagerWrapper, {
Simple
})
};
}
#[pymethods]
impl PythonEventManager {
#[staticmethod]
#[must_use]
pub fn new_simple(mgr: Py<PythonSimpleEventManager>) -> Self {
Self {
wrapper: PythonEventManagerWrapper::Simple(mgr),
}
}
}
impl UsesState for PythonEventManager {
type State = PythonStdState;
}
impl EventFirer for PythonEventManager {
fn fire(&mut self, state: &mut Self::State, event: Event<BytesInput>) -> Result<(), Error> {
unwrap_me_mut!(self.wrapper, e, { e.fire(state, event) })
}
}
impl EventRestarter for PythonEventManager {}
impl EventProcessor<PythonExecutor, PythonStdFuzzer> for PythonEventManager {
fn process(
&mut self,
fuzzer: &mut PythonStdFuzzer,
state: &mut PythonStdState,
executor: &mut PythonExecutor,
) -> Result<usize, Error> {
unwrap_me_mut!(self.wrapper, e, { e.process(fuzzer, state, executor) })
}
}
impl ProgressReporter for PythonEventManager {}
impl HasEventManagerId for PythonEventManager {
fn mgr_id(&self) -> EventManagerId {
unwrap_me!(self.wrapper, e, { e.mgr_id() })
}
}
impl EventManager<PythonExecutor, PythonStdFuzzer> for PythonEventManager {}
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonEventManager>()?;
Ok(())
}
}