Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support on_crash & on_timeout callbacks for libafl_qemu modules #2620

Merged
merged 8 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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