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},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::tuple_list,
|
tuples::tuple_list,
|
||||||
};
|
};
|
||||||
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};
|
use libafl_nyx::{executor::NyxExecutorBuilder, helper::NyxHelper, settings::NyxSettings};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
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 feedback = MaxMapFeedback::new(&observer);
|
||||||
let mut objective = CrashFeedback::new();
|
let mut objective = CrashFeedback::new();
|
||||||
let scheduler = RandScheduler::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
|
// If not restarting, create a State from scratch
|
||||||
let mut state = state.unwrap_or_else(|| {
|
let mut state = state.unwrap_or_else(|| {
|
||||||
|
@ -14,7 +14,7 @@ use libafl::{
|
|||||||
Fuzzer, StdFuzzer,
|
Fuzzer, StdFuzzer,
|
||||||
};
|
};
|
||||||
use libafl_bolts::{rands::StdRand, tuples::tuple_list};
|
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() {
|
fn main() {
|
||||||
// nyx stuff
|
// nyx stuff
|
||||||
@ -44,7 +44,7 @@ fn main() {
|
|||||||
let monitor = TuiMonitor::new(ui);
|
let monitor = TuiMonitor::new(ui);
|
||||||
|
|
||||||
let mut mgr = SimpleEventManager::new(monitor);
|
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 mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
|
@ -22,17 +22,17 @@ use libafl_bolts::{
|
|||||||
AsSlice,
|
AsSlice,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::HasObservers;
|
|
||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
use crate::executors::{Executor, ExitKind};
|
use crate::executors::{Executor, ExitKind};
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use crate::{inputs::Input, Error};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
executors::HasObservers,
|
||||||
inputs::{HasTargetBytes, UsesInput},
|
inputs::{HasTargetBytes, UsesInput},
|
||||||
observers::{ObserversTuple, UsesObservers},
|
observers::{ObserversTuple, StdErrObserver, StdOutObserver, UsesObservers},
|
||||||
state::{HasExecutions, State, UsesState},
|
state::{HasExecutions, State, UsesState},
|
||||||
std::borrow::ToOwned,
|
std::borrow::ToOwned,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use crate::{inputs::Input, Error};
|
||||||
|
|
||||||
/// How to deliver input to an external program
|
/// How to deliver input to an external program
|
||||||
/// `StdIn`: The target reads from stdin
|
/// `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
|
/// A simple Configurator that takes the most common parameters
|
||||||
/// Writes the input either to stdio or to a file
|
/// Writes the input either to stdio or to a file
|
||||||
/// Use [`CommandExecutor::builder()`] to use this configurator.
|
/// Use [`CommandExecutor::builder()`] to use this configurator.
|
||||||
@ -78,8 +63,8 @@ pub struct StdCommandConfigurator {
|
|||||||
/// If set to true, the child output will remain visible
|
/// If set to true, the child output will remain visible
|
||||||
/// By default, the child output is hidden to increase execution speed
|
/// By default, the child output is hidden to increase execution speed
|
||||||
debug_child: bool,
|
debug_child: bool,
|
||||||
has_stdout_observer: bool,
|
stdout_observer: Option<StdOutObserver>,
|
||||||
has_stderr_observer: bool,
|
stderr_observer: Option<StdErrObserver>,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
/// true: input gets delivered via stdink
|
/// true: input gets delivered via stdink
|
||||||
input_location: InputLocation,
|
input_location: InputLocation,
|
||||||
@ -91,6 +76,22 @@ impl<I> CommandConfigurator<I> for StdCommandConfigurator
|
|||||||
where
|
where
|
||||||
I: HasTargetBytes,
|
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> {
|
fn spawn_child(&mut self, input: &I) -> Result<Child, Error> {
|
||||||
match &mut self.input_location {
|
match &mut self.input_location {
|
||||||
InputLocation::Arg { argnum } => {
|
InputLocation::Arg { argnum } => {
|
||||||
@ -102,10 +103,10 @@ where
|
|||||||
cmd.stderr(Stdio::null());
|
cmd.stderr(Stdio::null());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.has_stdout_observer {
|
if self.stdout_observer.is_some() {
|
||||||
cmd.stdout(Stdio::piped());
|
cmd.stdout(Stdio::piped());
|
||||||
}
|
}
|
||||||
if self.has_stderr_observer {
|
if self.stderr_observer.is_some() {
|
||||||
cmd.stderr(Stdio::piped());
|
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
|
// this only works on unix because of the reliance on checking the process signal for detecting OOM
|
||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
impl<EM, OT, S, T, Z> Executor<EM, Z> for CommandExecutor<OT, S, T>
|
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();
|
let mut stderr = Vec::new();
|
||||||
child.stderr.as_mut().ok_or_else(|| {
|
child.stderr.as_mut().ok_or_else(|| {
|
||||||
Error::illegal_state(
|
Error::illegal_state(
|
||||||
"Observer tries to read stderr, but stderr was not `Stdio::pipe` in CommandExecutor",
|
"Observer tries to read stderr, but stderr was not `Stdio::pipe` in CommandExecutor",
|
||||||
)
|
)
|
||||||
})?.read_to_end(&mut stderr)?;
|
})?.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
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -409,6 +313,8 @@ where
|
|||||||
/// The builder for a default [`CommandExecutor`] that should fit most use-cases.
|
/// The builder for a default [`CommandExecutor`] that should fit most use-cases.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CommandExecutorBuilder {
|
pub struct CommandExecutorBuilder {
|
||||||
|
stdout: Option<StdOutObserver>,
|
||||||
|
stderr: Option<StdErrObserver>,
|
||||||
debug_child: bool,
|
debug_child: bool,
|
||||||
program: Option<OsString>,
|
program: Option<OsString>,
|
||||||
args: Vec<OsString>,
|
args: Vec<OsString>,
|
||||||
@ -429,6 +335,8 @@ impl CommandExecutorBuilder {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn new() -> CommandExecutorBuilder {
|
fn new() -> CommandExecutorBuilder {
|
||||||
CommandExecutorBuilder {
|
CommandExecutorBuilder {
|
||||||
|
stdout: None,
|
||||||
|
stderr: None,
|
||||||
program: None,
|
program: None,
|
||||||
args: vec![],
|
args: vec![],
|
||||||
input_location: InputLocation::StdIn,
|
input_location: InputLocation::StdIn,
|
||||||
@ -468,7 +376,19 @@ impl CommandExecutorBuilder {
|
|||||||
pub fn arg_input_arg(&mut self) -> &mut Self {
|
pub fn arg_input_arg(&mut self) -> &mut Self {
|
||||||
let argnum = self.args.len();
|
let argnum = self.args.len();
|
||||||
self.input(InputLocation::Arg { argnum });
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,18 +413,12 @@ impl CommandExecutorBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an argument to the program's commandline.
|
/// 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 {
|
pub fn arg<O: AsRef<OsStr>>(&mut self, arg: O) -> &mut CommandExecutorBuilder {
|
||||||
self.args.push(arg.as_ref().to_owned());
|
self.args.push(arg.as_ref().to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a range of arguments to the program's commandline.
|
/// 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
|
pub fn args<IT, O>(&mut self, args: IT) -> &mut CommandExecutorBuilder
|
||||||
where
|
where
|
||||||
IT: IntoIterator<Item = O>,
|
IT: IntoIterator<Item = O>,
|
||||||
@ -597,18 +511,19 @@ impl CommandExecutorBuilder {
|
|||||||
command.stdout(Stdio::null());
|
command.stdout(Stdio::null());
|
||||||
command.stderr(Stdio::null());
|
command.stderr(Stdio::null());
|
||||||
}
|
}
|
||||||
if observers.observes_stdout() {
|
|
||||||
|
if self.stdout.is_some() {
|
||||||
command.stdout(Stdio::piped());
|
command.stdout(Stdio::piped());
|
||||||
}
|
}
|
||||||
if observers.observes_stderr() {
|
|
||||||
// we need stderr for `AsanBacktaceObserver`, and others
|
if self.stderr.is_some() {
|
||||||
command.stderr(Stdio::piped());
|
command.stderr(Stdio::piped());
|
||||||
}
|
}
|
||||||
|
|
||||||
let configurator = StdCommandConfigurator {
|
let configurator = StdCommandConfigurator {
|
||||||
debug_child: self.debug_child,
|
debug_child: self.debug_child,
|
||||||
has_stdout_observer: observers.observes_stdout(),
|
stdout_observer: self.stdout.clone(),
|
||||||
has_stderr_observer: observers.observes_stderr(),
|
stderr_observer: self.stderr.clone(),
|
||||||
input_location: self.input_location.clone(),
|
input_location: self.input_location.clone(),
|
||||||
timeout: self.timeout,
|
timeout: self.timeout,
|
||||||
command,
|
command,
|
||||||
@ -666,6 +581,24 @@ impl CommandExecutorBuilder {
|
|||||||
|
|
||||||
#[cfg(all(feature = "std", any(unix, doc)))]
|
#[cfg(all(feature = "std", any(unix, doc)))]
|
||||||
pub trait CommandConfigurator<I>: Sized {
|
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.
|
/// Spawns a new process with the given configuration.
|
||||||
fn spawn_child(&mut self, input: &I) -> Result<Child, Error>;
|
fn spawn_child(&mut self, input: &I) -> Result<Child, Error>;
|
||||||
|
|
||||||
@ -678,8 +611,8 @@ pub trait CommandConfigurator<I>: Sized {
|
|||||||
OT: MatchName,
|
OT: MatchName,
|
||||||
{
|
{
|
||||||
CommandExecutor {
|
CommandExecutor {
|
||||||
observers,
|
|
||||||
configurer: self,
|
configurer: self,
|
||||||
|
observers,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,32 +656,4 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.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
|
self.differential
|
||||||
.post_exec_child_all(state, input, exit_kind)
|
.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>
|
impl<A, B, DOT> MatchName for ProxyObserversTuple<A, B, DOT>
|
||||||
|
@ -186,22 +186,6 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.0.post_exec_child(state, input, exit_kind)
|
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>
|
impl<S, T, OTA, OTB, const ITH: bool, const NTH: bool> DifferentialObserver<OTA, OTB, S>
|
||||||
|
@ -81,29 +81,6 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
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.
|
/// Defines the observer type shared across traits of the type.
|
||||||
@ -139,16 +116,6 @@ where
|
|||||||
input: &S::Input,
|
input: &S::Input,
|
||||||
exit_kind: &ExitKind,
|
exit_kind: &ExitKind,
|
||||||
) -> Result<(), Error>;
|
) -> 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 ()
|
impl<S> ObserversTuple<S> for ()
|
||||||
@ -180,28 +147,6 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
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)
|
impl<Head, Tail, S> ObserversTuple<S> for (Head, Tail)
|
||||||
@ -239,32 +184,6 @@ where
|
|||||||
self.0.post_exec_child(state, input, exit_kind)?;
|
self.0.post_exec_child(state, input, exit_kind)?;
|
||||||
self.1.post_exec_child_all(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
|
/// A trait for [`Observer`]`s` with a hash field
|
||||||
|
@ -389,17 +389,6 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
Ok(())
|
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 {
|
impl Named for AsanBacktraceObserver {
|
||||||
|
@ -8,8 +8,6 @@ use std::vec::Vec;
|
|||||||
use libafl_bolts::Named;
|
use libafl_bolts::Named;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{inputs::UsesInput, observers::Observer};
|
|
||||||
|
|
||||||
/// An observer that captures stdout of a target.
|
/// An observer that captures stdout of a target.
|
||||||
/// Only works for supported executors.
|
/// Only works for supported executors.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
@ -30,19 +28,9 @@ impl StdOutObserver {
|
|||||||
stdout: None,
|
stdout: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> Observer<S> for StdOutObserver
|
|
||||||
where
|
|
||||||
S: UsesInput,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn observes_stdout(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// React to new `stdout`
|
/// React to new `stdout`
|
||||||
fn observe_stdout(&mut self, stdout: &[u8]) {
|
pub fn observe_stdout(&mut self, stdout: &[u8]) {
|
||||||
self.stdout = Some(stdout.into());
|
self.stdout = Some(stdout.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,19 +61,9 @@ impl StdErrObserver {
|
|||||||
stderr: None,
|
stderr: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> Observer<S> for StdErrObserver
|
|
||||||
where
|
|
||||||
S: UsesInput,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn observes_stderr(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// React to new `stderr`
|
/// React to new `stderr`
|
||||||
fn observe_stderr(&mut self, stderr: &[u8]) {
|
pub fn observe_stderr(&mut self, stderr: &[u8]) {
|
||||||
self.stderr = Some(stderr.into());
|
self.stderr = Some(stderr.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
inputs::HasTargetBytes,
|
inputs::HasTargetBytes,
|
||||||
observers::{ObserversTuple, UsesObservers},
|
observers::{ObserversTuple, StdErrObserver, StdOutObserver, UsesObservers},
|
||||||
state::{HasExecutions, State, UsesState},
|
state::{HasExecutions, State, UsesState},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -20,6 +20,10 @@ use crate::helper::NyxHelper;
|
|||||||
pub struct NyxExecutor<S, OT> {
|
pub struct NyxExecutor<S, OT> {
|
||||||
/// implement nyx function
|
/// implement nyx function
|
||||||
pub helper: NyxHelper,
|
pub helper: NyxHelper,
|
||||||
|
/// stdout
|
||||||
|
stdout: Option<StdOutObserver>,
|
||||||
|
/// stderr
|
||||||
|
// stderr: Option<StdErrObserver>,
|
||||||
/// observers
|
/// observers
|
||||||
observers: OT,
|
observers: OT,
|
||||||
/// phantom data to keep generic type <I,S>
|
/// 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();
|
let mut stdout = Vec::new();
|
||||||
self.helper.nyx_stdout.rewind()?;
|
self.helper.nyx_stdout.rewind()?;
|
||||||
self.helper
|
self.helper
|
||||||
.nyx_stdout
|
.nyx_stdout
|
||||||
.read_to_end(&mut stdout)
|
.read_to_end(&mut stdout)
|
||||||
.map_err(|e| Error::illegal_state(format!("Failed to read Nyx stdout: {e}")))?;
|
.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)
|
Ok(exit_kind)
|
||||||
@ -125,14 +133,6 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<S, OT> NyxExecutor<S, OT> {
|
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
|
/// convert `trace_bits` ptr into real trace map
|
||||||
pub fn trace_bits(self) -> &'static mut [u8] {
|
pub fn trace_bits(self) -> &'static mut [u8] {
|
||||||
unsafe {
|
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>
|
impl<S, OT> HasObservers for NyxExecutor<S, OT>
|
||||||
where
|
where
|
||||||
S: State,
|
S: State,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user