Skip to content

Commit

Permalink
Make exit status interpretable by CommandConfigurator (AFLplusplus#2723)
Browse files Browse the repository at this point in the history
* Make exit status interpretable by CommandConfigurator

* Fix import issues

* Fix default implementation for non-unix environment

* Make docs only available on unix if the entry is only for unix

* Revert "Fix default implementation for non-unix environment"

This reverts commit 5457f6f.

* Fix the invalid link in the example
  • Loading branch information
momvart authored Nov 27, 2024
1 parent 94fa401 commit 0d0bbf0
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 23 deletions.
44 changes: 24 additions & 20 deletions libafl/src/executors/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ use typed_builder::TypedBuilder;

use super::HasTimeout;
#[cfg(all(feature = "std", unix))]
use crate::executors::{Executor, ExitKind};
use crate::executors::Executor;
#[cfg(all(feature = "std", any(unix, doc)))]
use crate::executors::ExitKind;
use crate::{
corpus::Corpus,
executors::{hooks::ExecutorHooksTuple, HasObservers},
Expand Down Expand Up @@ -337,38 +339,28 @@ where
OT: Debug + ObserversTuple<I, S>,
{
fn execute_input_with_command(&mut self, state: &mut S, input: &I) -> Result<ExitKind, Error> {
use std::os::unix::prelude::ExitStatusExt;

use wait_timeout::ChildExt;

*state.executions_mut() += 1;
self.observers.pre_exec_child_all(state, input)?;

let mut child = self.configurer.spawn_child(input)?;

let res = match child
let exit_kind = child
.wait_timeout(self.configurer.exec_timeout())
.expect("waiting on child failed")
.map(|status| status.signal())
{
// for reference: https://www.man7.org/linux/man-pages/man7/signal.7.html
Some(Some(9)) => Ok(ExitKind::Oom),
Some(Some(_)) => Ok(ExitKind::Crash),
Some(None) => Ok(ExitKind::Ok),
None => {
.map(|status| self.configurer.exit_kind_from_status(&status))
.unwrap_or_else(|| {
// if this fails, there is not much we can do. let's hope it failed because the process finished
// in the meantime.
drop(child.kill());
// finally, try to wait to properly clean up system resources.
drop(child.wait());
Ok(ExitKind::Timeout)
}
};
ExitKind::Timeout
});

if let Ok(exit_kind) = res {
self.observers
.post_exec_child_all(state, input, &exit_kind)?;
}
self.observers
.post_exec_child_all(state, input, &exit_kind)?;

if let Some(h) = &mut self.configurer.stdout_observer() {
let mut stdout = Vec::new();
Expand All @@ -392,7 +384,7 @@ where
let obs = observers.index_mut(h);
obs.observe_stderr(&stderr);
}
res
Ok(exit_kind)
}
}

Expand Down Expand Up @@ -809,7 +801,7 @@ impl CommandExecutorBuilder {
/// MyExecutor.into_executor(())
/// }
/// ```
#[cfg(all(feature = "std", any(unix, doc)))]
#[cfg(all(feature = "std", unix))]
pub trait CommandConfigurator<I, C = Child>: Sized {
/// Get the stdout
fn stdout_observer(&self) -> Option<Handle<StdOutObserver>> {
Expand All @@ -828,6 +820,18 @@ pub trait CommandConfigurator<I, C = Child>: Sized {
/// Set the timeout duration for execution of the child process.
fn exec_timeout_mut(&mut self) -> &mut Duration;

/// Maps the exit status of the child process to an `ExitKind`.
#[inline]
fn exit_kind_from_status(&self, status: &std::process::ExitStatus) -> ExitKind {
use crate::std::os::unix::process::ExitStatusExt;
match status.signal() {
// for reference: https://www.man7.org/linux/man-pages/man7/signal.7.html
Some(9) => ExitKind::Oom,
Some(_) => ExitKind::Crash,
None => ExitKind::Ok,
}
}

/// Create an `Executor` from this `CommandConfigurator`.
fn into_executor<OT, S>(self, observers: OT) -> CommandExecutor<OT, S, Self, (), C>
where
Expand Down
4 changes: 2 additions & 2 deletions libafl/src/executors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use alloc::vec::Vec;
use core::{fmt::Debug, time::Duration};

pub use combined::CombinedExecutor;
#[cfg(all(feature = "std", any(unix, doc)))]
#[cfg(all(feature = "std", unix))]
pub use command::CommandExecutor;
pub use differential::DiffExecutor;
#[cfg(all(feature = "std", feature = "fork", unix))]
Expand All @@ -23,7 +23,7 @@ pub use with_observers::WithObservers;
use crate::{state::UsesState, Error};

pub mod combined;
#[cfg(all(feature = "std", any(unix, doc)))]
#[cfg(all(feature = "std", unix))]
pub mod command;
pub mod differential;
#[cfg(all(feature = "std", feature = "fork", unix))]
Expand Down
5 changes: 4 additions & 1 deletion libafl/src/observers/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
//!
//! The [`StdOutObserver`] and [`StdErrObserver`] observers look at the stdout of a program
//! The executor must explicitly support these observers.
//! For example, they are supported on the [`crate::executors::CommandExecutor`].
#![cfg_attr(
all(feature = "std", unix),
doc = r"For example, they are supported on the [`crate::executors::CommandExecutor`]."
)]

use alloc::borrow::Cow;
use std::vec::Vec;
Expand Down

0 comments on commit 0d0bbf0

Please sign in to comment.