1use 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;
38pub mod sand;
40
41#[cfg(all(feature = "std", unix))]
43pub mod inprocess_fork;
44
45pub mod shadow;
46
47pub mod with_observers;
48
49pub mod hooks;
51
52#[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)] pub enum ExitKind {
59 Ok,
61 Crash,
63 Oom,
65 Timeout,
67 Diff {
69 primary: DiffExitKind,
71 secondary: DiffExitKind,
73 },
74 }
77
78#[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)] pub enum DiffExitKind {
85 Ok,
87 Crash,
89 Oom,
91 Timeout,
93 Diff,
95 }
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
115pub trait HasObservers {
117 type Observers;
119
120 fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers>;
122
123 fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers>;
125}
126
127pub trait Executor<EM, I, S, Z> {
129 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
139pub trait HasTimeout {
141 fn timeout(&self) -> Duration;
143
144 fn set_timeout(&mut self, timeout: Duration);
146}
147
148pub trait ExecutorsTuple<EM, I, S, Z> {
150 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
160impl<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#[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#[derive(Debug, Clone)]
239pub struct StdChildArgsInner {
240 pub timeout: Duration,
242 pub stderr_observer: Option<Handle<StdErrObserver>>,
244 pub stdout_observer: Option<Handle<StdOutObserver>>,
246 pub current_directory: Option<PathBuf>,
248 pub debug_child: bool,
250 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")]
269pub trait StdChildArgs: Sized {
271 fn inner(&self) -> &StdChildArgsInner;
273
274 fn inner_mut(&mut self) -> &mut StdChildArgsInner;
276
277 #[must_use]
278 fn timeout(mut self, timeout: Duration) -> Self {
280 self.inner_mut().timeout = timeout;
281 self
282 }
283
284 #[must_use]
285 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 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 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 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 fn core(mut self, core: CoreId) -> Self {
322 self.inner_mut().core = Some(core);
323 self
324 }
325}
326
327#[cfg(test)]
328pub 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}