add TimeoutExecutor

This commit is contained in:
toka 2021-03-16 18:13:18 +09:00
parent b259e57524
commit ab3d070f1a
4 changed files with 149 additions and 92 deletions

View File

@ -17,6 +17,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <vector> #include <vector>
@ -83,6 +84,7 @@ static const int kPngHeaderSize = 8;
// Roughly follows the libpng book example: // Roughly follows the libpng book example:
// http://www.libpng.org/pub/png/book/chapter13.html // http://www.libpng.org/pub/png/book/chapter13.html
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
sleep(3);
if (size < kPngHeaderSize) { if (size < kPngHeaderSize) {
return 0; return 0;
} }

View File

@ -11,7 +11,7 @@ use libafl::{
QueueCorpusScheduler, QueueCorpusScheduler,
}, },
events::setup_restarting_mgr, events::setup_restarting_mgr,
executors::{inprocess::InProcessExecutor, Executor, ExitKind}, executors::{inprocess::InProcessExecutor, Executor, ExitKind, inprocess::TimeoutExecutor},
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, HasCorpusScheduler, StdFuzzer}, fuzzer::{Fuzzer, HasCorpusScheduler, StdFuzzer},
inputs::Input, inputs::Input,
@ -150,7 +150,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
&mut state, &mut state,
&mut restarting_mgr, &mut restarting_mgr,
)?; )?;
let mut tmexecutor = TimeoutExecutor::new(executor, 2);
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
unsafe { unsafe {
@ -163,7 +163,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
if state.corpus().count() < 1 { if state.corpus().count() < 1 {
state state
.load_initial_inputs( .load_initial_inputs(
&mut executor, &mut tmexecutor,
&mut restarting_mgr, &mut restarting_mgr,
fuzzer.scheduler(), fuzzer.scheduler(),
&corpus_dirs, &corpus_dirs,
@ -175,7 +175,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
println!("We imported {} inputs from disk.", state.corpus().count()); println!("We imported {} inputs from disk.", state.corpus().count());
} }
fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?; fuzzer.fuzz_loop(&mut state, &mut tmexecutor, &mut restarting_mgr)?;
// Never reached // Never reached
Ok(()) Ok(())

View File

@ -2,6 +2,14 @@
//! It should usually be paired with extra error-handling, such as a restarting event manager, to be effective. //! It should usually be paired with extra error-handling, such as a restarting event manager, to be effective.
use core::marker::PhantomData; 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)] #[cfg(unix)]
use core::{ use core::{
ptr::{self, write_volatile}, ptr::{self, write_volatile},
@ -164,6 +172,140 @@ 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: u64) -> Self{
Self{
executor,
exec_tmout: Duration::from_secs(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)
}
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error>{
let run_result = self.executor.run_target(input);
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(),
);
}
run_result
}
}
#[cfg(unix)] #[cfg(unix)]
mod unix_signal_handler { mod unix_signal_handler {
use alloc::vec::Vec; use alloc::vec::Vec;

View File

@ -8,11 +8,6 @@ use alloc::{
use core::time::Duration; use core::time::Duration;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(unix)]
use std::os::raw::c_int;
#[cfg(unix)]
use std::ptr::null_mut;
use crate::{ use crate::{
bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named, TupleList}, bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named, TupleList},
utils::current_time, utils::current_time,
@ -99,31 +94,8 @@ pub struct TimeObserver {
name: String, name: String,
start_time: Duration, start_time: Duration,
last_runtime: Option<Duration>, last_runtime: Option<Duration>,
exec_tmout: Option<Duration>,
} }
#[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;
impl TimeObserver { impl TimeObserver {
/// Creates a new TimeObserver with the given name. /// Creates a new TimeObserver with the given name.
pub fn new(name: &'static str) -> Self { pub fn new(name: &'static str) -> Self {
@ -131,17 +103,6 @@ impl TimeObserver {
name: name.to_string(), name: name.to_string(),
start_time: Duration::from_secs(0), start_time: Duration::from_secs(0),
last_runtime: None, last_runtime: None,
exec_tmout: None,
}
}
#[cfg(unix)]
pub fn with_timeout(name: &'static str, tmout: u64) -> Self {
Self {
name: name.to_string(),
start_time: Duration::from_secs(0),
last_runtime: None,
exec_tmout: Some(Duration::from_secs(tmout)),
} }
} }
@ -152,30 +113,6 @@ impl TimeObserver {
impl Observer for TimeObserver { impl Observer for TimeObserver {
fn pre_exec(&mut self) -> Result<(), Error> { fn pre_exec(&mut self) -> Result<(), Error> {
#[cfg(unix)]
match self.exec_tmout {
Some(exec_tmout) => unsafe {
let milli_sec = 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(),
);
},
None => (),
}
self.last_runtime = None; self.last_runtime = None;
self.start_time = current_time(); self.start_time = current_time();
Ok(()) Ok(())
@ -183,30 +120,6 @@ impl Observer for TimeObserver {
fn post_exec(&mut self) -> Result<(), Error> { fn post_exec(&mut self) -> Result<(), Error> {
self.last_runtime = Some(current_time() - self.start_time); self.last_runtime = Some(current_time() - self.start_time);
#[cfg(unix)]
match self.exec_tmout {
Some(_) => 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(),
);
},
None => (),
}
Ok(()) Ok(())
} }
} }
@ -240,4 +153,4 @@ mod tests {
postcard::from_bytes(&vec).unwrap(); postcard::from_bytes(&vec).unwrap();
assert_eq!(obv.0.name(), obv2.0.name()); assert_eq!(obv.0.name(), obv2.0.name());
} }
} }