From c09feeba4e472fd60abdee1e3121407d486cea8d Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Wed, 5 Feb 2025 14:00:09 +0100 Subject: [PATCH] Don't write pointers to the crash handlers at every execution (#2935) * make it safe * aa * forgot to put it back * stateful * comment * lol * aa * aa * aa * win * lol * lol * a * a * i hate rust --------- Co-authored-by: Your Name --- libafl/src/executors/hooks/inprocess.rs | 45 +++++++------------- libafl/src/executors/hooks/inprocess_fork.rs | 23 +++------- libafl/src/executors/inprocess/mod.rs | 3 ++ libafl/src/executors/inprocess/stateful.rs | 2 + libafl_qemu/src/executor.rs | 40 +++++++++++------ 5 files changed, 52 insertions(+), 61 deletions(-) diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index 8793d4a236..03fed6b1bf 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -43,12 +43,6 @@ use crate::{inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase} /// The inmem executor's handlers. #[expect(missing_debug_implementations)] pub struct InProcessHooks { - /// On crash C function pointer - #[cfg(feature = "std")] - pub crash_handler: *const c_void, - /// On timeout C function pointer - #[cfg(feature = "std")] - pub timeout_handler: *const c_void, /// `TImer` struct #[cfg(feature = "std")] pub timer: TimerStruct, @@ -196,20 +190,12 @@ impl ExecutorHook for InProcessHooks { fn init(&mut self, _state: &mut S) {} /// Call before running a target. fn pre_exec(&mut self, _state: &mut S, _input: &I) { - #[cfg(feature = "std")] - unsafe { - let data = &raw mut GLOBAL_STATE; - (*data).crash_handler = self.crash_handler; - (*data).timeout_handler = self.timeout_handler; - } - #[cfg(all(feature = "std", not(all(miri, target_vendor = "apple"))))] self.timer_mut().set_timer(); } /// Call after running a target. fn post_exec(&mut self, _state: &mut S, _input: &I) { - // timeout stuff // # Safety // We're calling this only once per execution, in a single thread. #[cfg(all(feature = "std", not(all(miri, target_vendor = "apple"))))] @@ -247,15 +233,19 @@ impl InProcessHooks { unsafe { setup_signal_handler(data)?; } + + #[cfg(feature = "std")] + unsafe { + let data = &raw mut GLOBAL_STATE; + (*data).crash_handler = + unix_signal_handler::inproc_crash_handler:: as *const c_void; + (*data).timeout_handler = + unix_signal_handler::inproc_timeout_handler:: as *const _; + } + compiler_fence(Ordering::SeqCst); Ok(Self { #[cfg(feature = "std")] - crash_handler: unix_signal_handler::inproc_crash_handler:: - as *const c_void, - #[cfg(feature = "std")] - timeout_handler: unix_signal_handler::inproc_timeout_handler:: - as *const _, - #[cfg(feature = "std")] timer: TimerStruct::new(exec_tmout), phantom: PhantomData, }) @@ -288,7 +278,7 @@ impl InProcessHooks { >(); setup_exception_handler(data)?; compiler_fence(Ordering::SeqCst); - let crash_handler = + (*data).crash_handler = crate::executors::hooks::windows::windows_exception_handler::inproc_crash_handler::< E, EM, @@ -306,10 +296,9 @@ impl InProcessHooks { S, Z, > as *const c_void; + (*data).timeout_handler = timeout_handler; let timer = TimerStruct::new(exec_tmout, timeout_handler); ret = Ok(Self { - crash_handler, - timeout_handler, timer, phantom: PhantomData, }); @@ -347,10 +336,6 @@ impl InProcessHooks { #[cfg(not(windows))] pub fn nop() -> Self { Self { - #[cfg(feature = "std")] - crash_handler: ptr::null(), - #[cfg(feature = "std")] - timeout_handler: ptr::null(), #[cfg(feature = "std")] timer: TimerStruct::new(Duration::from_millis(5000)), phantom: PhantomData, @@ -374,10 +359,10 @@ pub struct InProcessExecutorHandlerData { /// The timeout handler #[cfg(feature = "std")] - pub(crate) crash_handler: *const c_void, + pub crash_handler: *const c_void, /// The timeout handler #[cfg(feature = "std")] - pub(crate) timeout_handler: *const c_void, + pub timeout_handler: *const c_void, #[cfg(all(windows, feature = "std"))] pub(crate) ptp_timer: Option, @@ -501,7 +486,7 @@ impl InProcessExecutorHandlerData { } /// Exception handling needs some nasty unsafe. -pub(crate) static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHandlerData { +pub static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHandlerData { // The state ptr for signal handling state_ptr: null_mut(), // The event manager ptr for signal handling diff --git a/libafl/src/executors/hooks/inprocess_fork.rs b/libafl/src/executors/hooks/inprocess_fork.rs index 753a5f6ce6..9db361c55d 100644 --- a/libafl/src/executors/hooks/inprocess_fork.rs +++ b/libafl/src/executors/hooks/inprocess_fork.rs @@ -27,10 +27,6 @@ use crate::{ /// The inmem fork executor's hooks. #[derive(Debug)] pub struct InChildProcessHooks { - /// On crash C function pointer - pub crash_handler: *const c_void, - /// On timeout C function pointer - pub timeout_handler: *const c_void, phantom: PhantomData<(I, S)>, } @@ -39,14 +35,7 @@ impl ExecutorHook for InChildProcessHooks { fn init(&mut self, _state: &mut S) {} /// Call before running a target. - fn pre_exec(&mut self, _state: &mut S, _input: &I) { - unsafe { - let data = &raw mut FORK_EXECUTOR_GLOBAL_DATA; - (*data).crash_handler = self.crash_handler; - (*data).timeout_handler = self.timeout_handler; - compiler_fence(Ordering::SeqCst); - } - } + fn pre_exec(&mut self, _state: &mut S, _input: &I) {} fn post_exec(&mut self, _state: &mut S, _input: &I) {} } @@ -65,11 +54,11 @@ impl InChildProcessHooks { #[cfg(not(miri))] setup_signal_handler(data)?; compiler_fence(Ordering::SeqCst); + (*data).crash_handler = + child_signal_handlers::child_crash_handler:: as *const c_void; + (*data).timeout_handler = + child_signal_handlers::child_timeout_handler:: as *const c_void; Ok(Self { - crash_handler: child_signal_handlers::child_crash_handler:: - as *const c_void, - timeout_handler: child_signal_handlers::child_timeout_handler:: - as *const c_void, phantom: PhantomData, }) } @@ -79,8 +68,6 @@ impl InChildProcessHooks { #[must_use] pub fn nop() -> Self { Self { - crash_handler: null(), - timeout_handler: null(), phantom: PhantomData, } } diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index 6c7ddd54a3..ef22caf20f 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -90,16 +90,19 @@ where input: &I, ) -> Result { *state.executions_mut() += 1; + unsafe { let executor_ptr = ptr::from_ref(self) as *const c_void; self.inner .enter_target(fuzzer, state, mgr, input, executor_ptr); } + self.inner.hooks.pre_exec_all(state, input); let ret = self.harness_fn.borrow_mut()(input); self.inner.hooks.post_exec_all(state, input); + self.inner.leave_target(fuzzer, state, mgr, input); Ok(ret) } diff --git a/libafl/src/executors/inprocess/stateful.rs b/libafl/src/executors/inprocess/stateful.rs index 5efa7cd94c..26265d6028 100644 --- a/libafl/src/executors/inprocess/stateful.rs +++ b/libafl/src/executors/inprocess/stateful.rs @@ -86,6 +86,7 @@ where input: &I, ) -> Result { *state.executions_mut() += 1; + unsafe { let executor_ptr = ptr::from_ref(self) as *const c_void; self.inner @@ -96,6 +97,7 @@ where let ret = self.harness_fn.borrow_mut()(&mut self.exposed_executor_state, state, input); self.inner.hooks.post_exec_all(state, input); + self.inner.leave_target(fuzzer, state, mgr, input); Ok(ret) } diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index ea1b4ed2ad..9695a1a26d 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -14,7 +14,7 @@ use libafl::state::HasCorpus; use libafl::{ events::{EventFirer, EventRestarter}, executors::{ - hooks::inprocess::InProcessExecutorHandlerData, + hooks::inprocess::{InProcessExecutorHandlerData, GLOBAL_STATE}, inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks}, inprocess_fork::stateful::StatefulInProcessForkExecutor, Executor, ExitKind, HasObservers, @@ -243,25 +243,39 @@ where OF: Feedback, Z: HasObjective + HasScheduler + ExecutionProcessor, { - let mut inner = StatefulInProcessExecutor::with_timeout( + let inner = StatefulInProcessExecutor::with_timeout( harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout, )?; + let data = &raw mut GLOBAL_STATE; #[cfg(feature = "usermode")] - { - inner.inprocess_hooks_mut().crash_handler = + unsafe { + // rewrite the crash handler pointer + (*data).crash_handler = inproc_qemu_crash_handler:: as *const c_void; } - inner.inprocess_hooks_mut().timeout_handler = inproc_qemu_timeout_handler::< - StatefulInProcessExecutor<'a, EM, Emulator, H, I, OT, S, Z>, - EM, - ET, - I, - OF, - S, - Z, - > as *const c_void; + unsafe { + // rewrite the timeout handler pointer + (*data).timeout_handler = inproc_qemu_timeout_handler::< + StatefulInProcessExecutor< + 'a, + EM, + Emulator, + H, + I, + OT, + S, + Z, + >, + EM, + ET, + I, + OF, + S, + Z, + > as *const c_void; + } Ok(Self { inner,