Remove observer_stdout/observer_stderr from Observer trait (#2167)
* stuff * upd * cargo test * doc * fmt * nyx stuff
This commit is contained in:
parent
5872d24021
commit
bf4d1de7cd
@ -19,7 +19,7 @@ use libafl_bolts::{
|
||||
shmem::{ShMemProvider, StdShMemProvider},
|
||||
tuples::tuple_list,
|
||||
};
|
||||
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};
|
||||
use libafl_nyx::{executor::NyxExecutorBuilder, helper::NyxHelper, settings::NyxSettings};
|
||||
|
||||
fn main() {
|
||||
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
||||
@ -54,7 +54,7 @@ fn main() {
|
||||
let mut feedback = MaxMapFeedback::new(&observer);
|
||||
let mut objective = CrashFeedback::new();
|
||||
let scheduler = RandScheduler::new();
|
||||
let mut executor = NyxExecutor::new(helper, tuple_list!(observer));
|
||||
let mut executor = NyxExecutorBuilder::new().build(helper, tuple_list!(observer));
|
||||
|
||||
// If not restarting, create a State from scratch
|
||||
let mut state = state.unwrap_or_else(|| {
|
||||
|
@ -14,7 +14,7 @@ use libafl::{
|
||||
Fuzzer, StdFuzzer,
|
||||
};
|
||||
use libafl_bolts::{rands::StdRand, tuples::tuple_list};
|
||||
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};
|
||||
use libafl_nyx::{executor::NyxExecutorBuilder, helper::NyxHelper, settings::NyxSettings};
|
||||
|
||||
fn main() {
|
||||
// nyx stuff
|
||||
@ -44,7 +44,7 @@ fn main() {
|
||||
let monitor = TuiMonitor::new(ui);
|
||||
|
||||
let mut mgr = SimpleEventManager::new(monitor);
|
||||
let mut executor = NyxExecutor::new(helper, tuple_list!(observer));
|
||||
let mut executor = NyxExecutorBuilder::new().build(helper, tuple_list!(observer));
|
||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
|
||||
|
@ -22,17 +22,17 @@ use libafl_bolts::{
|
||||
AsSlice,
|
||||
};
|
||||
|
||||
use super::HasObservers;
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
use crate::executors::{Executor, ExitKind};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{inputs::Input, Error};
|
||||
use crate::{
|
||||
executors::HasObservers,
|
||||
inputs::{HasTargetBytes, UsesInput},
|
||||
observers::{ObserversTuple, UsesObservers},
|
||||
observers::{ObserversTuple, StdErrObserver, StdOutObserver, UsesObservers},
|
||||
state::{HasExecutions, State, UsesState},
|
||||
std::borrow::ToOwned,
|
||||
};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::{inputs::Input, Error};
|
||||
|
||||
/// How to deliver input to an external program
|
||||
/// `StdIn`: The target reads from stdin
|
||||
@ -54,21 +54,6 @@ pub enum InputLocation {
|
||||
},
|
||||
}
|
||||
|
||||
/// Clones a [`Command`] (without stdio and stdout/stderr - they are not accesible)
|
||||
fn clone_command(cmd: &Command) -> Command {
|
||||
let mut new_cmd = Command::new(cmd.get_program());
|
||||
new_cmd.args(cmd.get_args());
|
||||
new_cmd.env_clear();
|
||||
new_cmd.envs(
|
||||
cmd.get_envs()
|
||||
.filter_map(|(key, value)| value.map(|value| (key, value))),
|
||||
);
|
||||
if let Some(cwd) = cmd.get_current_dir() {
|
||||
new_cmd.current_dir(cwd);
|
||||
}
|
||||
new_cmd
|
||||
}
|
||||
|
||||
/// A simple Configurator that takes the most common parameters
|
||||
/// Writes the input either to stdio or to a file
|
||||
/// Use [`CommandExecutor::builder()`] to use this configurator.
|
||||
@ -78,8 +63,8 @@ pub struct StdCommandConfigurator {
|
||||
/// If set to true, the child output will remain visible
|
||||
/// By default, the child output is hidden to increase execution speed
|
||||
debug_child: bool,
|
||||
has_stdout_observer: bool,
|
||||
has_stderr_observer: bool,
|
||||
stdout_observer: Option<StdOutObserver>,
|
||||
stderr_observer: Option<StdErrObserver>,
|
||||
timeout: Duration,
|
||||
/// true: input gets delivered via stdink
|
||||
input_location: InputLocation,
|
||||
@ -91,6 +76,22 @@ impl<I> CommandConfigurator<I> for StdCommandConfigurator
|
||||
where
|
||||
I: HasTargetBytes,
|
||||
{
|
||||
fn stdout_observer(&self) -> Option<&StdOutObserver> {
|
||||
self.stdout_observer.as_ref()
|
||||
}
|
||||
|
||||
fn stdout_observer_mut(&mut self) -> Option<&mut StdOutObserver> {
|
||||
self.stdout_observer.as_mut()
|
||||
}
|
||||
|
||||
fn stderr_observer(&self) -> Option<&StdErrObserver> {
|
||||
self.stderr_observer.as_ref()
|
||||
}
|
||||
|
||||
fn stderr_observer_mut(&mut self) -> Option<&mut StdErrObserver> {
|
||||
self.stderr_observer.as_mut()
|
||||
}
|
||||
|
||||
fn spawn_child(&mut self, input: &I) -> Result<Child, Error> {
|
||||
match &mut self.input_location {
|
||||
InputLocation::Arg { argnum } => {
|
||||
@ -102,10 +103,10 @@ where
|
||||
cmd.stderr(Stdio::null());
|
||||
}
|
||||
|
||||
if self.has_stdout_observer {
|
||||
if self.stdout_observer.is_some() {
|
||||
cmd.stdout(Stdio::piped());
|
||||
}
|
||||
if self.has_stderr_observer {
|
||||
if self.stderr_observer.is_some() {
|
||||
cmd.stderr(Stdio::piped());
|
||||
}
|
||||
|
||||
@ -213,102 +214,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<OT, S> CommandExecutor<OT, S, StdCommandConfigurator>
|
||||
where
|
||||
OT: MatchName + ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
{
|
||||
/// Creates a new `CommandExecutor`.
|
||||
/// Instead of parsing the Command for `@@`, it will
|
||||
pub fn from_cmd_with_file<P>(
|
||||
cmd: &Command,
|
||||
debug_child: bool,
|
||||
timeout: Duration,
|
||||
observers: OT,
|
||||
path: P,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut command = clone_command(cmd);
|
||||
if !debug_child {
|
||||
command.stdout(Stdio::null());
|
||||
command.stderr(Stdio::null());
|
||||
}
|
||||
command.stdin(Stdio::null());
|
||||
|
||||
let has_stdout_observer = observers.observes_stdout();
|
||||
if has_stdout_observer {
|
||||
command.stdout(Stdio::piped());
|
||||
}
|
||||
let has_stderr_observer = observers.observes_stderr();
|
||||
if has_stderr_observer {
|
||||
command.stderr(Stdio::piped());
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
observers,
|
||||
configurer: StdCommandConfigurator {
|
||||
input_location: InputLocation::File {
|
||||
out_file: InputFile::create(path)?,
|
||||
},
|
||||
command,
|
||||
debug_child,
|
||||
has_stdout_observer,
|
||||
has_stderr_observer,
|
||||
timeout,
|
||||
},
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses an AFL-like commandline, replacing `@@` with the input file
|
||||
/// generated by the fuzzer (similar to the `afl-fuzz` command line).
|
||||
///
|
||||
/// If no `@@` was found, will use stdin for input.
|
||||
/// The arg 0 is the program.
|
||||
pub fn parse_afl_cmdline<IT, O>(
|
||||
args: IT,
|
||||
observers: OT,
|
||||
debug_child: bool,
|
||||
timeout: Duration,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
IT: IntoIterator<Item = O>,
|
||||
O: AsRef<OsStr>,
|
||||
{
|
||||
let mut atat_at = None;
|
||||
let mut builder = CommandExecutorBuilder::new();
|
||||
builder.debug_child(debug_child);
|
||||
builder.timeout(timeout);
|
||||
let afl_delim = OsStr::new("@@");
|
||||
|
||||
for (pos, arg) in args.into_iter().enumerate() {
|
||||
if pos == 0 {
|
||||
if arg.as_ref() == afl_delim {
|
||||
return Err(Error::illegal_argument(
|
||||
"The first argument must not be @@ but the program to execute",
|
||||
));
|
||||
}
|
||||
builder.program(arg);
|
||||
} else if arg.as_ref() == afl_delim {
|
||||
if atat_at.is_some() {
|
||||
return Err(Error::illegal_argument(
|
||||
"Multiple @@ in afl commandline are not permitted",
|
||||
));
|
||||
}
|
||||
atat_at = Some(pos);
|
||||
builder.arg_input_file_std();
|
||||
} else {
|
||||
builder.arg(arg);
|
||||
}
|
||||
}
|
||||
|
||||
builder.build(observers)
|
||||
}
|
||||
}
|
||||
|
||||
// this only works on unix because of the reliance on checking the process signal for detecting OOM
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
impl<EM, OT, S, T, Z> Executor<EM, Z> for CommandExecutor<OT, S, T>
|
||||
@ -353,25 +258,24 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
if self.observers.observes_stderr() {
|
||||
if let Some(ref mut ob) = &mut self.configurer.stdout_observer_mut() {
|
||||
let mut stdout = Vec::new();
|
||||
child.stdout.as_mut().ok_or_else(|| {
|
||||
Error::illegal_state(
|
||||
"Observer tries to read stderr, but stderr was not `Stdio::pipe` in CommandExecutor",
|
||||
)
|
||||
})?.read_to_end(&mut stdout)?;
|
||||
ob.observe_stdout(&stdout);
|
||||
}
|
||||
if let Some(ref mut ob) = &mut self.configurer.stderr_observer_mut() {
|
||||
let mut stderr = Vec::new();
|
||||
child.stderr.as_mut().ok_or_else(|| {
|
||||
Error::illegal_state(
|
||||
"Observer tries to read stderr, but stderr was not `Stdio::pipe` in CommandExecutor",
|
||||
)
|
||||
})?.read_to_end(&mut stderr)?;
|
||||
self.observers.observe_stderr(&stderr);
|
||||
ob.observe_stderr(&stderr);
|
||||
}
|
||||
if self.observers.observes_stdout() {
|
||||
let mut stdout = Vec::new();
|
||||
child.stdout.as_mut().ok_or_else(|| {
|
||||
Error::illegal_state(
|
||||
"Observer tries to read stdout, but stdout was not `Stdio::pipe` in CommandExecutor",
|
||||
)
|
||||
})?.read_to_end(&mut stdout)?;
|
||||
self.observers.observe_stdout(&stdout);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
@ -409,6 +313,8 @@ where
|
||||
/// The builder for a default [`CommandExecutor`] that should fit most use-cases.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CommandExecutorBuilder {
|
||||
stdout: Option<StdOutObserver>,
|
||||
stderr: Option<StdErrObserver>,
|
||||
debug_child: bool,
|
||||
program: Option<OsString>,
|
||||
args: Vec<OsString>,
|
||||
@ -429,6 +335,8 @@ impl CommandExecutorBuilder {
|
||||
#[must_use]
|
||||
fn new() -> CommandExecutorBuilder {
|
||||
CommandExecutorBuilder {
|
||||
stdout: None,
|
||||
stderr: None,
|
||||
program: None,
|
||||
args: vec![],
|
||||
input_location: InputLocation::StdIn,
|
||||
@ -468,7 +376,19 @@ impl CommandExecutorBuilder {
|
||||
pub fn arg_input_arg(&mut self) -> &mut Self {
|
||||
let argnum = self.args.len();
|
||||
self.input(InputLocation::Arg { argnum });
|
||||
self.arg("DUMMY");
|
||||
// self.arg("DUMMY");
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the stdout observer
|
||||
pub fn stdout_observer(&mut self, stdout: StdOutObserver) -> &mut Self {
|
||||
self.stdout = Some(stdout);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the stderr observer
|
||||
pub fn stderr_observer(&mut self, stderr: StdErrObserver) -> &mut Self {
|
||||
self.stderr = Some(stderr);
|
||||
self
|
||||
}
|
||||
|
||||
@ -493,18 +413,12 @@ impl CommandExecutorBuilder {
|
||||
}
|
||||
|
||||
/// Adds an argument to the program's commandline.
|
||||
///
|
||||
/// You may want to use [`CommandExecutor::parse_afl_cmdline`] if you're going to pass `@@`
|
||||
/// represents the input file generated by the fuzzer (similar to the `afl-fuzz` command line).
|
||||
pub fn arg<O: AsRef<OsStr>>(&mut self, arg: O) -> &mut CommandExecutorBuilder {
|
||||
self.args.push(arg.as_ref().to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a range of arguments to the program's commandline.
|
||||
///
|
||||
/// You may want to use [`CommandExecutor::parse_afl_cmdline`] if you're going to pass `@@`
|
||||
/// represents the input file generated by the fuzzer (similar to the `afl-fuzz` command line).
|
||||
pub fn args<IT, O>(&mut self, args: IT) -> &mut CommandExecutorBuilder
|
||||
where
|
||||
IT: IntoIterator<Item = O>,
|
||||
@ -597,18 +511,19 @@ impl CommandExecutorBuilder {
|
||||
command.stdout(Stdio::null());
|
||||
command.stderr(Stdio::null());
|
||||
}
|
||||
if observers.observes_stdout() {
|
||||
|
||||
if self.stdout.is_some() {
|
||||
command.stdout(Stdio::piped());
|
||||
}
|
||||
if observers.observes_stderr() {
|
||||
// we need stderr for `AsanBacktaceObserver`, and others
|
||||
|
||||
if self.stderr.is_some() {
|
||||
command.stderr(Stdio::piped());
|
||||
}
|
||||
|
||||
let configurator = StdCommandConfigurator {
|
||||
debug_child: self.debug_child,
|
||||
has_stdout_observer: observers.observes_stdout(),
|
||||
has_stderr_observer: observers.observes_stderr(),
|
||||
stdout_observer: self.stdout.clone(),
|
||||
stderr_observer: self.stderr.clone(),
|
||||
input_location: self.input_location.clone(),
|
||||
timeout: self.timeout,
|
||||
command,
|
||||
@ -666,6 +581,24 @@ impl CommandExecutorBuilder {
|
||||
|
||||
#[cfg(all(feature = "std", any(unix, doc)))]
|
||||
pub trait CommandConfigurator<I>: Sized {
|
||||
/// Get the stdout
|
||||
fn stdout_observer(&self) -> Option<&StdOutObserver> {
|
||||
None
|
||||
}
|
||||
/// Get the mut stdout
|
||||
fn stdout_observer_mut(&mut self) -> Option<&mut StdOutObserver> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get the stderr
|
||||
fn stderr_observer(&self) -> Option<&StdErrObserver> {
|
||||
None
|
||||
}
|
||||
/// Get the mut stderr
|
||||
fn stderr_observer_mut(&mut self) -> Option<&mut StdErrObserver> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Spawns a new process with the given configuration.
|
||||
fn spawn_child(&mut self, input: &I) -> Result<Child, Error>;
|
||||
|
||||
@ -678,8 +611,8 @@ pub trait CommandConfigurator<I>: Sized {
|
||||
OT: MatchName,
|
||||
{
|
||||
CommandExecutor {
|
||||
observers,
|
||||
configurer: self,
|
||||
observers,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -723,32 +656,4 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
#[cfg_attr(miri, ignore)]
|
||||
fn test_parse_afl_cmdline() {
|
||||
use alloc::string::ToString;
|
||||
use core::time::Duration;
|
||||
|
||||
let mut mgr = SimpleEventManager::new(SimpleMonitor::new(|status| {
|
||||
log::info!("{status}");
|
||||
}));
|
||||
|
||||
let mut executor = CommandExecutor::parse_afl_cmdline(
|
||||
["file".to_string(), "@@".to_string()],
|
||||
(),
|
||||
true,
|
||||
Duration::from_secs(5),
|
||||
)
|
||||
.unwrap();
|
||||
executor
|
||||
.run_target(
|
||||
&mut NopFuzzer::new(),
|
||||
&mut NopState::new(),
|
||||
&mut mgr,
|
||||
&BytesInput::new(b"test".to_vec()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -155,29 +155,6 @@ where
|
||||
self.differential
|
||||
.post_exec_child_all(state, input, exit_kind)
|
||||
}
|
||||
|
||||
/// Returns true if a `stdout` observer was added to the list
|
||||
#[inline]
|
||||
fn observes_stdout(&self) -> bool {
|
||||
self.primary.as_ref().observes_stdout() || self.secondary.as_ref().observes_stdout()
|
||||
}
|
||||
/// Returns true if a `stderr` observer was added to the list
|
||||
#[inline]
|
||||
fn observes_stderr(&self) -> bool {
|
||||
self.primary.as_ref().observes_stderr() || self.secondary.as_ref().observes_stderr()
|
||||
}
|
||||
|
||||
/// Runs `observe_stdout` for all stdout observers in the list
|
||||
fn observe_stdout(&mut self, stdout: &[u8]) {
|
||||
self.primary.as_mut().observe_stderr(stdout);
|
||||
self.secondary.as_mut().observe_stderr(stdout);
|
||||
}
|
||||
|
||||
/// Runs `observe_stderr` for all stderr observers in the list
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||
self.primary.as_mut().observe_stderr(stderr);
|
||||
self.secondary.as_mut().observe_stderr(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, DOT> MatchName for ProxyObserversTuple<A, B, DOT>
|
||||
|
@ -186,22 +186,6 @@ where
|
||||
) -> Result<(), Error> {
|
||||
self.0.post_exec_child(state, input, exit_kind)
|
||||
}
|
||||
|
||||
fn observes_stdout(&self) -> bool {
|
||||
self.0.observes_stdout()
|
||||
}
|
||||
|
||||
fn observes_stderr(&self) -> bool {
|
||||
self.0.observes_stderr()
|
||||
}
|
||||
|
||||
fn observe_stdout(&mut self, stdout: &[u8]) {
|
||||
self.0.observe_stdout(stdout);
|
||||
}
|
||||
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||
self.0.observe_stderr(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T, OTA, OTB, const ITH: bool, const NTH: bool> DifferentialObserver<OTA, OTB, S>
|
||||
|
@ -81,29 +81,6 @@ where
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// If this observer observes `stdout`
|
||||
#[inline]
|
||||
fn observes_stdout(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// If this observer observes `stderr`
|
||||
#[inline]
|
||||
fn observes_stderr(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// React to new `stdout`
|
||||
/// To use this, always return `true` from `observes_stdout`
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
fn observe_stdout(&mut self, stdout: &[u8]) {}
|
||||
|
||||
/// React to new `stderr`
|
||||
/// To use this, always return `true` from `observes_stderr`
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {}
|
||||
}
|
||||
|
||||
/// Defines the observer type shared across traits of the type.
|
||||
@ -139,16 +116,6 @@ where
|
||||
input: &S::Input,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Returns true if a `stdout` observer was added to the list
|
||||
fn observes_stdout(&self) -> bool;
|
||||
/// Returns true if a `stderr` observer was added to the list
|
||||
fn observes_stderr(&self) -> bool;
|
||||
|
||||
/// Runs `observe_stdout` for all stdout observers in the list
|
||||
fn observe_stdout(&mut self, stdout: &[u8]);
|
||||
/// Runs `observe_stderr` for all stderr observers in the list
|
||||
fn observe_stderr(&mut self, stderr: &[u8]);
|
||||
}
|
||||
|
||||
impl<S> ObserversTuple<S> for ()
|
||||
@ -180,28 +147,6 @@ where
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns true if a `stdout` observer was added to the list
|
||||
#[inline]
|
||||
fn observes_stdout(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns true if a `stderr` observer was added to the list
|
||||
#[inline]
|
||||
fn observes_stderr(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Runs `observe_stdout` for all stdout observers in the list
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
fn observe_stdout(&mut self, stdout: &[u8]) {}
|
||||
|
||||
/// Runs `observe_stderr` for all stderr observers in the list
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {}
|
||||
}
|
||||
|
||||
impl<Head, Tail, S> ObserversTuple<S> for (Head, Tail)
|
||||
@ -239,32 +184,6 @@ where
|
||||
self.0.post_exec_child(state, input, exit_kind)?;
|
||||
self.1.post_exec_child_all(state, input, exit_kind)
|
||||
}
|
||||
|
||||
/// Returns true if a `stdout` observer was added to the list
|
||||
#[inline]
|
||||
fn observes_stdout(&self) -> bool {
|
||||
self.0.observes_stdout() || self.1.observes_stdout()
|
||||
}
|
||||
|
||||
/// Returns true if a `stderr` observer was added to the list
|
||||
#[inline]
|
||||
fn observes_stderr(&self) -> bool {
|
||||
self.0.observes_stderr() || self.1.observes_stderr()
|
||||
}
|
||||
|
||||
/// Runs `observe_stdout` for all stdout observers in the list
|
||||
#[inline]
|
||||
fn observe_stdout(&mut self, stdout: &[u8]) {
|
||||
self.0.observe_stdout(stdout);
|
||||
self.1.observe_stdout(stdout);
|
||||
}
|
||||
|
||||
/// Runs `observe_stderr` for all stderr observers in the list
|
||||
#[inline]
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||
self.0.observe_stderr(stderr);
|
||||
self.1.observe_stderr(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for [`Observer`]`s` with a hash field
|
||||
|
@ -389,17 +389,6 @@ where
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Do nothing on new `stderr`
|
||||
#[inline]
|
||||
fn observes_stderr(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Do nothing on new `stderr`
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||
self.parse_asan_output(&String::from_utf8_lossy(stderr));
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for AsanBacktraceObserver {
|
||||
|
@ -8,8 +8,6 @@ use std::vec::Vec;
|
||||
use libafl_bolts::Named;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{inputs::UsesInput, observers::Observer};
|
||||
|
||||
/// An observer that captures stdout of a target.
|
||||
/// Only works for supported executors.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
@ -30,19 +28,9 @@ impl StdOutObserver {
|
||||
stdout: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Observer<S> for StdOutObserver
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
#[inline]
|
||||
fn observes_stdout(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// React to new `stdout`
|
||||
fn observe_stdout(&mut self, stdout: &[u8]) {
|
||||
pub fn observe_stdout(&mut self, stdout: &[u8]) {
|
||||
self.stdout = Some(stdout.into());
|
||||
}
|
||||
}
|
||||
@ -73,19 +61,9 @@ impl StdErrObserver {
|
||||
stderr: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Observer<S> for StdErrObserver
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
#[inline]
|
||||
fn observes_stderr(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// React to new `stderr`
|
||||
fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||
pub fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||
self.stderr = Some(stderr.into());
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use std::{
|
||||
use libafl::{
|
||||
executors::{Executor, ExitKind, HasObservers},
|
||||
inputs::HasTargetBytes,
|
||||
observers::{ObserversTuple, UsesObservers},
|
||||
observers::{ObserversTuple, StdErrObserver, StdOutObserver, UsesObservers},
|
||||
state::{HasExecutions, State, UsesState},
|
||||
Error,
|
||||
};
|
||||
@ -20,6 +20,10 @@ use crate::helper::NyxHelper;
|
||||
pub struct NyxExecutor<S, OT> {
|
||||
/// implement nyx function
|
||||
pub helper: NyxHelper,
|
||||
/// stdout
|
||||
stdout: Option<StdOutObserver>,
|
||||
/// stderr
|
||||
// stderr: Option<StdErrObserver>,
|
||||
/// observers
|
||||
observers: OT,
|
||||
/// phantom data to keep generic type <I,S>
|
||||
@ -110,14 +114,18 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
if self.observers.observes_stdout() {
|
||||
match self.stdout.as_mut() {
|
||||
Some(ob) => {
|
||||
let mut stdout = Vec::new();
|
||||
self.helper.nyx_stdout.rewind()?;
|
||||
self.helper
|
||||
.nyx_stdout
|
||||
.read_to_end(&mut stdout)
|
||||
.map_err(|e| Error::illegal_state(format!("Failed to read Nyx stdout: {e}")))?;
|
||||
self.observers.observe_stdout(&stdout);
|
||||
|
||||
ob.observe_stdout(&stdout);
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
Ok(exit_kind)
|
||||
@ -125,14 +133,6 @@ where
|
||||
}
|
||||
|
||||
impl<S, OT> NyxExecutor<S, OT> {
|
||||
pub fn new(helper: NyxHelper, observers: OT) -> Self {
|
||||
Self {
|
||||
helper,
|
||||
observers,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// convert `trace_bits` ptr into real trace map
|
||||
pub fn trace_bits(self) -> &'static mut [u8] {
|
||||
unsafe {
|
||||
@ -141,6 +141,42 @@ impl<S, OT> NyxExecutor<S, OT> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NyxExecutorBuilder {
|
||||
stdout: Option<StdOutObserver>,
|
||||
// stderr: Option<StdErrObserver>,
|
||||
}
|
||||
|
||||
impl NyxExecutorBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
stdout: None,
|
||||
// stderr: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdout(&mut self, stdout: StdOutObserver) -> &mut Self {
|
||||
self.stdout = Some(stdout);
|
||||
self
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn stderr(&mut self, stderr: StdErrObserver) -> &mut Self {
|
||||
self.stderr = Some(stderr);
|
||||
self
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn build<S, OT>(&self, helper: NyxHelper, observers: OT) -> NyxExecutor<S, OT> {
|
||||
NyxExecutor {
|
||||
helper,
|
||||
stdout: self.stdout.clone(),
|
||||
// stderr: self.stderr.clone(),
|
||||
observers,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, OT> HasObservers for NyxExecutor<S, OT>
|
||||
where
|
||||
S: State,
|
||||
|
Loading…
x
Reference in New Issue
Block a user