diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 8d3d28a36b..67b3781a81 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -68,7 +68,7 @@ pub struct ShutdownSignalData { /// Type for shutdown handler #[cfg(all(unix, feature = "std"))] pub type ShutdownFuncPtr = - unsafe fn(Signal, siginfo_t, &mut ucontext_t, data: &mut ShutdownSignalData); + unsafe fn(Signal, &mut siginfo_t, &mut ucontext_t, data: &mut ShutdownSignalData); /// Shutdown handler. `SigTerm`, `SigInterrupt`, `SigQuit` call this /// We can't handle SIGKILL in the signal handler, this means that you shouldn't kill your fuzzer with `kill -9` because then the shmem segments are never freed @@ -79,7 +79,7 @@ pub type ShutdownFuncPtr = #[cfg(all(unix, feature = "std"))] pub unsafe fn shutdown_handler( signal: Signal, - _info: siginfo_t, + _info: &mut siginfo_t, _context: &mut ucontext_t, data: &ShutdownSignalData, ) where @@ -106,7 +106,7 @@ pub unsafe fn shutdown_handler( #[cfg(all(unix, feature = "std"))] impl Handler for ShutdownSignalData { - fn handle(&mut self, signal: Signal, info: siginfo_t, context: &mut ucontext_t) { + fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: &mut ucontext_t) { unsafe { let data = &mut SHUTDOWN_SIGHANDLER_DATA; if !data.shutdown_handler.is_null() { diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index cb5b5a551c..9270c5c601 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -418,13 +418,13 @@ impl InProcessHandlers { /// The global state of the in-process harness. #[derive(Debug)] -pub(crate) struct InProcessExecutorHandlerData { +pub struct InProcessExecutorHandlerData { state_ptr: *mut c_void, event_mgr_ptr: *mut c_void, fuzzer_ptr: *mut c_void, executor_ptr: *const c_void, - pub current_input_ptr: *const c_void, - pub in_handler: bool, + pub(crate) current_input_ptr: *const c_void, + pub(crate) in_handler: bool, /// The timeout handler #[cfg(any(unix, feature = "std"))] @@ -478,7 +478,7 @@ impl InProcessExecutorHandlerData { } #[cfg(any(unix, feature = "std"))] - pub fn is_valid(&self) -> bool { + pub(crate) fn is_valid(&self) -> bool { !self.current_input_ptr.is_null() } @@ -631,8 +631,9 @@ pub fn run_observers_and_save_state( log::info!("Bye!"); } +/// The inprocess executor singal handling code for unix #[cfg(unix)] -mod unix_signal_handler { +pub mod unix_signal_handler { use alloc::vec::Vec; #[cfg(feature = "std")] use alloc::{boxed::Box, string::String}; @@ -658,12 +659,12 @@ mod unix_signal_handler { }; pub(crate) type HandlerFuncPtr = - unsafe fn(Signal, siginfo_t, &mut ucontext_t, data: &mut InProcessExecutorHandlerData); + unsafe fn(Signal, &mut siginfo_t, &mut ucontext_t, data: &mut InProcessExecutorHandlerData); /// A handler that does nothing. /*pub fn nop_handler( _signal: Signal, - _info: siginfo_t, + _info: &mut siginfo_t, _context: &mut ucontext_t, _data: &mut InProcessExecutorHandlerData, ) { @@ -671,7 +672,7 @@ mod unix_signal_handler { #[cfg(unix)] impl Handler for InProcessExecutorHandlerData { - fn handle(&mut self, signal: Signal, info: siginfo_t, context: &mut ucontext_t) { + fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: &mut ucontext_t) { unsafe { let data = &mut GLOBAL_STATE; let in_handler = data.set_in_handler(true); @@ -748,10 +749,15 @@ mod unix_signal_handler { })); } + /// Timeout-Handler for in-process fuzzing. + /// It will store the current State to shmem, then exit. + /// + /// # Safety + /// Well, signal handling is not safe #[cfg(unix)] - pub(crate) unsafe fn inproc_timeout_handler( + pub unsafe fn inproc_timeout_handler( _signal: Signal, - _info: siginfo_t, + _info: &mut siginfo_t, _context: &mut ucontext_t, data: &mut InProcessExecutorHandlerData, ) where @@ -795,10 +801,13 @@ mod unix_signal_handler { /// Crash-Handler for in-process fuzzing. /// Will be used for signal handling. /// It will store the current State to shmem, then exit. + /// + /// # Safety + /// Well, signal handling is not safe #[allow(clippy::too_many_lines)] - pub(crate) unsafe fn inproc_crash_handler( + pub unsafe fn inproc_crash_handler( signal: Signal, - _info: siginfo_t, + _info: &mut siginfo_t, _context: &mut ucontext_t, data: &mut InProcessExecutorHandlerData, ) where @@ -991,7 +1000,7 @@ pub mod windows_asan_handler { } #[cfg(all(windows, feature = "std"))] -mod windows_exception_handler { +pub mod windows_exception_handler { #[cfg(feature = "std")] use alloc::boxed::Box; use alloc::{string::String, vec::Vec}; @@ -1058,6 +1067,9 @@ mod windows_exception_handler { } /// invokes the `post_exec` hook on all observer in case of panic + /// + /// # Safety + /// Well, exception handling is not safe #[cfg(feature = "std")] pub fn setup_panic_hook() where @@ -1117,6 +1129,9 @@ mod windows_exception_handler { } /// Timeout handler for windows + /// + /// # Safety + /// Well, exception handling is not safe pub unsafe extern "system" fn inproc_timeout_handler( _p0: *mut u8, global_state: *mut c_void, @@ -1180,8 +1195,12 @@ mod windows_exception_handler { // log::info!("TIMER INVOKED!"); } + /// Crash handler for windows + /// + /// # Safety + /// Well, exception handling is not safe #[allow(clippy::too_many_lines)] - pub(crate) unsafe fn inproc_crash_handler( + pub unsafe fn inproc_crash_handler( exception_pointers: *mut EXCEPTION_POINTERS, data: &mut InProcessExecutorHandlerData, ) where @@ -1303,7 +1322,7 @@ mod windows_exception_handler { /// The signature of the crash handler function #[cfg(all(feature = "std", unix))] pub(crate) type ForkHandlerFuncPtr = - unsafe fn(Signal, siginfo_t, &mut ucontext_t, data: &mut InProcessForkExecutorGlobalData); + unsafe fn(Signal, &mut siginfo_t, &mut ucontext_t, data: &mut InProcessForkExecutorGlobalData); /// The inmem fork executor's handlers. #[cfg(all(feature = "std", unix))] @@ -1443,7 +1462,7 @@ pub(crate) static mut FORK_EXECUTOR_GLOBAL_DATA: InProcessForkExecutorGlobalData #[cfg(all(feature = "std", unix))] impl Handler for InProcessForkExecutorGlobalData { - fn handle(&mut self, signal: Signal, info: siginfo_t, context: &mut ucontext_t) { + fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: &mut ucontext_t) { match signal { Signal::SigUser2 | Signal::SigAlarm => unsafe { if !FORK_EXECUTOR_GLOBAL_DATA.timeout_handler.is_null() { @@ -2052,7 +2071,7 @@ pub mod child_signal_handlers { #[cfg(unix)] pub(crate) unsafe fn child_crash_handler( _signal: Signal, - _info: siginfo_t, + _info: &mut siginfo_t, _context: &mut ucontext_t, data: &mut InProcessForkExecutorGlobalData, ) where @@ -2074,7 +2093,7 @@ pub mod child_signal_handlers { #[cfg(unix)] pub(crate) unsafe fn child_timeout_handler( _signal: Signal, - _info: siginfo_t, + _info: &mut siginfo_t, _context: &mut ucontext_t, data: &mut InProcessForkExecutorGlobalData, ) where diff --git a/libafl_bolts/src/llmp.rs b/libafl_bolts/src/llmp.rs index 9c310f419c..8e3cb1bf97 100644 --- a/libafl_bolts/src/llmp.rs +++ b/libafl_bolts/src/llmp.rs @@ -1939,7 +1939,7 @@ pub struct LlmpShutdownSignalHandler { #[cfg(unix)] impl Handler for LlmpShutdownSignalHandler { - fn handle(&mut self, _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t) { + fn handle(&mut self, _signal: Signal, _info: &mut siginfo_t, _context: &mut ucontext_t) { unsafe { ptr::write_volatile(&mut self.shutting_down, true); } diff --git a/libafl_bolts/src/minibsod.rs b/libafl_bolts/src/minibsod.rs index 722b211ca5..76f79ffa80 100644 --- a/libafl_bolts/src/minibsod.rs +++ b/libafl_bolts/src/minibsod.rs @@ -836,7 +836,7 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er pub fn generate_minibsod( writer: &mut BufWriter, signal: Signal, - _siginfo: siginfo_t, + _siginfo: &siginfo_t, ucontext: &ucontext_t, ) -> Result<(), std::io::Error> { writeln!(writer, "{:━^100}", " CRASH ")?; diff --git a/libafl_bolts/src/os/unix_signals.rs b/libafl_bolts/src/os/unix_signals.rs index 05542652e6..b0ff5a91cc 100644 --- a/libafl_bolts/src/os/unix_signals.rs +++ b/libafl_bolts/src/os/unix_signals.rs @@ -378,7 +378,7 @@ impl Display for Signal { #[cfg(feature = "alloc")] pub trait Handler { /// Handle a signal - fn handle(&mut self, signal: Signal, info: siginfo_t, _context: &mut ucontext_t); + fn handle(&mut self, signal: Signal, info: &mut siginfo_t, _context: &mut ucontext_t); /// Return a list of signals to handle fn signals(&self) -> Vec; } @@ -414,7 +414,7 @@ static mut SIGNAL_HANDLERS: [Option; 32] = [ /// This should be somewhat safe to call for signals previously registered, /// unless the signal handlers registered using [`setup_signal_handler()`] are broken. #[cfg(feature = "alloc")] -unsafe fn handle_signal(sig: c_int, info: siginfo_t, void: *mut c_void) { +unsafe fn handle_signal(sig: c_int, info: *mut siginfo_t, void: *mut c_void) { let signal = &Signal::try_from(sig).unwrap(); let handler = { match &SIGNAL_HANDLERS[*signal as usize] { @@ -424,7 +424,7 @@ unsafe fn handle_signal(sig: c_int, info: siginfo_t, void: *mut c_void) { }; handler.handle( *signal, - info, + &mut ptr::read_unaligned(info), &mut ptr::read_unaligned(void as *mut ucontext_t), ); } diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index b9d2a72bd7..8ffdad7261 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -8,7 +8,7 @@ use which::which; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -const QEMU_REVISION: &str = "ff5bc3d934044a5a5466759525f0371ccf86152e"; +const QEMU_REVISION: &str = "ead06288fd597e72cbf50db1c89386f952592860"; fn build_dep_check(tools: &[&str]) { for tool in tools { @@ -216,7 +216,6 @@ pub fn build( .arg("--disable-gtk") .arg("--disable-guest-agent") .arg("--disable-guest-agent-msi") - .arg("--disable-hax") .arg("--disable-hvf") .arg("--disable-iconv") .arg("--disable-jack") diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index fe55023243..3c9181a3eb 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -7,12 +7,14 @@ use core::{ mem::MaybeUninit, ptr::{addr_of, copy_nonoverlapping, null}, }; -use std::{cell::OnceCell, slice::from_raw_parts, str::from_utf8_unchecked}; +#[cfg(emulation_mode = "usermode")] +use std::cell::OnceCell; #[cfg(emulation_mode = "systemmode")] use std::{ ffi::{CStr, CString}, ptr::null_mut, }; +use std::{slice::from_raw_parts, str::from_utf8_unchecked}; #[cfg(emulation_mode = "usermode")] use libc::c_int; diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 581e24183c..416f848811 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -1,6 +1,10 @@ //! A `QEMU`-based executor for binary-only instrumentation in `LibAFL` +#[cfg(emulation_mode = "usermode")] +use core::ffi::c_void; use core::fmt::{self, Debug, Formatter}; +#[cfg(emulation_mode = "usermode")] +use libafl::executors::inprocess::InProcessExecutorHandlerData; #[cfg(feature = "fork")] use libafl::{ events::EventManager, @@ -9,7 +13,7 @@ use libafl::{ }; use libafl::{ events::{EventFirer, EventRestarter}, - executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, + executors::{inprocess::InProcessExecutor, Executor, ExitKind, HasObservers}, feedbacks::Feedback, fuzzer::HasObjective, inputs::UsesInput, @@ -17,6 +21,8 @@ use libafl::{ state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState}, Error, }; +#[cfg(emulation_mode = "usermode")] +use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Signal}; #[cfg(feature = "fork")] use libafl_bolts::shmem::ShMemProvider; @@ -29,9 +35,9 @@ where OT: ObserversTuple, QT: QemuHelperTuple, { - first_exec: bool, - hooks: &'a mut QemuHooks<'a, QT, S>, inner: InProcessExecutor<'a, H, OT, S>, + hooks: &'a mut QemuHooks<'a, QT, S>, + first_exec: bool, } impl<'a, H, OT, QT, S> Debug for QemuExecutor<'a, H, OT, QT, S> @@ -49,6 +55,46 @@ where } } +#[cfg(emulation_mode = "usermode")] +extern "C" { + // Original QEMU user signal handler + fn libafl_qemu_handle_crash(signal: i32, info: *mut siginfo_t, puc: *mut c_void) -> i32; +} + +#[cfg(emulation_mode = "usermode")] +static mut USE_LIBAFL_CRASH_HANDLER: bool = false; + +#[cfg(emulation_mode = "usermode")] +#[no_mangle] +pub unsafe extern "C" fn libafl_executor_reinstall_handlers() { + USE_LIBAFL_CRASH_HANDLER = true; +} + +#[cfg(emulation_mode = "usermode")] +pub unsafe fn inproc_qemu_crash_handler( + signal: Signal, + info: &mut siginfo_t, + context: &mut ucontext_t, + data: &mut InProcessExecutorHandlerData, +) where + E: Executor + HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + Z: HasObjective, +{ + let real_crash = if USE_LIBAFL_CRASH_HANDLER { + true + } else { + libafl_qemu_handle_crash(signal as i32, info, context as *mut _ as *mut c_void) != 0 + }; + if real_crash { + libafl::executors::inprocess::unix_signal_handler::inproc_crash_handler::( + signal, info, context, data, + ); + } +} + impl<'a, H, OT, QT, S> QemuExecutor<'a, H, OT, QT, S> where H: FnMut(&S::Input) -> ExitKind, @@ -70,6 +116,20 @@ where S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor, Z: HasObjective, { + #[cfg(emulation_mode = "usermode")] + { + let mut inner = + InProcessExecutor::new(harness_fn, observers, fuzzer, state, event_mgr)?; + inner.handlers_mut().crash_handler = + inproc_qemu_crash_handler::, EM, OF, Z> + as *const c_void; + Ok(Self { + first_exec: true, + hooks, + inner, + }) + } + #[cfg(not(emulation_mode = "usermode"))] Ok(Self { first_exec: true, hooks,