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 <you@example.com>
This commit is contained in:
Dongjia "toka" Zhang 2025-02-05 14:00:09 +01:00 committed by GitHub
parent 8398f8f99a
commit c09feeba4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 52 additions and 61 deletions

View File

@ -43,12 +43,6 @@ use crate::{inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase}
/// The inmem executor's handlers.
#[expect(missing_debug_implementations)]
pub struct InProcessHooks<I, S> {
/// 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<I, S> ExecutorHook<I, S> for InProcessHooks<I, S> {
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<I, S> InProcessHooks<I, S> {
unsafe {
setup_signal_handler(data)?;
}
#[cfg(feature = "std")]
unsafe {
let data = &raw mut GLOBAL_STATE;
(*data).crash_handler =
unix_signal_handler::inproc_crash_handler::<E, EM, I, OF, S, Z> as *const c_void;
(*data).timeout_handler =
unix_signal_handler::inproc_timeout_handler::<E, EM, I, OF, S, Z> as *const _;
}
compiler_fence(Ordering::SeqCst);
Ok(Self {
#[cfg(feature = "std")]
crash_handler: unix_signal_handler::inproc_crash_handler::<E, EM, I, OF, S, Z>
as *const c_void,
#[cfg(feature = "std")]
timeout_handler: unix_signal_handler::inproc_timeout_handler::<E, EM, I, OF, S, Z>
as *const _,
#[cfg(feature = "std")]
timer: TimerStruct::new(exec_tmout),
phantom: PhantomData,
})
@ -288,7 +278,7 @@ impl<I, S> InProcessHooks<I, S> {
>();
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<I, S> InProcessHooks<I, S> {
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<I, S> InProcessHooks<I, S> {
#[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<PTP_TIMER>,
@ -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

View File

@ -27,10 +27,6 @@ use crate::{
/// The inmem fork executor's hooks.
#[derive(Debug)]
pub struct InChildProcessHooks<I, S> {
/// 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<I, S> ExecutorHook<I, S> for InChildProcessHooks<I, S> {
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<I, S> InChildProcessHooks<I, S> {
#[cfg(not(miri))]
setup_signal_handler(data)?;
compiler_fence(Ordering::SeqCst);
(*data).crash_handler =
child_signal_handlers::child_crash_handler::<E, I, S> as *const c_void;
(*data).timeout_handler =
child_signal_handlers::child_timeout_handler::<E, I, S> as *const c_void;
Ok(Self {
crash_handler: child_signal_handlers::child_crash_handler::<E, I, S>
as *const c_void,
timeout_handler: child_signal_handlers::child_timeout_handler::<E, I, S>
as *const c_void,
phantom: PhantomData,
})
}
@ -79,8 +68,6 @@ impl<I, S> InChildProcessHooks<I, S> {
#[must_use]
pub fn nop() -> Self {
Self {
crash_handler: null(),
timeout_handler: null(),
phantom: PhantomData,
}
}

View File

@ -90,16 +90,19 @@ where
input: &I,
) -> Result<ExitKind, Error> {
*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)
}

View File

@ -86,6 +86,7 @@ where
input: &I,
) -> Result<ExitKind, Error> {
*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)
}

View File

@ -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<EM, I, OT, S>,
Z: HasObjective<Objective = OF> + HasScheduler<I, S> + ExecutionProcessor<EM, I, OT, S>,
{
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::<Self, EM, ET, I, OF, S, Z> as *const c_void;
}
inner.inprocess_hooks_mut().timeout_handler = inproc_qemu_timeout_handler::<
StatefulInProcessExecutor<'a, EM, Emulator<C, CM, ED, ET, I, S, SM>, 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<C, CM, ED, ET, I, S, SM>,
H,
I,
OT,
S,
Z,
>,
EM,
ET,
I,
OF,
S,
Z,
> as *const c_void;
}
Ok(Self {
inner,