use alloc::vec::Vec;
use core::{fmt::Debug, time::Duration};
#[cfg(feature = "std")]
use std::path::PathBuf;
pub use combined::CombinedExecutor;
#[cfg(feature = "std")]
pub use command::CommandExecutor;
pub use differential::DiffExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub use forkserver::{Forkserver, ForkserverExecutor};
pub use inprocess::InProcessExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub use inprocess_fork::InProcessForkExecutor;
#[cfg(unix)]
use libafl_bolts::os::unix_signals::Signal;
use libafl_bolts::tuples::RefIndexable;
#[cfg(feature = "std")]
use libafl_bolts::{core_affinity::CoreId, tuples::Handle};
use serde::{Deserialize, Serialize};
pub use shadow::ShadowExecutor;
pub use with_observers::WithObservers;
use crate::Error;
#[cfg(feature = "std")]
use crate::observers::{StdErrObserver, StdOutObserver};
pub mod combined;
#[cfg(feature = "std")]
pub mod command;
pub mod differential;
#[cfg(all(feature = "std", feature = "fork", unix))]
pub mod forkserver;
pub mod inprocess;
pub mod nop;
pub mod sand;
#[cfg(all(feature = "std", unix))]
pub mod inprocess_fork;
pub mod shadow;
pub mod with_observers;
pub mod hooks;
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(
any(not(feature = "serdeany_autoreg"), miri),
expect(clippy::unsafe_derive_deserialize)
)] pub enum ExitKind {
Ok,
Crash,
Oom,
Timeout,
Diff {
primary: DiffExitKind,
secondary: DiffExitKind,
},
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(
any(not(feature = "serdeany_autoreg"), miri),
expect(clippy::unsafe_derive_deserialize)
)] pub enum DiffExitKind {
Ok,
Crash,
Oom,
Timeout,
Diff,
}
libafl_bolts::impl_serdeany!(ExitKind);
impl From<ExitKind> for DiffExitKind {
fn from(exitkind: ExitKind) -> Self {
match exitkind {
ExitKind::Ok => DiffExitKind::Ok,
ExitKind::Crash => DiffExitKind::Crash,
ExitKind::Oom => DiffExitKind::Oom,
ExitKind::Timeout => DiffExitKind::Timeout,
ExitKind::Diff { .. } => DiffExitKind::Diff,
}
}
}
libafl_bolts::impl_serdeany!(DiffExitKind);
pub trait HasObservers {
type Observers;
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers>;
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers>;
}
pub trait Executor<EM, I, S, Z> {
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<ExitKind, Error>;
}
pub trait HasTimeout {
fn timeout(&self) -> Duration;
}
pub trait SetTimeout {
fn set_timeout(&mut self, timeout: Duration);
}
pub trait ExecutorsTuple<EM, I, S, Z> {
fn run_target_all(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<ExitKind, Error>;
}
impl<E, EM, I, S, Z> ExecutorsTuple<EM, I, S, Z> for Vec<E>
where
E: Executor<EM, I, S, Z>,
{
fn run_target_all(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<ExitKind, Error> {
let mut kind = ExitKind::Ok;
for e in self.iter_mut() {
kind = e.run_target(fuzzer, state, mgr, input)?;
if kind == ExitKind::Crash {
return Ok(kind);
}
}
Ok(kind)
}
}
impl<EM, I, S, Z> ExecutorsTuple<EM, I, S, Z> for () {
fn run_target_all(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<ExitKind, Error> {
Ok(ExitKind::Ok)
}
}
impl<Head, Tail, EM, I, S, Z> ExecutorsTuple<EM, I, S, Z> for (Head, Tail)
where
Head: Executor<EM, I, S, Z>,
Tail: ExecutorsTuple<EM, I, S, Z>,
{
fn run_target_all(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<ExitKind, Error> {
let kind = self.0.run_target(fuzzer, state, mgr, input)?;
if kind == ExitKind::Crash {
return Ok(kind);
}
self.1.run_target_all(fuzzer, state, mgr, input)
}
}
#[cfg(unix)]
#[inline]
#[must_use]
pub fn common_signals() -> Vec<Signal> {
vec![
Signal::SigAlarm,
Signal::SigUser2,
Signal::SigAbort,
Signal::SigBus,
#[cfg(feature = "handle_sigpipe")]
Signal::SigPipe,
Signal::SigFloatingPointException,
Signal::SigIllegalInstruction,
Signal::SigSegmentationFault,
Signal::SigTrap,
]
}
#[cfg(feature = "std")]
#[derive(Debug, Clone)]
pub struct StdChildArgsInner {
pub timeout: Duration,
pub stderr_observer: Option<Handle<StdErrObserver>>,
pub stdout_observer: Option<Handle<StdOutObserver>>,
pub current_directory: Option<PathBuf>,
pub debug_child: bool,
pub core: Option<CoreId>,
}
#[cfg(feature = "std")]
impl Default for StdChildArgsInner {
fn default() -> Self {
Self {
timeout: Duration::from_millis(5000),
stderr_observer: None,
stdout_observer: None,
current_directory: None,
debug_child: false,
core: None,
}
}
}
#[cfg(feature = "std")]
pub trait StdChildArgs: Sized {
fn inner(&self) -> &StdChildArgsInner;
fn inner_mut(&mut self) -> &mut StdChildArgsInner;
#[must_use]
fn timeout(mut self, timeout: Duration) -> Self {
self.inner_mut().timeout = timeout;
self
}
#[must_use]
fn stdout_observer(mut self, stdout: Handle<StdOutObserver>) -> Self {
self.inner_mut().stdout_observer = Some(stdout);
self
}
#[must_use]
fn stderr_observer(mut self, stderr: Handle<StdErrObserver>) -> Self {
self.inner_mut().stderr_observer = Some(stderr);
self
}
#[must_use]
fn current_dir(mut self, current_dir: PathBuf) -> Self {
self.inner_mut().current_directory = Some(current_dir);
self
}
#[must_use]
fn debug_child(mut self, debug_child: bool) -> Self {
if debug_child {
assert!(
self.inner().stderr_observer.is_none() && self.inner().stdout_observer.is_none(),
"you can not set debug_child when you have stderr_observer or stdout_observer"
);
}
self.inner_mut().debug_child = debug_child;
self
}
#[must_use]
fn core(mut self, core: CoreId) -> Self {
self.inner_mut().core = Some(core);
self
}
}
#[cfg(test)]
pub mod test {
use super::nop::NopExecutor;
use crate::{
events::NopEventManager,
executors::{Executor, ExitKind},
fuzzer::NopFuzzer,
inputs::BytesInput,
state::NopState,
};
#[test]
fn nop_executor() {
let empty_input = BytesInput::new(vec![]);
let mut executor = NopExecutor::ok();
let mut fuzzer = NopFuzzer::new();
let mut mgr: NopEventManager = NopEventManager::new();
let mut state: NopState<BytesInput> = NopState::new();
assert_eq!(
executor
.run_target(&mut fuzzer, &mut state, &mut mgr, &empty_input)
.unwrap(),
ExitKind::Ok
);
}
}