From cad5e339d93072c0e2ad038fa9a06079dde27d37 Mon Sep 17 00:00:00 2001 From: toka Date: Sat, 13 Mar 2021 07:25:28 +0900 Subject: [PATCH 01/11] add timeouts for executors --- libafl/src/executors/inprocess.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index a890be9518..cc9c0460b3 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -71,7 +71,15 @@ where #[inline] fn run_target(&mut self, input: &I) -> Result { let bytes = input.target_bytes(); + + #[cfg(unix)] + unsafe { libc::alarm(1) }; + let ret = (self.harness_fn)(self, bytes.as_slice()); + + #[cfg(unix)] + unsafe { libc::alarm(0) }; + #[cfg(unix)] unsafe { write_volatile( @@ -228,14 +236,19 @@ mod unix_signal_handler { unsafe { let data = &mut GLOBAL_STATE; match signal { - Signal::SigUser2 => (data.timeout_handler)(signal, info, void, data), - _ => (data.crash_handler)(signal, info, void, data), + Signal::SigUser2 | Signal::SigAlarm => { + (data.timeout_handler)(signal, info, void, data) + }, + _ => { + (data.crash_handler)(signal, info, void, data) + }, } } } fn signals(&self) -> Vec { vec![ + Signal::SigAlarm, Signal::SigUser2, Signal::SigAbort, Signal::SigBus, From ae9486814e0cd94d6a204d15354f022eea568090 Mon Sep 17 00:00:00 2001 From: toka Date: Sun, 14 Mar 2021 07:55:14 +0900 Subject: [PATCH 02/11] move timeouts to observer --- libafl/src/executors/inprocess.rs | 4 -- libafl/src/observers/mod.rs | 71 +++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index cc9c0460b3..638eab008e 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -72,13 +72,9 @@ where fn run_target(&mut self, input: &I) -> Result { let bytes = input.target_bytes(); - #[cfg(unix)] - unsafe { libc::alarm(1) }; let ret = (self.harness_fn)(self, bytes.as_slice()); - #[cfg(unix)] - unsafe { libc::alarm(0) }; #[cfg(unix)] unsafe { diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 7404ceeeb9..df1d076127 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -7,6 +7,8 @@ use alloc::{ }; use core::time::Duration; use serde::{Deserialize, Serialize}; +use std::os::raw::c_int; +use std::ptr::null_mut; use crate::{ bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named, TupleList}, @@ -94,8 +96,27 @@ pub struct TimeObserver { name: String, start_time: Duration, last_runtime: Option, + exec_tmout: Option, } +#[repr(C)] +struct Timeval { + pub tv_sec: i64, + pub tv_usec: i64, +} + +#[repr(C)] +struct Itimerval { + pub it_interval: Timeval, + pub it_value: Timeval, +} + +extern "C" { + fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int; +} + +const ITIMER_REAL: c_int = 0; + impl TimeObserver { /// Creates a new TimeObserver with the given name. pub fn new(name: &'static str) -> Self { @@ -103,6 +124,7 @@ impl TimeObserver { name: name.to_string(), start_time: Duration::from_secs(0), last_runtime: None, + exec_tmout: None, } } @@ -113,6 +135,31 @@ 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() as i64; + let it_value = Timeval{ + tv_sec: milli_sec / 1000, + tv_usec: milli_sec % 1000, + }; + 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(()) @@ -120,6 +167,30 @@ 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(()) } } From ff759e2ca7569545d08d08316098a6dadf09fe45 Mon Sep 17 00:00:00 2001 From: toka Date: Mon, 15 Mar 2021 10:20:13 +0900 Subject: [PATCH 03/11] add with_timeout constructor for Observer --- libafl/src/executors/inprocess.rs | 4 ---- libafl/src/observers/mod.rs | 22 +++++++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 638eab008e..d68ffe09df 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -71,11 +71,7 @@ where #[inline] fn run_target(&mut self, input: &I) -> Result { let bytes = input.target_bytes(); - - let ret = (self.harness_fn)(self, bytes.as_slice()); - - #[cfg(unix)] unsafe { write_volatile( diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index df1d076127..8c3fc688da 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -128,6 +128,15 @@ impl TimeObserver { } } + 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)), + } + } + pub fn last_runtime(&self) -> &Option { &self.last_runtime } @@ -135,22 +144,21 @@ 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() as i64; - let it_value = Timeval{ + let it_value = Timeval { tv_sec: milli_sec / 1000, tv_usec: milli_sec % 1000, }; - let it_interval = Timeval{ + let it_interval = Timeval { tv_sec: 0, tv_usec: 0, }; setitimer( ITIMER_REAL, - &mut Itimerval{ + &mut Itimerval { it_interval, it_value, }, @@ -171,17 +179,17 @@ impl Observer for TimeObserver { #[cfg(unix)] match self.exec_tmout { Some(_) => unsafe { - let it_value = Timeval{ + let it_value = Timeval { tv_sec: 0, tv_usec: 0, }; - let it_interval = Timeval{ + let it_interval = Timeval { tv_sec: 0, tv_usec: 0, }; setitimer( ITIMER_REAL, - &mut Itimerval{ + &mut Itimerval { it_interval, it_value, }, From 30716e2483a89e61131583006e2ea856c2b357b6 Mon Sep 17 00:00:00 2001 From: toka Date: Mon, 15 Mar 2021 10:23:33 +0900 Subject: [PATCH 04/11] cast to i64 later in pre_exec --- libafl/src/observers/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 8c3fc688da..99e132fa96 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -147,10 +147,10 @@ impl Observer for TimeObserver { #[cfg(unix)] match self.exec_tmout { Some(exec_tmout) => unsafe { - let milli_sec = exec_tmout.as_millis() as i64; + let milli_sec = exec_tmout.as_millis(); let it_value = Timeval { - tv_sec: milli_sec / 1000, - tv_usec: milli_sec % 1000, + tv_sec: (milli_sec / 1000) as i64, + tv_usec: (milli_sec % 1000) as i64, }; let it_interval = Timeval { tv_sec: 0, From b259e575240365fbcb21adcc738f1c268af78bcf Mon Sep 17 00:00:00 2001 From: toka Date: Mon, 15 Mar 2021 10:37:46 +0900 Subject: [PATCH 05/11] add cfg(unix) guards --- libafl/src/observers/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 99e132fa96..c72df9e36f 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -7,7 +7,10 @@ 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::{ @@ -100,21 +103,25 @@ pub struct TimeObserver { } #[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 { @@ -128,6 +135,7 @@ impl TimeObserver { } } + #[cfg(unix)] pub fn with_timeout(name: &'static str, tmout: u64) -> Self { Self { name: name.to_string(), From ab3d070f1a0150fd99d61de886b99a6683d7c8bd Mon Sep 17 00:00:00 2001 From: toka Date: Tue, 16 Mar 2021 18:13:18 +0900 Subject: [PATCH 06/11] add TimeoutExecutor --- fuzzers/libfuzzer_libpng/harness.cc | 2 + fuzzers/libfuzzer_libpng/src/fuzzer.rs | 8 +- libafl/src/executors/inprocess.rs | 142 +++++++++++++++++++++++++ libafl/src/observers/mod.rs | 89 +--------------- 4 files changed, 149 insertions(+), 92 deletions(-) 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 From b321675aa9f90ab239affe1f458df254b26c8ecc Mon Sep 17 00:00:00 2001 From: toka Date: Tue, 16 Mar 2021 18:48:40 +0900 Subject: [PATCH 07/11] add TimeoutFeedback and send ExitKind::Timeout from the handler --- fuzzers/libfuzzer_libpng/harness.cc | 2 -- fuzzers/libfuzzer_libpng/src/fuzzer.rs | 8 +++--- libafl/src/executors/inprocess.rs | 39 +++++++++++++------------ libafl/src/feedbacks/mod.rs | 40 ++++++++++++++++++++++++++ libafl/src/observers/mod.rs | 2 +- 5 files changed, 65 insertions(+), 26 deletions(-) diff --git a/fuzzers/libfuzzer_libpng/harness.cc b/fuzzers/libfuzzer_libpng/harness.cc index 91c54a168c..65faff685d 100644 --- a/fuzzers/libfuzzer_libpng/harness.cc +++ b/fuzzers/libfuzzer_libpng/harness.cc @@ -17,7 +17,6 @@ #include #include #include -#include #include @@ -84,7 +83,6 @@ 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 23a0810297..4640433c40 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, inprocess::TimeoutExecutor}, + executors::{inprocess::InProcessExecutor, Executor, ExitKind}, 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 tmexecutor, + &mut executor, &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 tmexecutor, &mut restarting_mgr)?; + fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?; // Never reached Ok(()) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 8914d144f7..b7247617e7 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -213,7 +213,7 @@ where I: Input + HasTargetBytes, OT: ObserversTuple, { - fn name(&self) -> &str{ + fn name(&self) -> &str { self.executor.name() } } @@ -241,8 +241,8 @@ where I: Input + HasTargetBytes, OT: ObserversTuple, { - pub fn new(executor: EX, exec_tmout: u64) -> Self{ - Self{ + pub fn new(executor: EX, exec_tmout: u64) -> Self { + Self { executor, exec_tmout: Duration::from_secs(exec_tmout), phantom: PhantomData, @@ -257,20 +257,25 @@ where OT: ObserversTuple, { #[inline] - fn pre_exec, S>(&mut self, _state: &mut S, _event_mgr: &mut EM, _input: &I,) -> Result<(), Error>{ - unsafe{ + 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{ + let it_value = Timeval { tv_sec: (milli_sec / 1000) as i64, tv_usec: (milli_sec % 1000) as i64, }; - let it_interval = Timeval{ + let it_interval = Timeval { tv_sec: 0, tv_usec: 0, }; setitimer( ITIMER_REAL, - &mut Itimerval{ + &mut Itimerval { it_interval, it_value, }, @@ -280,21 +285,20 @@ where self.executor.pre_exec(_state, _event_mgr, _input) } - fn run_target(&mut self, input: &I) -> Result{ - + fn run_target(&mut self, input: &I) -> Result { let run_result = self.executor.run_target(input); - unsafe{ - let it_value = Timeval{ + unsafe { + let it_value = Timeval { tv_sec: 0, tv_usec: 0, }; - let it_interval = Timeval{ + let it_interval = Timeval { tv_sec: 0, tv_usec: 0, }; setitimer( ITIMER_REAL, - &mut Itimerval{ + &mut Itimerval { it_interval, it_value, }, @@ -305,7 +309,6 @@ where } } - #[cfg(unix)] mod unix_signal_handler { use alloc::vec::Vec; @@ -373,9 +376,7 @@ mod unix_signal_handler { Signal::SigUser2 | Signal::SigAlarm => { (data.timeout_handler)(signal, info, void, data) }, - _ => { - (data.crash_handler)(signal, info, void, data) - }, + _ => (data.crash_handler)(signal, info, void, data), } } } @@ -426,7 +427,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 diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 79dddaaf5d..5a156539eb 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -157,6 +157,46 @@ impl Default for CrashFeedback { } } +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct TimeoutFeedback {} + +impl Feedback for TimeoutFeedback +where + I: Input, +{ + fn is_interesting( + &mut self, + _input: &I, + _observers: &OT, + exit_kind: ExitKind, + ) -> Result { + 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 { diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 72a28db4b5..7404ceeeb9 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -153,4 +153,4 @@ mod tests { postcard::from_bytes(&vec).unwrap(); assert_eq!(obv.0.name(), obv2.0.name()); } -} \ No newline at end of file +} From e4a584c02aef0270b8364b865f189f672319d66e Mon Sep 17 00:00:00 2001 From: toka Date: Tue, 16 Mar 2021 19:20:40 +0900 Subject: [PATCH 08/11] pass Duration and move timeout stuff to post_exec --- libafl/src/executors/inprocess.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index b7247617e7..ef273a755d 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -241,10 +241,10 @@ where I: Input + HasTargetBytes, OT: ObserversTuple, { - pub fn new(executor: EX, exec_tmout: u64) -> Self { + pub fn new(executor: EX, exec_tmout: Duration) -> Self { Self { executor, - exec_tmout: Duration::from_secs(exec_tmout), + exec_tmout, phantom: PhantomData, } } @@ -285,8 +285,13 @@ where self.executor.pre_exec(_state, _event_mgr, _input) } - fn run_target(&mut self, input: &I) -> Result { - let run_result = self.executor.run_target(input); + #[inline] + fn post_exec, S>( + &mut self, + _state: &S, + _event_mgr: &mut EM, + _input: &I, + ) -> Result<(), Error> { unsafe { let it_value = Timeval { tv_sec: 0, @@ -305,7 +310,11 @@ where null_mut(), ); } - run_result + self.executor.post_exec(_state, _event_mgr, _input) + } + + fn run_target(&mut self, input: &I) -> Result{ + self.executor.run_target(input) } } From 088b54d614222c0ecf56eb0bbf9922010d30acaf Mon Sep 17 00:00:00 2001 From: toka Date: Tue, 16 Mar 2021 19:26:36 +0900 Subject: [PATCH 09/11] format --- libafl/src/executors/inprocess.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index ef273a755d..339f6c3c6e 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -313,7 +313,7 @@ where self.executor.post_exec(_state, _event_mgr, _input) } - fn run_target(&mut self, input: &I) -> Result{ + fn run_target(&mut self, input: &I) -> Result { self.executor.run_target(input) } } From 46c69aeee83c7d37238003417fd91d2876fa7358 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 17 Mar 2021 15:36:56 +0100 Subject: [PATCH 10/11] add timeouts to libpng_libfuzzer --- fuzzers/libfuzzer_libpng/src/fuzzer.rs | 24 ++++++++++++++---------- libafl/src/executors/inprocess.rs | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/fuzzers/libfuzzer_libpng/src/fuzzer.rs b/fuzzers/libfuzzer_libpng/src/fuzzer.rs index 4640433c40..f5ff1dc90d 100644 --- a/fuzzers/libfuzzer_libpng/src/fuzzer.rs +++ b/fuzzers/libfuzzer_libpng/src/fuzzer.rs @@ -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, 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,16 @@ fn fuzz(corpus_dirs: Vec, 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( - "in-process(edges)", - harness, - tuple_list!(edges_observer, TimeObserver::new("time")), - &mut state, - &mut restarting_mgr, - )?; + let mut executor = TimeoutExecutor::new( + InProcessExecutor::new( + "in-process(edges)", + harness, + tuple_list!(edges_observer, TimeObserver::new("time")), + &mut state, + &mut restarting_mgr, + )?, + Duration::new(0, 3), + ); // The actual target run starts here. // Call LLVMFUzzerInitialize() if present. diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 339f6c3c6e..e29b61f7b6 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -384,7 +384,7 @@ mod unix_signal_handler { match signal { Signal::SigUser2 | Signal::SigAlarm => { (data.timeout_handler)(signal, info, void, data) - }, + } _ => (data.crash_handler)(signal, info, void, data), } } From 774dbc82d18c6f683cb8216f38347db9e50aac16 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 17 Mar 2021 16:46:29 +0100 Subject: [PATCH 11/11] 10 sec timeout --- fuzzers/libfuzzer_libpng/src/fuzzer.rs | 3 ++- libafl/src/executors/inprocess.rs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzzers/libfuzzer_libpng/src/fuzzer.rs b/fuzzers/libfuzzer_libpng/src/fuzzer.rs index f5ff1dc90d..486dbd27ae 100644 --- a/fuzzers/libfuzzer_libpng/src/fuzzer.rs +++ b/fuzzers/libfuzzer_libpng/src/fuzzer.rs @@ -152,7 +152,8 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> &mut state, &mut restarting_mgr, )?, - Duration::new(0, 3), + // 10 seconds timeout + Duration::new(10, 0), ); // The actual target run starts here. diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index e29b61f7b6..beb34f71fb 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -582,7 +582,6 @@ mod tests { let mut in_process_executor = InProcessExecutor:: { harness_fn: test_harness_fn_nop, - // TODO: on_crash_fn: Box::new(|_, _, _, _, _| ()), observers: tuple_list!(), name: "main", phantom: PhantomData,