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

View File

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

View File

@ -8,11 +8,6 @@ use alloc::{
use core::time::Duration;
use serde::{Deserialize, Serialize};
#[cfg(unix)]
use std::os::raw::c_int;
#[cfg(unix)]
use std::ptr::null_mut;
use crate::{
bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named, TupleList},
utils::current_time,
@ -99,31 +94,8 @@ pub struct TimeObserver {
name: String,
start_time: 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 {
/// Creates a new TimeObserver with the given name.
pub fn new(name: &'static str) -> Self {
@ -131,17 +103,6 @@ impl TimeObserver {
name: name.to_string(),
start_time: Duration::from_secs(0),
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 {
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.start_time = current_time();
Ok(())
@ -183,30 +120,6 @@ impl Observer for TimeObserver {
fn post_exec(&mut self) -> Result<(), Error> {
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(())
}
}