From 871dfa0a013f31f84e43e125105febca2f137049 Mon Sep 17 00:00:00 2001 From: s1341 Date: Thu, 29 Jun 2023 00:53:51 +0300 Subject: [PATCH] Insert into corpus if feedback is_interesting on crash/timeout (#1327) * Insert into corpus if feedback is_interesting on crash/timeout * Use correct import for HasExecutions * Windows add missing import * QemuExecutor add HasFeedback * Windows asan fix * Add missing call to scheduler.on_add * Add missing HasExecutions for windows frida * QemuExecutor missing HasScheduler * QemuExecutor missing HasCorput --- libafl/src/executors/inprocess.rs | 210 ++++++++++++++++++++--------- libafl_frida/src/executor.rs | 4 +- libafl_qemu/src/executor.rs | 18 ++- libafl_targets/src/windows_asan.rs | 15 ++- 4 files changed, 169 insertions(+), 78 deletions(-) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 88d8f344ee..5cef974bf9 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -44,13 +44,15 @@ use crate::bolts::os::windows_exceptions::setup_exception_handler; #[cfg(all(feature = "std", unix))] use crate::bolts::shmem::ShMemProvider; use crate::{ + bolts::current_time, events::{EventFirer, EventRestarter}, executors::{Executor, ExitKind, HasObservers}, feedbacks::Feedback, - fuzzer::HasObjective, + fuzzer::{HasFeedback, HasObjective, HasScheduler}, inputs::UsesInput, observers::{ObserversTuple, UsesObservers}, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions, UsesState}, + schedulers::Scheduler, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, UsesState}, Error, }; @@ -167,7 +169,7 @@ where H: FnMut(&::Input) -> ExitKind + ?Sized, HB: BorrowMut, OT: ObserversTuple, - S: HasSolutions + HasClientPerfMonitor + HasCorpus, + S: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, { /// Create a new in mem executor. /// Caution: crash and restart in one of them will lead to odd behavior if multiple are used, @@ -175,7 +177,7 @@ where /// * `harness_fn` - the harness, executing the function /// * `observers` - the observers observing the target during execution /// This may return an error on unix, if signal handler setup fails - pub fn new( + pub fn new( harness_fn: HB, observers: OT, _fuzzer: &mut Z, @@ -185,10 +187,13 @@ where where Self: Executor, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - Z: HasObjective, + Z: HasObjective + + HasFeedback + + HasScheduler, { - let handlers = InProcessHandlers::new::()?; + let handlers = InProcessHandlers::new::()?; #[cfg(windows)] // Some initialization necessary for windows. unsafe { @@ -251,7 +256,7 @@ where H: FnMut(&::Input) -> ExitKind + ?Sized, HB: BorrowMut, OT: ObserversTuple, - S: HasSolutions + HasClientPerfMonitor + HasCorpus, + S: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, { /// the timeout handler #[inline] @@ -341,27 +346,30 @@ impl InProcessHandlers { /// Create new [`InProcessHandlers`]. #[cfg(not(all(windows, feature = "std")))] - pub fn new() -> Result + pub fn new() -> Result where E: Executor + HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { #[cfg(unix)] #[cfg_attr(miri, allow(unused_variables))] unsafe { let data = &mut GLOBAL_STATE; #[cfg(feature = "std")] - unix_signal_handler::setup_panic_hook::(); + unix_signal_handler::setup_panic_hook::(); #[cfg(not(miri))] setup_signal_handler(data)?; compiler_fence(Ordering::SeqCst); Ok(Self { - crash_handler: unix_signal_handler::inproc_crash_handler:: + crash_handler: unix_signal_handler::inproc_crash_handler:: as *const c_void, - timeout_handler: unix_signal_handler::inproc_timeout_handler:: + timeout_handler: unix_signal_handler::inproc_timeout_handler:: as *const _, }) } @@ -371,25 +379,28 @@ impl InProcessHandlers { /// Create new [`InProcessHandlers`]. #[cfg(all(windows, feature = "std"))] - pub fn new() -> Result + pub fn new() -> Result where E: Executor + HasObservers + HasInProcessHandlers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { unsafe { let data = &mut GLOBAL_STATE; #[cfg(feature = "std")] - windows_exception_handler::setup_panic_hook::(); + windows_exception_handler::setup_panic_hook::(); setup_exception_handler(data)?; compiler_fence(Ordering::SeqCst); Ok(Self { - crash_handler: windows_exception_handler::inproc_crash_handler:: + crash_handler: windows_exception_handler::inproc_crash_handler:: as *const _, - timeout_handler: windows_exception_handler::inproc_timeout_handler:: + timeout_handler: windows_exception_handler::inproc_timeout_handler:: as *const c_void, }) } @@ -560,7 +571,7 @@ use crate::{ #[inline] #[allow(clippy::too_many_arguments)] /// Save state if it is an objective -pub fn run_observers_and_save_state( +pub fn run_observers_and_save_state( executor: &mut E, state: &mut E::State, input: &::Input, @@ -570,9 +581,12 @@ pub fn run_observers_and_save_state( ) where E: HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { let observers = executor.observers_mut(); @@ -580,6 +594,44 @@ pub fn run_observers_and_save_state( .post_exec_all(state, input, &exitkind) .expect("Observers post_exec_all failed"); + let interesting_for_corpus = fuzzer + .feedback_mut() + .is_interesting(state, event_mgr, input, observers, &exitkind) + .expect("In run_observers_and_save_state feedback failure."); + + if interesting_for_corpus { + let mut new_testcase = Testcase::with_executions(input.clone(), *state.executions()); + new_testcase.add_metadata(exitkind); + new_testcase.set_parent_id_optional(*state.corpus().current()); + fuzzer + .feedback_mut() + .append_metadata(state, observers, &mut new_testcase) + .expect("Failed adding metadata"); + let idx = state + .corpus_mut() + .add(new_testcase) + .expect("In run_observers_and_save_state corpus failure."); + fuzzer + .scheduler_mut() + .on_add(state, idx) + .expect("Could not add to scheduler in run_observers_and_save_state."); + event_mgr + .fire( + state, + Event::NewTestcase { + input: input.clone(), + observers_buf: None, + exit_kind: exitkind, + corpus_size: state.corpus().count(), + client_config: event_mgr.configuration(), + time: current_time(), + executions: *state.executions(), + forward_id: None, + }, + ) + .expect("Could not add the testcase in run_observers_and_save_state"); + } + let interesting = fuzzer .objective_mut() .is_interesting(state, event_mgr, input, observers, &exitkind) @@ -636,9 +688,9 @@ mod unix_signal_handler { Executor, ExitKind, HasObservers, }, feedbacks::Feedback, - fuzzer::HasObjective, + fuzzer::{HasFeedback, HasObjective, HasScheduler}, inputs::UsesInput, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, }; pub(crate) type HandlerFuncPtr = @@ -692,13 +744,16 @@ mod unix_signal_handler { /// invokes the `post_exec` hook on all observer in case of panic #[cfg(feature = "std")] - pub fn setup_panic_hook() + pub fn setup_panic_hook() where E: HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { let old_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| { @@ -712,7 +767,7 @@ mod unix_signal_handler { let fuzzer = data.fuzzer_mut::(); let event_mgr = data.event_mgr_mut::(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -729,7 +784,7 @@ mod unix_signal_handler { } #[cfg(unix)] - pub(crate) unsafe fn inproc_timeout_handler( + pub(crate) unsafe fn inproc_timeout_handler( _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t, @@ -737,9 +792,12 @@ mod unix_signal_handler { ) where E: HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { if !data.timeout_executor_ptr.is_null() && data.timeout_executor_mut::().handle_timeout(data) @@ -760,7 +818,7 @@ mod unix_signal_handler { log::error!("Timeout in fuzz run."); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -778,7 +836,7 @@ mod unix_signal_handler { /// Will be used for signal handling. /// It will store the current State to shmem, then exit. #[allow(clippy::too_many_lines)] - pub(crate) unsafe fn inproc_crash_handler( + pub(crate) unsafe fn inproc_crash_handler( signal: Signal, _info: siginfo_t, _context: &mut ucontext_t, @@ -786,9 +844,12 @@ mod unix_signal_handler { ) where E: Executor + HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { #[cfg(all(target_os = "android", target_arch = "aarch64"))] let _context = &mut *(((_context as *mut _ as *mut libc::c_void as usize) + 128) @@ -819,7 +880,7 @@ mod unix_signal_handler { log::error!("{}", std::str::from_utf8(&bsod).unwrap()); } - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -893,20 +954,23 @@ pub mod windows_asan_handler { Executor, ExitKind, HasObservers, }, feedbacks::Feedback, - fuzzer::HasObjective, + fuzzer::{HasFeedback, HasObjective, HasScheduler}, inputs::UsesInput, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, }; /// # Safety /// ASAN deatch handler - pub unsafe extern "C" fn asan_death_handler() + pub unsafe extern "C" fn asan_death_handler() where E: Executor + HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { let data = &mut GLOBAL_STATE; // Have we set a timer_before? @@ -960,7 +1024,7 @@ pub mod windows_asan_handler { // Make sure we don't crash in the crash handler forever. let input = data.take_current_input::<::Input>(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -1005,9 +1069,9 @@ mod windows_exception_handler { Executor, ExitKind, HasObservers, }, feedbacks::Feedback, - fuzzer::HasObjective, + fuzzer::{HasFeedback, HasObjective, HasScheduler}, inputs::UsesInput, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, }; pub(crate) type HandlerFuncPtr = @@ -1041,13 +1105,16 @@ mod windows_exception_handler { /// invokes the `post_exec` hook on all observer in case of panic #[cfg(feature = "std")] - pub fn setup_panic_hook() + pub fn setup_panic_hook() where E: HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { let old_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| { @@ -1079,7 +1146,7 @@ mod windows_exception_handler { let input = data.take_current_input::<::Input>(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -1097,16 +1164,19 @@ mod windows_exception_handler { } /// Timeout handler for windows - pub unsafe extern "system" fn inproc_timeout_handler( + pub unsafe extern "system" fn inproc_timeout_handler( _p0: *mut u8, global_state: *mut c_void, _p1: *mut u8, ) where E: HasObservers + HasInProcessHandlers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { let data: &mut InProcessExecutorHandlerData = &mut *(global_state as *mut InProcessExecutorHandlerData); @@ -1148,7 +1218,7 @@ mod windows_exception_handler { .unwrap(); data.timeout_input_ptr = ptr::null_mut(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -1173,15 +1243,18 @@ mod windows_exception_handler { } #[allow(clippy::too_many_lines)] - pub(crate) unsafe fn inproc_crash_handler( + pub(crate) unsafe fn inproc_crash_handler( exception_pointers: *mut EXCEPTION_POINTERS, data: &mut InProcessExecutorHandlerData, ) where E: Executor + HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { // Have we set a timer_before? if !(data.tp_timer as *mut windows::Win32::System::Threading::TP_TIMER).is_null() { @@ -1271,7 +1344,7 @@ mod windows_exception_handler { if is_crash { let input = data.take_current_input::<::Input>(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -1789,11 +1862,11 @@ impl<'a, H, OT, S, SP> InProcessForkExecutor<'a, H, OT, S, SP> where H: FnMut(&S::Input) -> ExitKind + ?Sized, OT: ObserversTuple, - S: UsesInput, + S: UsesInput + HasCorpus, SP: ShMemProvider, { /// Creates a new [`InProcessForkExecutor`] - pub fn new( + pub fn new( harness_fn: &'a mut H, observers: OT, _fuzzer: &mut Z, @@ -1803,9 +1876,12 @@ where ) -> Result where EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + Z: HasObjective + + HasFeedback + + HasScheduler, { let handlers = InChildProcessHandlers::new::()?; Ok(Self { @@ -1834,13 +1910,13 @@ where impl<'a, H, OT, S, SP> TimeoutInProcessForkExecutor<'a, H, OT, S, SP> where H: FnMut(&S::Input) -> ExitKind + ?Sized, - S: UsesInput, + S: UsesInput + HasCorpus, OT: ObserversTuple, SP: ShMemProvider, { /// Creates a new [`TimeoutInProcessForkExecutor`] #[cfg(target_os = "linux")] - pub fn new( + pub fn new( harness_fn: &'a mut H, observers: OT, _fuzzer: &mut Z, @@ -1851,9 +1927,12 @@ where ) -> Result where EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + Z: HasObjective + + HasFeedback + + HasScheduler, { let handlers = InChildProcessHandlers::with_timeout::()?; let milli_sec = timeout.as_millis(); @@ -1882,7 +1961,7 @@ where /// Creates a new [`TimeoutInProcessForkExecutor`], non linux #[cfg(not(target_os = "linux"))] - pub fn new( + pub fn new( harness_fn: &'a mut H, observers: OT, _fuzzer: &mut Z, @@ -1893,9 +1972,12 @@ where ) -> Result where EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + Z: HasObjective + + HasFeedback + + HasScheduler, { let handlers = InChildProcessHandlers::with_timeout::()?; let milli_sec = timeout.as_millis(); diff --git a/libafl_frida/src/executor.rs b/libafl_frida/src/executor.rs index 8cff0aca4a..85f92753eb 100644 --- a/libafl_frida/src/executor.rs +++ b/libafl_frida/src/executor.rs @@ -8,7 +8,7 @@ use frida_gum::{ #[cfg(windows)] use libafl::{ executors::inprocess::{HasInProcessHandlers, InProcessHandlers}, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, }; use libafl::{ executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, @@ -200,7 +200,7 @@ impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHandlers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where H: FnMut(&S::Input) -> ExitKind, - S: UsesInput + HasClientPerfMonitor + HasSolutions + HasCorpus, + S: UsesInput + HasClientPerfMonitor + HasSolutions + HasCorpus + HasExecutions, S::Input: HasTargetBytes, OT: ObserversTuple, RT: FridaRuntimeTuple, diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 6be1d53b5b..918f467651 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -10,7 +10,7 @@ use libafl::{ events::{EventFirer, EventRestarter}, executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, feedbacks::Feedback, - fuzzer::HasObjective, + fuzzer::{HasFeedback, HasObjective, HasScheduler}, inputs::UsesInput, observers::{ObserversTuple, UsesObservers}, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState}, @@ -53,7 +53,7 @@ where OT: ObserversTuple, QT: QemuHelperTuple, { - pub fn new( + pub fn new( hooks: &'a mut QemuHooks<'a, QT, S>, harness_fn: &'a mut H, observers: OT, @@ -63,9 +63,12 @@ where ) -> Result where EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + Z: HasObjective + + HasFeedback + + HasScheduler, { Ok(Self { first_exec: true, @@ -201,12 +204,12 @@ where impl<'a, H, OT, QT, S, SP> QemuForkExecutor<'a, H, OT, QT, S, SP> where H: FnMut(&S::Input) -> ExitKind, - S: UsesInput, + S: UsesInput + HasCorpus, OT: ObserversTuple, QT: QemuHelperTuple, SP: ShMemProvider, { - pub fn new( + pub fn new( hooks: &'a mut QemuHooks<'a, QT, S>, harness_fn: &'a mut H, observers: OT, @@ -217,9 +220,12 @@ where ) -> Result where EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + Z: HasObjective + + HasFeedback + + HasScheduler, { assert!(!QT::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded"); diff --git a/libafl_targets/src/windows_asan.rs b/libafl_targets/src/windows_asan.rs index e062980362..3a89a49c67 100644 --- a/libafl_targets/src/windows_asan.rs +++ b/libafl_targets/src/windows_asan.rs @@ -4,8 +4,8 @@ use libafl::{ events::{EventFirer, EventRestarter}, executors::{inprocess::windows_asan_handler::asan_death_handler, Executor, HasObservers}, feedbacks::Feedback, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, - HasObjective, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, + HasFeedback, HasObjective, HasScheduler, }; /// Asan death callback type @@ -27,13 +27,16 @@ extern "C" { /// /// # Safety /// Calls the unsafe `__sanitizer_set_death_callback` symbol, but should be safe to call otherwise. -pub unsafe fn setup_asan_callback(_executor: &E, _event_mgr: &EM, _fuzzer: &Z) +pub unsafe fn setup_asan_callback(_executor: &E, _event_mgr: &EM, _fuzzer: &Z) where E: Executor + HasObservers, EM: EventFirer + EventRestarter, + CF: Feedback, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, - Z: HasObjective, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, + Z: HasObjective + + HasFeedback + + HasScheduler, { - __sanitizer_set_death_callback(asan_death_handler::); + __sanitizer_set_death_callback(asan_death_handler::); }