Call the original QEMU user crash handler in libafl_qemu (#1575)
* Call the original QEMU user crash handler in libafl_qemu * Return if real crash or not * merge * Fix singal handlers in libafl and libafl_qemu * doc and clippy * clippy * clippy * clippy * slirp * fix * fix system
This commit is contained in:
parent
d4e9107fc2
commit
cffbf069d2
@ -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<SP>(
|
||||
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<SP>(
|
||||
|
||||
#[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() {
|
||||
|
@ -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<E, EM, OF, Z>(
|
||||
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<E, EM, OF, Z>(
|
||||
pub unsafe fn inproc_timeout_handler<E, EM, OF, Z>(
|
||||
_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<E, EM, OF, Z>(
|
||||
pub unsafe fn inproc_crash_handler<E, EM, OF, Z>(
|
||||
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<E, EM, OF, Z>()
|
||||
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<E, EM, OF, Z>(
|
||||
_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<E, EM, OF, Z>(
|
||||
pub unsafe fn inproc_crash_handler<E, EM, OF, Z>(
|
||||
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<E>(
|
||||
_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<E>(
|
||||
_signal: Signal,
|
||||
_info: siginfo_t,
|
||||
_info: &mut siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
data: &mut InProcessForkExecutorGlobalData,
|
||||
) where
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -836,7 +836,7 @@ fn write_minibsod<W: Write>(writer: &mut BufWriter<W>) -> Result<(), std::io::Er
|
||||
pub fn generate_minibsod<W: Write>(
|
||||
writer: &mut BufWriter<W>,
|
||||
signal: Signal,
|
||||
_siginfo: siginfo_t,
|
||||
_siginfo: &siginfo_t,
|
||||
ucontext: &ucontext_t,
|
||||
) -> Result<(), std::io::Error> {
|
||||
writeln!(writer, "{:━^100}", " CRASH ")?;
|
||||
|
@ -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<Signal>;
|
||||
}
|
||||
@ -414,7 +414,7 @@ static mut SIGNAL_HANDLERS: [Option<HandlerHolder>; 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),
|
||||
);
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
|
@ -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<S>,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
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<E, EM, OF, Z>(
|
||||
signal: Signal,
|
||||
info: &mut siginfo_t,
|
||||
context: &mut ucontext_t,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
) where
|
||||
E: Executor<EM, Z> + HasObservers,
|
||||
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||
OF: Feedback<E::State>,
|
||||
E::State: HasSolutions + HasClientPerfMonitor + HasCorpus,
|
||||
Z: HasObjective<Objective = OF, State = E::State>,
|
||||
{
|
||||
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::<E, EM, OF, Z>(
|
||||
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<Objective = OF, State = S>,
|
||||
{
|
||||
#[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::<InProcessExecutor<'a, H, OT, S>, 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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user