diff --git a/fuzzers/libfuzzer_libpng/harness.cc b/fuzzers/libfuzzer_libpng/harness.cc index 65faff685d..91c54a168c 100644 --- a/fuzzers/libfuzzer_libpng/harness.cc +++ b/fuzzers/libfuzzer_libpng/harness.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -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; } diff --git a/fuzzers/libfuzzer_libpng/src/fuzzer.rs b/fuzzers/libfuzzer_libpng/src/fuzzer.rs index 4640433c40..23a0810297 100644 --- a/fuzzers/libfuzzer_libpng/src/fuzzer.rs +++ b/fuzzers/libfuzzer_libpng/src/fuzzer.rs @@ -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, 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, 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, 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(()) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index d68ffe09df..8914d144f7 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -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 +where + EX: Executor + HasObservers, + I: Input + HasTargetBytes, + OT: ObserversTuple, +{ + executor: EX, + exec_tmout: Duration, + phantom: PhantomData<(I, OT)>, +} + +impl Named for TimeoutExecutor +where + EX: Executor + HasObservers, + I: Input + HasTargetBytes, + OT: ObserversTuple, +{ + fn name(&self) -> &str{ + self.executor.name() + } +} + +impl HasObservers for TimeoutExecutor +where + EX: Executor + HasObservers, + 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 TimeoutExecutor +where + EX: Executor + HasObservers, + 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 Executor for TimeoutExecutor +where + EX: Executor + HasObservers, + I: Input + HasTargetBytes, + OT: ObserversTuple, +{ + #[inline] + fn pre_exec, 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{ + + 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; diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index c72df9e36f..72a28db4b5 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -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, - exec_tmout: Option, } -#[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(()) } } @@ -240,4 +153,4 @@ mod tests { postcard::from_bytes(&vec).unwrap(); assert_eq!(obv.0.name(), obv2.0.name()); } -} +} \ No newline at end of file