From f4cb9a827d83721e16e53610cdd5b7336ae7a013 Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Tue, 11 Mar 2025 12:53:27 +0100 Subject: [PATCH] Partially Revert #3029 and #3053 (#3063) * revert begins * fixer * e? * fixer * how you didn't report that at the same time though??? * i'm tired of you --- libafl/src/executors/hooks/inprocess.rs | 33 ++- libafl/src/executors/hooks/unix.rs | 22 +- libafl/src/executors/hooks/windows.rs | 34 ++- libafl/src/executors/inprocess/inner.rs | 18 +- libafl/src/executors/inprocess/mod.rs | 86 ++------ libafl/src/executors/inprocess/stateful.rs | 28 ++- libafl/src/fuzzer/mod.rs | 236 ++++++++++----------- libafl/src/state/mod.rs | 18 +- libafl_qemu/src/executor.rs | 29 +-- libafl_targets/src/windows_asan.rs | 9 +- 10 files changed, 208 insertions(+), 305 deletions(-) diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index d453898af6..0880538efe 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -24,7 +24,7 @@ use windows::Win32::System::Threading::{CRITICAL_SECTION, PTP_TIMER}; #[cfg(feature = "std")] use crate::executors::hooks::timer::TimerStruct; use crate::{ - Error, HasFeedback, HasObjective, HasScheduler, + Error, HasObjective, events::{EventFirer, EventRestarter}, executors::{Executor, HasObservers, hooks::ExecutorHook, inprocess::HasInProcessHooks}, feedbacks::Feedback, @@ -232,15 +232,14 @@ impl InProcessHooks { /// Create new [`InProcessHooks`]. #[cfg(unix)] #[allow(unused_variables)] // for `exec_tmout` without `std` - pub fn new(exec_tmout: Duration) -> Result + pub fn new(exec_tmout: Duration) -> Result where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { // # Safety @@ -250,7 +249,7 @@ impl InProcessHooks { #[cfg(all(not(miri), unix, feature = "std"))] let data = unsafe { &raw mut GLOBAL_STATE }; #[cfg(feature = "std")] - unix_signal_handler::setup_panic_hook::(); + unix_signal_handler::setup_panic_hook::(); // # Safety // Setting up the signal handlers with a pointer to the `GLOBAL_STATE` which should not be NULL at this point. // We are the sole users of `GLOBAL_STATE` right now, and only dereference it in case of Segfault/Panic. @@ -263,10 +262,10 @@ impl InProcessHooks { compiler_fence(Ordering::SeqCst); Ok(Self { #[cfg(feature = "std")] - crash_handler: unix_signal_handler::inproc_crash_handler:: + crash_handler: unix_signal_handler::inproc_crash_handler:: as *const c_void, #[cfg(feature = "std")] - timeout_handler: unix_signal_handler::inproc_timeout_handler:: + timeout_handler: unix_signal_handler::inproc_timeout_handler:: as *const _, #[cfg(feature = "std")] timer: TimerStruct::new(exec_tmout), @@ -277,16 +276,15 @@ impl InProcessHooks { /// Create new [`InProcessHooks`]. #[cfg(windows)] #[allow(unused_variables)] // for `exec_tmout` without `std` - pub fn new(exec_tmout: Duration) -> Result + pub fn new(exec_tmout: Duration) -> Result where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, I: Input + Clone, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { let ret; #[cfg(feature = "std")] @@ -295,7 +293,6 @@ impl InProcessHooks { crate::executors::hooks::windows::windows_exception_handler::setup_panic_hook::< E, EM, - F, I, OF, S, @@ -307,7 +304,6 @@ impl InProcessHooks { crate::executors::hooks::windows::windows_exception_handler::inproc_crash_handler::< E, EM, - F, I, OF, S, @@ -317,7 +313,6 @@ impl InProcessHooks { crate::executors::hooks::windows::windows_exception_handler::inproc_timeout_handler::< E, EM, - F, I, OF, S, @@ -344,14 +339,13 @@ impl InProcessHooks { /// Create a new [`InProcessHooks`] #[cfg(all(not(unix), not(windows)))] #[expect(unused_variables)] - pub fn new(exec_tmout: Duration) -> Result + pub fn new(exec_tmout: Duration) -> Result where E: Executor + HasObservers + HasInProcessHooks, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { #[cfg_attr(miri, allow(unused_variables))] let ret = Self { @@ -478,7 +472,7 @@ impl InProcessExecutorHandlerData { /// /// Should only be called to signal a crash in the target #[cfg(all(unix, feature = "std"))] - pub unsafe fn maybe_report_crash( + pub unsafe fn maybe_report_crash( &mut self, bsod_info: Option, ) -> bool @@ -486,10 +480,9 @@ impl InProcessExecutorHandlerData { E: Executor + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { unsafe { @@ -517,7 +510,7 @@ impl InProcessExecutorHandlerData { } } - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, diff --git a/libafl/src/executors/hooks/unix.rs b/libafl/src/executors/hooks/unix.rs index 9cd8d7752a..41f01b94d1 100644 --- a/libafl/src/executors/hooks/unix.rs +++ b/libafl/src/executors/hooks/unix.rs @@ -12,7 +12,6 @@ pub mod unix_signal_handler { use libc::siginfo_t; use crate::{ - HasFeedback, HasScheduler, events::{EventFirer, EventRestarter}, executors::{ Executor, ExitKind, HasObservers, common_signals, @@ -87,15 +86,14 @@ pub mod unix_signal_handler { } /// invokes the `post_exec` hook on all observer in case of panic - pub fn setup_panic_hook() + pub fn setup_panic_hook() where E: Executor + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { let old_hook = panic::take_hook(); @@ -119,7 +117,7 @@ pub 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, @@ -142,7 +140,7 @@ pub mod unix_signal_handler { /// Well, signal handling is not safe #[cfg(unix)] #[allow(clippy::needless_pass_by_value)] // nightly no longer requires this - pub unsafe fn inproc_timeout_handler( + pub unsafe fn inproc_timeout_handler( _signal: Signal, _info: &mut siginfo_t, _context: Option<&mut ucontext_t>, @@ -151,10 +149,9 @@ pub mod unix_signal_handler { E: HasInProcessHooks + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { unsafe { @@ -181,7 +178,7 @@ pub mod unix_signal_handler { log::error!("Timeout in fuzz run."); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -201,7 +198,7 @@ pub mod unix_signal_handler { /// # Safety /// Well, signal handling is not safe #[allow(clippy::needless_pass_by_value)] // nightly no longer requires this - pub unsafe fn inproc_crash_handler( + pub unsafe fn inproc_crash_handler( signal: Signal, _info: &mut siginfo_t, _context: Option<&mut ucontext_t>, @@ -210,10 +207,9 @@ pub mod unix_signal_handler { E: Executor + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { unsafe { @@ -255,7 +251,7 @@ pub mod unix_signal_handler { } } - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, diff --git a/libafl/src/executors/hooks/windows.rs b/libafl/src/executors/hooks/windows.rs index e1219c4763..29faa8d441 100644 --- a/libafl/src/executors/hooks/windows.rs +++ b/libafl/src/executors/hooks/windows.rs @@ -9,14 +9,13 @@ pub mod windows_asan_handler { }; use crate::{ - HasFeedback, events::{EventFirer, EventRestarter}, executors::{ Executor, ExitKind, HasObservers, hooks::inprocess::GLOBAL_STATE, inprocess::run_observers_and_save_state, }, feedbacks::Feedback, - fuzzer::{HasObjective, HasScheduler}, + fuzzer::HasObjective, inputs::Input, observers::ObserversTuple, state::{HasCurrentTestcase, HasExecutions, HasSolutions}, @@ -24,16 +23,15 @@ pub mod windows_asan_handler { /// # Safety /// ASAN deatch handler - pub unsafe extern "C" fn asan_death_handler() + pub unsafe extern "C" fn asan_death_handler() where E: Executor + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, I: Input + Clone, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { unsafe { let data = &raw mut GLOBAL_STATE; @@ -96,7 +94,7 @@ pub mod windows_asan_handler { // Make sure we don't crash in the crash handler forever. let input = (*data).take_current_input::(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -139,7 +137,6 @@ pub mod windows_exception_handler { }; use crate::{ - HasFeedback, events::{EventFirer, EventRestarter}, executors::{ Executor, ExitKind, HasObservers, @@ -147,7 +144,7 @@ pub mod windows_exception_handler { inprocess::{HasInProcessHooks, run_observers_and_save_state}, }, feedbacks::Feedback, - fuzzer::{HasObjective, HasScheduler}, + fuzzer::HasObjective, inputs::Input, observers::ObserversTuple, state::{HasCurrentTestcase, HasExecutions, HasSolutions}, @@ -200,16 +197,15 @@ pub mod windows_exception_handler { /// # Safety /// Well, exception handling is not safe #[cfg(feature = "std")] - pub fn setup_panic_hook() + pub fn setup_panic_hook() where E: Executor + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, I: Input + Clone, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { let old_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| unsafe { @@ -246,7 +242,7 @@ pub mod windows_exception_handler { let input = (*data).take_current_input::(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -266,7 +262,7 @@ pub mod windows_exception_handler { /// /// # Safety /// Well, exception handling is not safe - 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, @@ -275,10 +271,9 @@ pub mod windows_exception_handler { E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, I: Input + Clone, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { let data: &mut InProcessExecutorHandlerData = unsafe { &mut *(global_state as *mut InProcessExecutorHandlerData) }; @@ -318,7 +313,7 @@ pub mod windows_exception_handler { let input = unsafe { (data.current_input_ptr as *const I).as_ref().unwrap() }; data.current_input_ptr = ptr::null_mut(); - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, @@ -346,7 +341,7 @@ pub mod windows_exception_handler { /// /// # Safety /// Well, exception handling is not safe - pub unsafe fn inproc_crash_handler( + pub unsafe fn inproc_crash_handler( exception_pointers: *mut EXCEPTION_POINTERS, data: &mut InProcessExecutorHandlerData, ) where @@ -354,10 +349,9 @@ pub mod windows_exception_handler { E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, I: Input + Clone, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { // Have we set a timer_before? if data.ptp_timer.is_some() { @@ -462,7 +456,7 @@ pub mod windows_exception_handler { log::warn!("Running observers and exiting!"); // // I want to disable the hooks before doing anything, especially before taking a stack dump let input = unsafe { data.take_current_input::() }; - run_observers_and_save_state::( + run_observers_and_save_state::( executor, state, input, diff --git a/libafl/src/executors/inprocess/inner.rs b/libafl/src/executors/inprocess/inner.rs index 4ebb904ed0..12f961fe6f 100644 --- a/libafl/src/executors/inprocess/inner.rs +++ b/libafl/src/executors/inprocess/inner.rs @@ -14,7 +14,7 @@ use windows::Win32::System::Threading::SetThreadStackGuarantee; #[cfg(all(windows, feature = "std"))] use crate::executors::hooks::inprocess::HasTimeout; use crate::{ - Error, HasFeedback, + Error, events::{EventFirer, EventRestarter}, executors::{ Executor, HasObservers, @@ -25,7 +25,7 @@ use crate::{ inprocess::HasInProcessHooks, }, feedbacks::Feedback, - fuzzer::{HasObjective, HasScheduler}, + fuzzer::HasObjective, inputs::Input, observers::ObserversTuple, state::{HasCurrentTestcase, HasExecutions, HasSolutions}, @@ -130,7 +130,7 @@ where S: HasExecutions + HasSolutions, { /// Create a new in mem executor with the default timeout (5 sec) - pub fn generic( + pub fn generic( user_hooks: HT, observers: OT, fuzzer: &mut Z, @@ -142,12 +142,11 @@ where E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, I: Input + Clone, - F: Feedback, OF: Feedback, S: HasCurrentTestcase + HasSolutions, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { - Self::with_timeout_generic::( + Self::with_timeout_generic::( user_hooks, observers, fuzzer, @@ -165,7 +164,7 @@ where /// * `observers` - the observers observing the target during execution /// /// This may return an error on unix, if signal handler setup fails - pub fn with_timeout_generic( + pub fn with_timeout_generic( user_hooks: HT, observers: OT, _fuzzer: &mut Z, @@ -177,13 +176,12 @@ where E: Executor + HasObservers + HasInProcessHooks, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasCurrentTestcase + HasSolutions, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { - let default = InProcessHooks::new::(timeout)?; + let default = InProcessHooks::new::(timeout)?; let mut hooks = tuple_list!(default).merge(user_hooks); hooks.init_all(state); diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index b7be9b095e..a34dade086 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -15,7 +15,7 @@ use core::{ use libafl_bolts::tuples::{RefIndexable, tuple_list}; use crate::{ - Error, HasFeedback, HasScheduler, + Error, corpus::{Corpus, Testcase}, events::{Event, EventFirer, EventRestarter}, executors::{ @@ -27,7 +27,6 @@ use crate::{ fuzzer::HasObjective, inputs::Input, observers::ObserversTuple, - schedulers::Scheduler, state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions}, }; @@ -133,7 +132,7 @@ where I: Input, { /// Create a new in mem executor with the default timeout (5 sec) - pub fn new( + pub fn new( harness_fn: &'a mut H, observers: OT, fuzzer: &mut Z, @@ -142,11 +141,10 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { - Self::with_timeout_generic::( + Self::with_timeout_generic::( tuple_list!(), harness_fn, observers, @@ -165,7 +163,7 @@ where /// * `observers` - the observers observing the target during execution /// /// This may return an error on unix, if signal handler setup fails - pub fn with_timeout( + pub fn with_timeout( harness_fn: &'a mut H, observers: OT, fuzzer: &mut Z, @@ -175,11 +173,10 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { - let inner = GenericInProcessExecutorInner::with_timeout_generic::( + let inner = GenericInProcessExecutorInner::with_timeout_generic::( tuple_list!(), observers, fuzzer, @@ -206,7 +203,7 @@ where I: Input, { /// Create a new in mem executor with the default timeout (5 sec) - pub fn generic( + pub fn generic( user_hooks: HT, harness_fn: HB, observers: OT, @@ -216,11 +213,10 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { - Self::with_timeout_generic::( + Self::with_timeout_generic::( user_hooks, harness_fn, observers, @@ -239,7 +235,7 @@ where /// * `observers` - the observers observing the target during execution /// /// This may return an error on unix, if signal handler setup fails - pub fn with_timeout_generic( + pub fn with_timeout_generic( user_hooks: HT, harness_fn: HB, observers: OT, @@ -250,11 +246,10 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { - let inner = GenericInProcessExecutorInner::with_timeout_generic::( + let inner = GenericInProcessExecutorInner::with_timeout_generic::( user_hooks, observers, fuzzer, state, event_mgr, timeout, )?; @@ -317,7 +312,7 @@ impl HasInProcessHooks #[inline] /// 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 S, input: &I, @@ -329,9 +324,8 @@ pub fn run_observers_and_save_state( E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, OF: Feedback, - F: Feedback, S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { log::info!("in crash handler!"); @@ -341,52 +335,6 @@ pub fn run_observers_and_save_state( .post_exec_all(state, input, &exitkind) .expect("Observers post_exec_all failed"); - let is_corpus = fuzzer - .feedback_mut() - .is_interesting(state, event_mgr, input, &*observers, &exitkind) - .expect("In run_observers_and_save_state feedback failure"); - - if is_corpus { - // Add the input to the main corpus - let mut testcase = Testcase::from(input.clone()); - #[cfg(feature = "track_hit_feedbacks")] - fuzzer - .feedback_mut() - .append_hit_feedbacks(testcase.hit_feedbacks_mut()) - .expect("Failed to append hit feedbacks"); - testcase.set_parent_id_optional(*state.corpus().current()); - fuzzer - .feedback_mut() - .append_metadata(state, event_mgr, &observers, &mut testcase) - .expect("Failed to append metadata"); - - let id = state - .corpus_mut() - .add(testcase) - .expect("In run_observers_and_save_state failed to add to corpus."); - fuzzer - .scheduler_mut() - .on_add(state, id) - .expect("In run_observers_and_save_state failed to add to scheduler."); - - event_mgr - .fire( - state, - Event::NewTestcase { - input: input.clone(), - observers_buf: None, // idk it's not effective anyway just leave it like this - exit_kind: ExitKind::Ok, - corpus_size: state.corpus().count(), - client_config: event_mgr.configuration(), - time: libafl_bolts::current_time(), - forward_id: None, - #[cfg(all(unix, feature = "std", feature = "multi_machine"))] - node_id: None, - }, - ) - .expect("Could not send off events in run_observers_and_save_state"); - } - let is_solution = fuzzer .objective_mut() .is_interesting(state, event_mgr, input, &*observers, &exitkind) @@ -438,7 +386,7 @@ mod tests { feedbacks::CrashFeedback, inputs::NopInput, schedulers::RandScheduler, - state::StdState, + state::{NopState, StdState}, }; #[test] @@ -449,7 +397,7 @@ mod tests { let solutions = InMemoryCorpus::new(); let mut objective = CrashFeedback::new(); let mut feedback = tuple_list!(); - let sche = RandScheduler::new(); + let sche: RandScheduler> = RandScheduler::new(); let mut mgr = NopEventManager::new(); let mut state = StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap(); diff --git a/libafl/src/executors/inprocess/stateful.rs b/libafl/src/executors/inprocess/stateful.rs index 1c08b07d5e..f84cad9026 100644 --- a/libafl/src/executors/inprocess/stateful.rs +++ b/libafl/src/executors/inprocess/stateful.rs @@ -11,7 +11,7 @@ use core::{ use libafl_bolts::tuples::{RefIndexable, tuple_list}; use crate::{ - Error, HasFeedback, + Error, events::{EventFirer, EventRestarter}, executors::{ Executor, ExitKind, HasObservers, @@ -19,7 +19,7 @@ use crate::{ inprocess::{GenericInProcessExecutorInner, HasInProcessHooks}, }, feedbacks::Feedback, - fuzzer::{HasObjective, HasScheduler}, + fuzzer::HasObjective, inputs::Input, observers::ObserversTuple, state::{HasCurrentTestcase, HasExecutions, HasSolutions}, @@ -131,7 +131,7 @@ where I: Clone + Input, { /// Create a new in mem executor with the default timeout (5 sec) - pub fn new( + pub fn new( harness_fn: &'a mut H, exposed_executor_state: ES, observers: OT, @@ -141,9 +141,8 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { Self::with_timeout_generic( tuple_list!(), @@ -165,7 +164,7 @@ where /// * `observers` - the observers observing the target during execution /// /// This may return an error on unix, if signal handler setup fails - pub fn with_timeout( + pub fn with_timeout( harness_fn: &'a mut H, exposed_executor_state: ES, observers: OT, @@ -176,11 +175,10 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { - let inner = GenericInProcessExecutorInner::with_timeout_generic::( + let inner = GenericInProcessExecutorInner::with_timeout_generic::( tuple_list!(), observers, fuzzer, @@ -223,7 +221,7 @@ where S: HasExecutions + HasSolutions + HasCurrentTestcase, { /// Create a new in mem executor with the default timeout (5 sec) - pub fn generic( + pub fn generic( user_hooks: HT, harness_fn: HB, exposed_executor_state: ES, @@ -234,9 +232,8 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { Self::with_timeout_generic( user_hooks, @@ -259,7 +256,7 @@ where /// /// This may return an error on unix, if signal handler setup fails #[expect(clippy::too_many_arguments)] - pub fn with_timeout_generic( + pub fn with_timeout_generic( user_hooks: HT, harness_fn: HB, exposed_executor_state: ES, @@ -271,11 +268,10 @@ where ) -> Result where EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { - let inner = GenericInProcessExecutorInner::with_timeout_generic::( + let inner = GenericInProcessExecutorInner::with_timeout_generic::( user_hooks, observers, fuzzer, state, event_mgr, timeout, )?; diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 3c642f35eb..7196917700 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -191,7 +191,7 @@ pub trait Evaluator { executor: &mut E, manager: &mut EM, input: I, - ) -> Result<(CorpusId, ExecuteInputResult), Error>; + ) -> Result; /// Adds the input to the corpus as a disabled input. /// Used during initial corpus loading. @@ -248,44 +248,15 @@ pub trait Fuzzer { ) -> Result; } -/// The corpus this input should be added to -#[derive(Debug, PartialEq, Eq, Default)] -pub struct ExecuteInputResult { - is_corpus: bool, - is_solution: bool, -} - -impl ExecuteInputResult { - /// Constructor - #[must_use] - pub fn new(is_corpus: bool, is_solution: bool) -> Self { - Self { - is_corpus, - is_solution, - } - } - - /// if this is corpus worthy - #[must_use] - pub fn is_corpus(&self) -> bool { - self.is_corpus - } - - /// if this is solution worthy - #[must_use] - pub fn is_solution(&self) -> bool { - self.is_solution - } - - /// tell that this is corpus - pub fn set_is_corpus(&mut self, v: bool) { - self.is_corpus = v; - } - - /// tell that this is solution - pub fn set_is_solution(&mut self, v: bool) { - self.is_solution = v; - } +/// The result of harness execution +#[derive(Debug, PartialEq, Eq)] +pub enum ExecuteInputResult { + /// No special input + None, + /// This input should be stored in the corpus + Corpus, + /// This input leads to a solution + Solution, } /// Your default fuzzer instance, for everyday use. @@ -368,7 +339,7 @@ where observers: &OT, exit_kind: &ExitKind, ) -> Result { - let mut res = ExecuteInputResult::default(); + let mut res = ExecuteInputResult::None; #[cfg(not(feature = "introspection"))] let is_solution = self @@ -381,20 +352,20 @@ where .is_interesting_introspection(state, manager, input, observers, exit_kind)?; if is_solution { - res.set_is_solution(true); - } + res = ExecuteInputResult::Solution; + } else { + #[cfg(not(feature = "introspection"))] + let corpus_worthy = self + .feedback_mut() + .is_interesting(state, manager, input, observers, exit_kind)?; + #[cfg(feature = "introspection")] + let corpus_worthy = self + .feedback_mut() + .is_interesting_introspection(state, manager, input, observers, exit_kind)?; - #[cfg(not(feature = "introspection"))] - let corpus_worthy = self - .feedback_mut() - .is_interesting(state, manager, input, observers, exit_kind)?; - #[cfg(feature = "introspection")] - let corpus_worthy = self - .feedback_mut() - .is_interesting_introspection(state, manager, input, observers, exit_kind)?; - - if corpus_worthy { - res.set_is_corpus(true); + if corpus_worthy { + res = ExecuteInputResult::Corpus; + } } Ok(res) @@ -410,36 +381,39 @@ where exec_res: &ExecuteInputResult, observers: &OT, ) -> Result, Error> { - let corpus = if exec_res.is_corpus() { - // Add the input to the main corpus - let mut testcase = Testcase::from(input.clone()); - #[cfg(feature = "track_hit_feedbacks")] - self.feedback_mut() - .append_hit_feedbacks(testcase.hit_feedbacks_mut())?; - self.feedback_mut() - .append_metadata(state, manager, observers, &mut testcase)?; - let id = state.corpus_mut().add(testcase)?; - self.scheduler_mut().on_add(state, id)?; - Ok(Some(id)) - } else { - Ok(None) - }; + match exec_res { + ExecuteInputResult::None => Ok(None), + ExecuteInputResult::Corpus => { + // Not a solution + // Add the input to the main corpus + let mut testcase = Testcase::from(input.clone()); + #[cfg(feature = "track_hit_feedbacks")] + self.feedback_mut() + .append_hit_feedbacks(testcase.hit_feedbacks_mut())?; + self.feedback_mut() + .append_metadata(state, manager, observers, &mut testcase)?; + let id = state.corpus_mut().add(testcase)?; + self.scheduler_mut().on_add(state, id)?; - if exec_res.is_solution() { - // The input is a solution, add it to the respective corpus - let mut testcase = Testcase::from(input.clone()); - testcase.set_parent_id_optional(*state.corpus().current()); - if let Ok(mut tc) = state.current_testcase_mut() { - tc.found_objective(); + Ok(Some(id)) + } + ExecuteInputResult::Solution => { + // The input is a solution, add it to the respective corpus + let mut testcase = Testcase::from(input.clone()); + testcase.set_parent_id_optional(*state.corpus().current()); + if let Ok(mut tc) = state.current_testcase_mut() { + tc.found_objective(); + } + #[cfg(feature = "track_hit_feedbacks")] + self.objective_mut() + .append_hit_feedbacks(testcase.hit_objectives_mut())?; + self.objective_mut() + .append_metadata(state, manager, observers, &mut testcase)?; + state.solutions_mut().add(testcase)?; + + Ok(None) } - #[cfg(feature = "track_hit_feedbacks")] - self.objective_mut() - .append_hit_feedbacks(testcase.hit_objectives_mut())?; - self.objective_mut() - .append_metadata(state, manager, observers, &mut testcase)?; - state.solutions_mut().add(testcase)?; } - corpus } fn serialize_and_dispatch( @@ -452,14 +426,20 @@ where exit_kind: &ExitKind, ) -> Result<(), Error> { // Now send off the event - let observers_buf = if exec_res.is_corpus() - && manager.should_send() - && manager.configuration() != EventConfig::AlwaysUnique - { - // TODO set None for fast targets - Some(postcard::to_allocvec(observers)?) - } else { - None + let observers_buf = match exec_res { + ExecuteInputResult::Corpus => { + if manager.should_send() { + // TODO set None for fast targets + if manager.configuration() == EventConfig::AlwaysUnique { + None + } else { + Some(postcard::to_allocvec(observers)?) + } + } else { + None + } + } + _ => None, }; self.dispatch_event(state, manager, input, exec_res, observers_buf, exit_kind)?; @@ -476,35 +456,40 @@ where exit_kind: &ExitKind, ) -> Result<(), Error> { // Now send off the event - if manager.should_send() { - if exec_res.is_corpus() { - manager.fire( - state, - Event::NewTestcase { - input: input.clone(), - observers_buf, - exit_kind: *exit_kind, - corpus_size: state.corpus().count(), - client_config: manager.configuration(), - time: current_time(), - forward_id: None, - #[cfg(all(unix, feature = "std", feature = "multi_machine"))] - node_id: None, - }, - )?; - } - if exec_res.is_solution() { - manager.fire( - state, - Event::Objective { - input: self.share_objectives.then_some(input.clone()), - objective_size: state.solutions().count(), - time: current_time(), - }, - )?; - } - } + match exec_res { + ExecuteInputResult::Corpus => { + if manager.should_send() { + manager.fire( + state, + Event::NewTestcase { + input: input.clone(), + observers_buf, + exit_kind: *exit_kind, + corpus_size: state.corpus().count(), + client_config: manager.configuration(), + time: current_time(), + forward_id: None, + #[cfg(all(unix, feature = "std", feature = "multi_machine"))] + node_id: None, + }, + )?; + } + } + ExecuteInputResult::Solution => { + if manager.should_send() { + manager.fire( + state, + Event::Objective { + input: self.share_objectives.then_some(input.clone()), + objective_size: state.solutions().count(), + time: current_time(), + }, + )?; + } + } + ExecuteInputResult::None => (), + } Ok(()) } @@ -522,7 +507,7 @@ where if send_events { self.serialize_and_dispatch(state, manager, input, &exec_res, observers, exit_kind)?; } - if exec_res.is_corpus() || exec_res.is_solution() { + if exec_res != ExecuteInputResult::None { *state.last_found_time_mut() = current_time(); } Ok((exec_res, corpus_id)) @@ -629,7 +614,7 @@ where if self.input_filter.should_execute(input) { self.evaluate_input(state, executor, manager, input) } else { - Ok((ExecuteInputResult::default(), None)) + Ok((ExecuteInputResult::None, None)) } } @@ -652,7 +637,7 @@ where executor: &mut E, manager: &mut EM, input: I, - ) -> Result<(CorpusId, ExecuteInputResult), Error> { + ) -> Result { *state.last_found_time_mut() = current_time(); let exit_kind = self.execute_input(state, executor, manager, &input)?; @@ -682,7 +667,7 @@ where self.objective_mut() .append_metadata(state, manager, &*observers, &mut testcase)?; // we don't care about solution id - let _ = state.solutions_mut().add(testcase.clone())?; + let id = state.solutions_mut().add(testcase)?; manager.fire( state, @@ -692,17 +677,22 @@ where time: current_time(), }, )?; + + // if it is a solution then early return + return Ok(id); } + // not a solution + // several is_interesting implementations collect some data about the run, later used in // append_metadata; we *must* invoke is_interesting here to collect it #[cfg(not(feature = "introspection"))] - let corpus_worthy = + let _is_corpus = self.feedback_mut() .is_interesting(state, manager, &input, &*observers, &exit_kind)?; #[cfg(feature = "introspection")] - let corpus_worthy = self.feedback_mut().is_interesting_introspection( + let _is_corpus = self.feedback_mut().is_interesting_introspection( state, manager, &input, @@ -738,7 +728,7 @@ where node_id: None, }, )?; - Ok((id, ExecuteInputResult::new(corpus_worthy, is_solution))) + Ok(id) } fn add_disabled_input(&mut self, state: &mut S, input: I) -> Result { diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 4308e192bf..7cfdbb8323 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -26,8 +26,6 @@ use serde::{Deserialize, Serialize, de::DeserializeOwned}; mod stack; pub use stack::StageStack; -#[cfg(feature = "std")] -use crate::fuzzer::ExecuteInputResult; #[cfg(feature = "introspection")] use crate::monitors::stats::ClientPerfStats; use crate::{ @@ -35,7 +33,7 @@ use crate::{ corpus::{Corpus, CorpusId, HasCurrentCorpusId, HasTestcase, InMemoryCorpus, Testcase}, events::{Event, EventFirer, LogSeverity}, feedbacks::StateInitializer, - fuzzer::Evaluator, + fuzzer::{Evaluator, ExecuteInputResult}, generators::Generator, inputs::{Input, NopInput}, stages::StageId, @@ -717,15 +715,15 @@ where Ok(input) => input, Err(err) => { log::error!("Skipping input that we could not load from {path:?}: {err:?}"); - return Ok(ExecuteInputResult::default()); + return Ok(ExecuteInputResult::None); } }; if config.forced { - let (_id, result) = fuzzer.add_input(self, executor, manager, input)?; - Ok(result) + let _: CorpusId = fuzzer.add_input(self, executor, manager, input)?; + Ok(ExecuteInputResult::Corpus) } else { let (res, _) = fuzzer.evaluate_input(self, executor, manager, &input)?; - if !(res.is_corpus() || res.is_solution()) { + if res == ExecuteInputResult::None { fuzzer.add_disabled_input(self, input)?; log::warn!("input {:?} was not interesting, adding as disabled.", &path); } @@ -750,7 +748,7 @@ where match self.next_file() { Ok(path) => { let res = self.load_file(&path, manager, fuzzer, executor, &mut config)?; - if config.exit_on_solution && res.is_solution() { + if config.exit_on_solution && matches!(res, ExecuteInputResult::Solution) { return Err(Error::invalid_corpus(format!( "Input {} resulted in a solution.", path.display() @@ -1054,11 +1052,11 @@ where for _ in 0..num { let input = generator.generate(self)?; if forced { - let (_, _) = fuzzer.add_input(self, executor, manager, input)?; + let _: CorpusId = fuzzer.add_input(self, executor, manager, input)?; added += 1; } else { let (res, _) = fuzzer.evaluate_input(self, executor, manager, &input)?; - if res.is_corpus() { + if res != ExecuteInputResult::None { added += 1; } } diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 86aed815fd..aca720dfcd 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -12,7 +12,7 @@ use std::{ptr, str}; #[cfg(feature = "usermode")] use libafl::state::HasCorpus; use libafl::{ - Error, ExecutionProcessor, HasScheduler, + Error, ExecutionProcessor, events::{EventFirer, EventRestarter}, executors::{ Executor, ExitKind, HasObservers, @@ -21,7 +21,7 @@ use libafl::{ inprocess_fork::stateful::StatefulInProcessForkExecutor, }, feedbacks::Feedback, - fuzzer::{HasFeedback, HasObjective}, + fuzzer::HasObjective, inputs::Input, observers::ObserversTuple, state::{HasCurrentTestcase, HasExecutions, HasSolutions}, @@ -60,7 +60,7 @@ pub struct QemuExecutor<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, Z> { /// /// This should be used as a crash handler, and nothing else. #[cfg(feature = "usermode")] -pub unsafe fn inproc_qemu_crash_handler( +pub unsafe fn inproc_qemu_crash_handler( signal: Signal, info: &mut siginfo_t, mut context: Option<&mut ucontext_t>, @@ -70,10 +70,9 @@ pub unsafe fn inproc_qemu_crash_handler( E: Executor + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + Unpin, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone + Unpin, { log::debug!("QEMU signal handler has been triggered (signal {signal})"); @@ -127,7 +126,7 @@ pub unsafe fn inproc_qemu_crash_handler( log::debug!("Running crash hooks."); run_target_crash_hooks::(signal.into()); - assert!(unsafe { data.maybe_report_crash::(None) }); + assert!(unsafe { data.maybe_report_crash::(None) }); if let Some(cpu) = qemu.current_cpu() { eprint!("QEMU Context:\n{}", cpu.display_context()); @@ -164,7 +163,7 @@ pub(crate) static BREAK_ON_TMOUT: AtomicBool = AtomicBool::new(false); /// # Safety /// Can call through the `unix_signal_handler::inproc_timeout_handler`. /// Calling this method multiple times concurrently can lead to race conditions. -pub unsafe fn inproc_qemu_timeout_handler( +pub unsafe fn inproc_qemu_timeout_handler( signal: Signal, info: &mut siginfo_t, context: Option<&mut ucontext_t>, @@ -174,12 +173,11 @@ pub unsafe fn inproc_qemu_timeout_handler( E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, ET: EmulatorModuleTuple, - F: Feedback, I: Unpin, OF: Feedback, S: HasExecutions + HasSolutions + Unpin + HasCurrentTestcase, I: Input, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, { #[cfg(feature = "systemmode")] unsafe { @@ -189,7 +187,6 @@ pub unsafe fn inproc_qemu_timeout_handler( libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::< E, EM, - F, I, OF, S, @@ -208,7 +205,6 @@ pub unsafe fn inproc_qemu_timeout_handler( libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::< E, EM, - F, I, OF, S, @@ -238,7 +234,7 @@ where OT: ObserversTuple, S: Unpin + HasExecutions + HasSolutions + HasCurrentTestcase, { - pub fn new( + pub fn new( emulator: Emulator, harness_fn: &'a mut H, observers: OT, @@ -252,12 +248,8 @@ where CM: CommandManager, ED: EmulatorDriver, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, - Z: HasObjective - + HasScheduler - + ExecutionProcessor - + HasFeedback, + Z: HasObjective + ExecutionProcessor, { let mut inner = StatefulInProcessExecutor::with_timeout( harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout, @@ -267,7 +259,7 @@ where #[cfg(feature = "usermode")] { inner.inprocess_hooks_mut().crash_handler = - inproc_qemu_crash_handler:: as *const c_void; + inproc_qemu_crash_handler:: as *const c_void; } // rewrite the timeout handler pointer @@ -275,7 +267,6 @@ where StatefulInProcessExecutor<'a, EM, Emulator, H, I, OT, S, Z>, EM, ET, - F, I, OF, S, diff --git a/libafl_targets/src/windows_asan.rs b/libafl_targets/src/windows_asan.rs index 887798cbdc..767fec87cf 100644 --- a/libafl_targets/src/windows_asan.rs +++ b/libafl_targets/src/windows_asan.rs @@ -1,7 +1,7 @@ //! Setup asan death callbback use libafl::{ - HasFeedback, HasObjective, HasScheduler, + HasObjective, events::{EventFirer, EventRestarter}, executors::{Executor, HasObservers, hooks::windows::windows_asan_handler::asan_death_handler}, feedbacks::Feedback, @@ -29,7 +29,7 @@ unsafe extern "C" { /// /// # Safety /// Calls the unsafe `__sanitizer_set_death_callback` symbol, but should be safe to call otherwise. -pub unsafe fn setup_asan_callback( +pub unsafe fn setup_asan_callback( _executor: &E, _event_mgr: &EM, _fuzzer: &Z, @@ -37,13 +37,12 @@ pub unsafe fn setup_asan_callback( E: Executor + HasObservers, E::Observers: ObserversTuple, EM: EventFirer + EventRestarter, - F: Feedback, OF: Feedback, S: HasExecutions + HasSolutions + HasCurrentTestcase, - Z: HasObjective + HasFeedback + HasScheduler, + Z: HasObjective, I: Input + Clone, { unsafe { - __sanitizer_set_death_callback(Some(asan_death_handler::)); + __sanitizer_set_death_callback(Some(asan_death_handler::)); } }