Merge pull request #31 from AFLplusplus/timeout_executors
add timeouts for executors
This commit is contained in:
commit
5d92871b27
@ -1,6 +1,7 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
|
||||
use core::time::Duration;
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
#[cfg(unix)]
|
||||
@ -11,8 +12,8 @@ use libafl::{
|
||||
QueueCorpusScheduler,
|
||||
},
|
||||
events::setup_restarting_mgr,
|
||||
executors::{inprocess::InProcessExecutor, Executor, ExitKind},
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||
executors::{inprocess::InProcessExecutor, inprocess::TimeoutExecutor, Executor, ExitKind},
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||
fuzzer::{Fuzzer, HasCorpusScheduler, StdFuzzer},
|
||||
inputs::Input,
|
||||
mutators::{scheduled::HavocBytesMutator, token_mutations::Tokens},
|
||||
@ -117,7 +118,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
||||
// on disk so the user can get them after stopping the fuzzer
|
||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
||||
// Feedbacks to recognize an input as solution
|
||||
tuple_list!(CrashFeedback::new()),
|
||||
tuple_list!(CrashFeedback::new(), TimeoutFeedback::new()),
|
||||
)
|
||||
});
|
||||
|
||||
@ -143,13 +144,17 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
||||
let fuzzer = StdFuzzer::new(scheduler, tuple_list!(stage));
|
||||
|
||||
// Create the executor for an in-process function with just one observer for edge coverage
|
||||
let mut executor = InProcessExecutor::new(
|
||||
let mut executor = TimeoutExecutor::new(
|
||||
InProcessExecutor::new(
|
||||
"in-process(edges)",
|
||||
harness,
|
||||
tuple_list!(edges_observer, TimeObserver::new("time")),
|
||||
&mut state,
|
||||
&mut restarting_mgr,
|
||||
)?;
|
||||
)?,
|
||||
// 10 seconds timeout
|
||||
Duration::new(10, 0),
|
||||
);
|
||||
|
||||
// The actual target run starts here.
|
||||
// Call LLVMFUzzerInitialize() if present.
|
||||
|
@ -2,6 +2,14 @@
|
||||
//! It should usually be paired with extra error-handling, such as a restarting event manager, to be effective.
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(unix)]
|
||||
use core::time::Duration;
|
||||
#[cfg(unix)]
|
||||
use std::os::raw::c_int;
|
||||
#[cfg(unix)]
|
||||
use std::ptr::null_mut;
|
||||
|
||||
#[cfg(unix)]
|
||||
use core::{
|
||||
ptr::{self, write_volatile},
|
||||
@ -164,6 +172,152 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(unix)]
|
||||
struct Timeval {
|
||||
pub tv_sec: i64,
|
||||
pub tv_usec: i64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(unix)]
|
||||
struct Itimerval {
|
||||
pub it_interval: Timeval,
|
||||
pub it_value: Timeval,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
extern "C" {
|
||||
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
const ITIMER_REAL: c_int = 0;
|
||||
|
||||
//timeout excutor wrap a InProcessExecutor
|
||||
#[cfg(unix)]
|
||||
pub struct TimeoutExecutor<I, OT, EX>
|
||||
where
|
||||
EX: Executor<I> + HasObservers<OT>,
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
executor: EX,
|
||||
exec_tmout: Duration,
|
||||
phantom: PhantomData<(I, OT)>,
|
||||
}
|
||||
|
||||
impl<I, OT, EX> Named for TimeoutExecutor<I, OT, EX>
|
||||
where
|
||||
EX: Executor<I> + HasObservers<OT>,
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
fn name(&self) -> &str {
|
||||
self.executor.name()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, OT, EX> HasObservers<OT> for TimeoutExecutor<I, OT, EX>
|
||||
where
|
||||
EX: Executor<I> + HasObservers<OT>,
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
#[inline]
|
||||
fn observers(&self) -> &OT {
|
||||
self.executor.observers()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn observers_mut(&mut self) -> &mut OT {
|
||||
self.executor.observers_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, OT, EX> TimeoutExecutor<I, OT, EX>
|
||||
where
|
||||
EX: Executor<I> + HasObservers<OT>,
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
pub fn new(executor: EX, exec_tmout: Duration) -> Self {
|
||||
Self {
|
||||
executor,
|
||||
exec_tmout,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, OT, EX> Executor<I> for TimeoutExecutor<I, OT, EX>
|
||||
where
|
||||
EX: Executor<I> + HasObservers<OT>,
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
#[inline]
|
||||
fn pre_exec<EM: EventManager<I, S>, S>(
|
||||
&mut self,
|
||||
_state: &mut S,
|
||||
_event_mgr: &mut EM,
|
||||
_input: &I,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let milli_sec = self.exec_tmout.as_millis();
|
||||
let it_value = Timeval {
|
||||
tv_sec: (milli_sec / 1000) as i64,
|
||||
tv_usec: (milli_sec % 1000) as i64,
|
||||
};
|
||||
let it_interval = Timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
};
|
||||
setitimer(
|
||||
ITIMER_REAL,
|
||||
&mut Itimerval {
|
||||
it_interval,
|
||||
it_value,
|
||||
},
|
||||
null_mut(),
|
||||
);
|
||||
}
|
||||
self.executor.pre_exec(_state, _event_mgr, _input)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn post_exec<EM: EventManager<I, S>, S>(
|
||||
&mut self,
|
||||
_state: &S,
|
||||
_event_mgr: &mut EM,
|
||||
_input: &I,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let it_value = Timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
};
|
||||
let it_interval = Timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
};
|
||||
setitimer(
|
||||
ITIMER_REAL,
|
||||
&mut Itimerval {
|
||||
it_interval,
|
||||
it_value,
|
||||
},
|
||||
null_mut(),
|
||||
);
|
||||
}
|
||||
self.executor.post_exec(_state, _event_mgr, _input)
|
||||
}
|
||||
|
||||
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
|
||||
self.executor.run_target(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix_signal_handler {
|
||||
use alloc::vec::Vec;
|
||||
@ -228,7 +382,9 @@ mod unix_signal_handler {
|
||||
unsafe {
|
||||
let data = &mut GLOBAL_STATE;
|
||||
match signal {
|
||||
Signal::SigUser2 => (data.timeout_handler)(signal, info, void, data),
|
||||
Signal::SigUser2 | Signal::SigAlarm => {
|
||||
(data.timeout_handler)(signal, info, void, data)
|
||||
}
|
||||
_ => (data.crash_handler)(signal, info, void, data),
|
||||
}
|
||||
}
|
||||
@ -236,6 +392,7 @@ mod unix_signal_handler {
|
||||
|
||||
fn signals(&self) -> Vec<Signal> {
|
||||
vec![
|
||||
Signal::SigAlarm,
|
||||
Signal::SigUser2,
|
||||
Signal::SigAbort,
|
||||
Signal::SigBus,
|
||||
@ -279,7 +436,7 @@ mod unix_signal_handler {
|
||||
|
||||
let obj_fitness = state
|
||||
.objectives_mut()
|
||||
.is_interesting_all(&input, observers, ExitKind::Crash)
|
||||
.is_interesting_all(&input, observers, ExitKind::Timeout)
|
||||
.expect("In timeout handler objectives failure.");
|
||||
if obj_fitness > 0 {
|
||||
state
|
||||
@ -425,7 +582,6 @@ mod tests {
|
||||
|
||||
let mut in_process_executor = InProcessExecutor::<NopInput, ()> {
|
||||
harness_fn: test_harness_fn_nop,
|
||||
// TODO: on_crash_fn: Box::new(|_, _, _, _, _| ()),
|
||||
observers: tuple_list!(),
|
||||
name: "main",
|
||||
phantom: PhantomData,
|
||||
|
@ -157,6 +157,46 @@ impl Default for CrashFeedback {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct TimeoutFeedback {}
|
||||
|
||||
impl<I> Feedback<I> for TimeoutFeedback
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
fn is_interesting<OT: ObserversTuple>(
|
||||
&mut self,
|
||||
_input: &I,
|
||||
_observers: &OT,
|
||||
exit_kind: ExitKind,
|
||||
) -> Result<u32, Error> {
|
||||
if exit_kind == ExitKind::Timeout {
|
||||
Ok(1)
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for TimeoutFeedback {
|
||||
#[inline]
|
||||
fn name(&self) -> &str {
|
||||
"TimeoutFeedback"
|
||||
}
|
||||
}
|
||||
|
||||
impl TimeoutFeedback {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TimeoutFeedback {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Nop feedback that annotates execution time in the new testcase, if any
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct TimeFeedback {
|
||||
|
Loading…
x
Reference in New Issue
Block a user