libafl/executors/
mod.rs

1//! Executors take input, and run it in the target.
2
3use alloc::vec::Vec;
4use core::{fmt::Debug, time::Duration};
5#[cfg(feature = "std")]
6use std::path::PathBuf;
7
8pub use combined::CombinedExecutor;
9#[cfg(all(feature = "std", unix))]
10pub use command::CommandExecutor;
11pub use differential::DiffExecutor;
12#[cfg(all(feature = "std", feature = "fork", unix))]
13pub use forkserver::{Forkserver, ForkserverExecutor};
14pub use inprocess::InProcessExecutor;
15#[cfg(all(feature = "std", feature = "fork", unix))]
16pub use inprocess_fork::InProcessForkExecutor;
17#[cfg(unix)]
18use libafl_bolts::os::unix_signals::Signal;
19use libafl_bolts::tuples::RefIndexable;
20#[cfg(feature = "std")]
21use libafl_bolts::{core_affinity::CoreId, tuples::Handle};
22use serde::{Deserialize, Serialize};
23pub use shadow::ShadowExecutor;
24pub use with_observers::WithObservers;
25
26use crate::Error;
27#[cfg(feature = "std")]
28use crate::observers::{StdErrObserver, StdOutObserver};
29
30pub mod combined;
31#[cfg(all(feature = "std", unix))]
32pub mod command;
33pub mod differential;
34#[cfg(all(feature = "std", feature = "fork", unix))]
35pub mod forkserver;
36pub mod inprocess;
37pub mod nop;
38/// SAND(<https://github.com/wtdcode/sand-aflpp>) implementation
39pub mod sand;
40
41/// The module for inproc fork executor
42#[cfg(all(feature = "std", unix))]
43pub mod inprocess_fork;
44
45pub mod shadow;
46
47pub mod with_observers;
48
49/// The module for all the hooks
50pub mod hooks;
51
52/// How an execution finished.
53#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
54#[cfg_attr(
55    any(not(feature = "serdeany_autoreg"), miri),
56    expect(clippy::unsafe_derive_deserialize)
57)] // for SerdeAny
58pub enum ExitKind {
59    /// The run exited normally.
60    Ok,
61    /// The run resulted in a target crash.
62    Crash,
63    /// The run hit an out of memory error.
64    Oom,
65    /// The run timed out
66    Timeout,
67    /// Special case for [`DiffExecutor`] when both exitkinds don't match
68    Diff {
69        /// The exitkind of the primary executor
70        primary: DiffExitKind,
71        /// The exitkind of the secondary executor
72        secondary: DiffExitKind,
73    },
74    // The run resulted in a custom `ExitKind`.
75    // Custom(Box<dyn SerdeAny>),
76}
77
78/// How one of the diffing executions finished.
79#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
80#[cfg_attr(
81    any(not(feature = "serdeany_autoreg"), miri),
82    expect(clippy::unsafe_derive_deserialize)
83)] // for SerdeAny
84pub enum DiffExitKind {
85    /// The run exited normally.
86    Ok,
87    /// The run resulted in a target crash.
88    Crash,
89    /// The run hit an out of memory error.
90    Oom,
91    /// The run timed out
92    Timeout,
93    /// One of the executors itelf repots a differential, we can't go into further details.
94    Diff,
95    // The run resulted in a custom `ExitKind`.
96    // Custom(Box<dyn SerdeAny>),
97}
98
99libafl_bolts::impl_serdeany!(ExitKind);
100
101impl From<ExitKind> for DiffExitKind {
102    fn from(exitkind: ExitKind) -> Self {
103        match exitkind {
104            ExitKind::Ok => DiffExitKind::Ok,
105            ExitKind::Crash => DiffExitKind::Crash,
106            ExitKind::Oom => DiffExitKind::Oom,
107            ExitKind::Timeout => DiffExitKind::Timeout,
108            ExitKind::Diff { .. } => DiffExitKind::Diff,
109        }
110    }
111}
112
113libafl_bolts::impl_serdeany!(DiffExitKind);
114
115/// Holds a tuple of Observers
116pub trait HasObservers {
117    /// The observer
118    type Observers;
119
120    /// Get the linked observers
121    fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers>;
122
123    /// Get the linked observers (mutable)
124    fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers>;
125}
126
127/// An executor takes the given inputs, and runs the harness/target.
128pub trait Executor<EM, I, S, Z> {
129    /// Instruct the target about the input and run
130    fn run_target(
131        &mut self,
132        fuzzer: &mut Z,
133        state: &mut S,
134        mgr: &mut EM,
135        input: &I,
136    ) -> Result<ExitKind, Error>;
137}
138
139/// A trait that allows to get/set an `Executor`'s timeout thresold
140pub trait HasTimeout {
141    /// Get a timeout
142    fn timeout(&self) -> Duration;
143
144    /// Set timeout
145    fn set_timeout(&mut self, timeout: Duration);
146}
147
148/// Like [`crate::observers::ObserversTuple`], a list of executors
149pub trait ExecutorsTuple<EM, I, S, Z> {
150    /// Execute the executors and stop if any of them returns a crash
151    fn run_target_all(
152        &mut self,
153        fuzzer: &mut Z,
154        state: &mut S,
155        mgr: &mut EM,
156        input: &I,
157    ) -> Result<ExitKind, Error>;
158}
159
160/// Since in most cases, the executors types can not be determined during compilation
161/// time (for instance, the number of executors might change), this implementation would
162/// act as a small helper.
163impl<E, EM, I, S, Z> ExecutorsTuple<EM, I, S, Z> for Vec<E>
164where
165    E: Executor<EM, I, S, Z>,
166{
167    fn run_target_all(
168        &mut self,
169        fuzzer: &mut Z,
170        state: &mut S,
171        mgr: &mut EM,
172        input: &I,
173    ) -> Result<ExitKind, Error> {
174        let mut kind = ExitKind::Ok;
175        for e in self.iter_mut() {
176            kind = e.run_target(fuzzer, state, mgr, input)?;
177            if kind == ExitKind::Crash {
178                return Ok(kind);
179            }
180        }
181        Ok(kind)
182    }
183}
184
185impl<EM, I, S, Z> ExecutorsTuple<EM, I, S, Z> for () {
186    fn run_target_all(
187        &mut self,
188        _fuzzer: &mut Z,
189        _state: &mut S,
190        _mgr: &mut EM,
191        _input: &I,
192    ) -> Result<ExitKind, Error> {
193        Ok(ExitKind::Ok)
194    }
195}
196
197impl<Head, Tail, EM, I, S, Z> ExecutorsTuple<EM, I, S, Z> for (Head, Tail)
198where
199    Head: Executor<EM, I, S, Z>,
200    Tail: ExecutorsTuple<EM, I, S, Z>,
201{
202    fn run_target_all(
203        &mut self,
204        fuzzer: &mut Z,
205        state: &mut S,
206        mgr: &mut EM,
207        input: &I,
208    ) -> Result<ExitKind, Error> {
209        let kind = self.0.run_target(fuzzer, state, mgr, input)?;
210        if kind == ExitKind::Crash {
211            return Ok(kind);
212        }
213        self.1.run_target_all(fuzzer, state, mgr, input)
214    }
215}
216
217/// The common signals we want to handle
218#[cfg(unix)]
219#[inline]
220#[must_use]
221pub fn common_signals() -> Vec<Signal> {
222    vec![
223        Signal::SigAlarm,
224        Signal::SigUser2,
225        Signal::SigAbort,
226        Signal::SigBus,
227        #[cfg(feature = "handle_sigpipe")]
228        Signal::SigPipe,
229        Signal::SigFloatingPointException,
230        Signal::SigIllegalInstruction,
231        Signal::SigSegmentationFault,
232        Signal::SigTrap,
233    ]
234}
235
236#[cfg(feature = "std")]
237/// The inner shared members of [`StdChildArgs`]
238#[derive(Debug, Clone)]
239pub struct StdChildArgsInner {
240    /// The timeout of the children
241    pub timeout: Duration,
242    /// The stderr handle of the children
243    pub stderr_observer: Option<Handle<StdErrObserver>>,
244    /// The stdout handle of the children
245    pub stdout_observer: Option<Handle<StdOutObserver>>,
246    /// The current directory of the spawned children
247    pub current_directory: Option<PathBuf>,
248    /// Whether debug child by inheriting stdout/stderr
249    pub debug_child: bool,
250    /// Core to bind for the children
251    pub core: Option<CoreId>,
252}
253
254#[cfg(feature = "std")]
255impl Default for StdChildArgsInner {
256    fn default() -> Self {
257        Self {
258            timeout: Duration::from_millis(5000),
259            stderr_observer: None,
260            stdout_observer: None,
261            current_directory: None,
262            debug_child: false,
263            core: None,
264        }
265    }
266}
267
268#[cfg(feature = "std")]
269/// The shared implementation for children with stdout/stderr/timeouts.
270pub trait StdChildArgs: Sized {
271    /// The inner struct of child environment.
272    fn inner(&self) -> &StdChildArgsInner;
273
274    /// The mutable inner struct of child environment.
275    fn inner_mut(&mut self) -> &mut StdChildArgsInner;
276
277    #[must_use]
278    /// Sets the execution timeout duration.
279    fn timeout(mut self, timeout: Duration) -> Self {
280        self.inner_mut().timeout = timeout;
281        self
282    }
283
284    #[must_use]
285    /// Sets the stdout observer
286    fn stdout_observer(mut self, stdout: Handle<StdOutObserver>) -> Self {
287        self.inner_mut().stdout_observer = Some(stdout);
288        self
289    }
290
291    #[must_use]
292    /// Sets the stderr observer
293    fn stderr_observer(mut self, stderr: Handle<StdErrObserver>) -> Self {
294        self.inner_mut().stderr_observer = Some(stderr);
295        self
296    }
297
298    #[must_use]
299    /// Sets the working directory for the child process.
300    fn current_dir(mut self, current_dir: PathBuf) -> Self {
301        self.inner_mut().current_directory = Some(current_dir);
302        self
303    }
304
305    #[must_use]
306    /// If set to true, the child's output won't be redirecited to `/dev/null` and will go to parent's stdout/stderr
307    /// Defaults to `false`.
308    fn debug_child(mut self, debug_child: bool) -> Self {
309        if debug_child {
310            assert!(
311                self.inner().stderr_observer.is_none() && self.inner().stdout_observer.is_none(),
312                "you can not set debug_child when you have stderr_observer or stdout_observer"
313            );
314        }
315        self.inner_mut().debug_child = debug_child;
316        self
317    }
318
319    #[must_use]
320    /// Set the core to bind for the children
321    fn core(mut self, core: CoreId) -> Self {
322        self.inner_mut().core = Some(core);
323        self
324    }
325}
326
327#[cfg(test)]
328/// Tester for executor
329pub mod test {
330    use super::nop::NopExecutor;
331    use crate::{
332        events::NopEventManager,
333        executors::{Executor, ExitKind},
334        fuzzer::NopFuzzer,
335        inputs::BytesInput,
336        state::NopState,
337    };
338
339    #[test]
340    fn nop_executor() {
341        let empty_input = BytesInput::new(vec![]);
342        let mut executor = NopExecutor::ok();
343        let mut fuzzer = NopFuzzer::new();
344        let mut mgr: NopEventManager = NopEventManager::new();
345        let mut state: NopState<BytesInput> = NopState::new();
346
347        assert_eq!(
348            executor
349                .run_target(&mut fuzzer, &mut state, &mut mgr, &empty_input)
350                .unwrap(),
351            ExitKind::Ok
352        );
353    }
354}