Skip to content

Commit

Permalink
Support on_crash & on_timeout callbacks for libafl_qemu modules (#2620)
Browse files Browse the repository at this point in the history
* support (unsafe) on_crash / on_timeout callbacks for modules

* use libc types in bindgen
  • Loading branch information
rmalmain authored Oct 21, 2024
1 parent f0da4d1 commit d96d833
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 143 deletions.
2 changes: 2 additions & 0 deletions libafl_qemu/libafl_qemu_build/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ pub fn generate(
.allowlist_function("qemu_main_loop")
.allowlist_function("qemu_cleanup")
.blocklist_function("main_loop_wait") // bindgen issue #1313
.blocklist_type("siginfo_t")
.raw_line("use libc::siginfo_t;")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));

// arch specific functions
Expand Down
40 changes: 4 additions & 36 deletions libafl_qemu/libafl_qemu_sys/src/bindings/x86_64_stub_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* 1.83.0-nightly */
/* qemu git hash: d6637939526f453c69f4c6bfe4635feb5dc5c0be */
/* 1.84.0-nightly */
/* qemu git hash: 805b14ffc44999952562e8f219d81c21a4fa50b9 */
/* automatically generated by rust-bindgen 0.70.1 */

use libc::siginfo_t;

#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage> {
Expand Down Expand Up @@ -516,15 +518,6 @@ impl ::std::fmt::Debug for sigval {
pub type __sigval_t = sigval;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct siginfo_t {
pub si_signo: ::std::os::raw::c_int,
pub si_errno: ::std::os::raw::c_int,
pub si_code: ::std::os::raw::c_int,
pub __pad0: ::std::os::raw::c_int,
pub _sifields: siginfo_t__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union siginfo_t__bindgen_ty_1 {
pub _pad: [::std::os::raw::c_int; 28usize],
pub _kill: siginfo_t__bindgen_ty_1__bindgen_ty_1,
Expand Down Expand Up @@ -827,31 +820,6 @@ impl ::std::fmt::Debug for siginfo_t__bindgen_ty_1 {
write!(f, "siginfo_t__bindgen_ty_1 {{ union }}")
}
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of siginfo_t"][::std::mem::size_of::<siginfo_t>() - 128usize];
["Alignment of siginfo_t"][::std::mem::align_of::<siginfo_t>() - 8usize];
["Offset of field: siginfo_t::si_signo"][::std::mem::offset_of!(siginfo_t, si_signo) - 0usize];
["Offset of field: siginfo_t::si_errno"][::std::mem::offset_of!(siginfo_t, si_errno) - 4usize];
["Offset of field: siginfo_t::si_code"][::std::mem::offset_of!(siginfo_t, si_code) - 8usize];
["Offset of field: siginfo_t::__pad0"][::std::mem::offset_of!(siginfo_t, __pad0) - 12usize];
["Offset of field: siginfo_t::_sifields"]
[::std::mem::offset_of!(siginfo_t, _sifields) - 16usize];
};
impl Default for siginfo_t {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
impl ::std::fmt::Debug for siginfo_t {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write ! (f , "siginfo_t {{ si_signo: {:?}, si_errno: {:?}, si_code: {:?}, __pad0: {:?}, _sifields: {:?} }}" , self . si_signo , self . si_errno , self . si_code , self . __pad0 , self . _sifields)
}
}
pub type guint8 = ::std::os::raw::c_uchar;
pub type gchar = ::std::os::raw::c_char;
pub type guint = ::std::os::raw::c_uint;
Expand Down
4 changes: 2 additions & 2 deletions libafl_qemu/runtime/libafl_qemu_stub_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* 1.83.0-nightly */
/* qemu git hash: d6637939526f453c69f4c6bfe4635feb5dc5c0be */
/* 1.84.0-nightly */
/* qemu git hash: 805b14ffc44999952562e8f219d81c21a4fa50b9 */
/* automatically generated by rust-bindgen 0.70.1 */

pub const LIBAFL_SYNC_EXIT_OPCODE: u32 = 1727150607;
Expand Down
69 changes: 47 additions & 22 deletions libafl_qemu/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ use libafl_bolts::{
use libafl_qemu_sys::libafl_exit_request_timeout;
#[cfg(emulation_mode = "usermode")]
use libafl_qemu_sys::libafl_qemu_handle_crash;
#[cfg(emulation_mode = "usermode")]
use libafl_qemu_sys::siginfo_t;
#[cfg(emulation_mode = "systemmode")]
use libc::siginfo_t;

#[cfg(emulation_mode = "usermode")]
Expand All @@ -60,17 +57,26 @@ where
///
/// This should be used as a crash handler, and nothing else.
#[cfg(emulation_mode = "usermode")]
unsafe fn inproc_qemu_crash_handler(
unsafe fn inproc_qemu_crash_handler<ET, S>(
signal: Signal,
info: &mut siginfo_t,
mut context: Option<&mut ucontext_t>,
_data: &mut InProcessExecutorHandlerData,
) {
) where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
{
let puc = match &mut context {
Some(v) => ptr::from_mut::<ucontext_t>(*v) as *mut c_void,
None => ptr::null_mut(),
};
libafl_qemu_handle_crash(signal as i32, ptr::from_mut::<siginfo_t>(info), puc);

// run modules' crash callback
if let Some(emulator_modules) = EmulatorModules::<ET, S>::emulator_modules_mut() {
emulator_modules.modules_mut().on_crash_all();
}

libafl_qemu_handle_crash(signal as i32, info, puc);
}

#[cfg(emulation_mode = "systemmode")]
Expand All @@ -79,25 +85,44 @@ 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.
#[cfg(emulation_mode = "systemmode")]
pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
pub unsafe fn inproc_qemu_timeout_handler<E, EM, ET, OF, S, Z>(
signal: Signal,
info: &mut siginfo_t,
context: Option<&mut ucontext_t>,
data: &mut InProcessExecutorHandlerData,
) where
E: HasObservers + HasInProcessHooks<E::State> + Executor<EM, Z>,
E::Observers: ObserversTuple<E::Input, E::State>,
E::State: HasExecutions + HasSolutions + HasCorpus,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
ET: EmulatorModuleTuple<S>,
OF: Feedback<EM, E::Input, E::Observers, E::State>,
E::State: HasExecutions + HasSolutions + HasCorpus,
S: State + Unpin,
Z: HasObjective<Objective = OF, State = E::State>,
<<E as UsesState>::State as HasSolutions>::Solutions: Corpus<Input = E::Input>, //delete me
<<<E as UsesState>::State as HasCorpus>::Corpus as Corpus>::Input: Clone, //delete me
{
if BREAK_ON_TMOUT.load(Ordering::Acquire) {
libafl_exit_request_timeout();
} else {
#[cfg(emulation_mode = "systemmode")]
{
if BREAK_ON_TMOUT.load(Ordering::Acquire) {
libafl_exit_request_timeout();
} else {
libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::<
E,
EM,
OF,
Z,
>(signal, info, context, data);
}
}

#[cfg(emulation_mode = "usermode")]
{
// run modules' crash callback
if let Some(emulator_modules) = EmulatorModules::<ET, S>::emulator_modules_mut() {
emulator_modules.modules_mut().on_timeout_all();
}

libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::<E, EM, OF, Z>(
signal, info, context, data,
);
Expand Down Expand Up @@ -153,7 +178,8 @@ where

#[cfg(emulation_mode = "usermode")]
{
inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler as *const c_void;
inner.inprocess_hooks_mut().crash_handler =
inproc_qemu_crash_handler::<ET, S> as *const c_void;

let handler = |emulator_modules: &mut EmulatorModules<ET, S>, host_sig| {
eprintln!("Crashed with signal {host_sig}");
Expand All @@ -175,15 +201,14 @@ where
}
}

#[cfg(emulation_mode = "systemmode")]
{
inner.inprocess_hooks_mut().timeout_handler = inproc_qemu_timeout_handler::<
StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, ED, ET, S, SM>>,
EM,
OF,
Z,
> as *const c_void;
}
inner.inprocess_hooks_mut().timeout_handler = inproc_qemu_timeout_handler::<
StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, ED, ET, S, SM>>,
EM,
ET,
OF,
S,
Z,
> as *const c_void;

Ok(Self {
inner,
Expand Down
Loading

0 comments on commit d96d833

Please sign in to comment.