Break on timeout in QEMU system mode (#1619)
* Break on timeout in QEMU system mode * fix * fix * fix
This commit is contained in:
parent
31f4669794
commit
47cd4dfea6
@ -18,3 +18,4 @@ codegen-units = 1
|
|||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
libafl_bolts = { path = "../../libafl_bolts/" }
|
libafl_bolts = { path = "../../libafl_bolts/" }
|
||||||
libafl_qemu = { path = "../../libafl_qemu/", features = ["arm", "systemmode"] }
|
libafl_qemu = { path = "../../libafl_qemu/", features = ["arm", "systemmode"] }
|
||||||
|
env_logger = "*"
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
int BREAKPOINT() {
|
int __attribute__ ((noinline)) BREAKPOINT() {
|
||||||
for (;;) {}
|
for (;;) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(unsigned int *Data, unsigned int Size) {
|
int LLVMFuzzerTestOneInput(unsigned int *Data, unsigned int Size) {
|
||||||
// if (Data[3] == 0) {while(1){}} // cause a timeout
|
if (Data[3] == 0) {while(1){}} // cause a timeout
|
||||||
for (int i = 0; i < Size; i++) {
|
for (int i = 0; i < Size; i++) {
|
||||||
// if (Data[i] > 0xFFd0 && Data[i] < 0xFFFF) {return 1;} // cause qemu to
|
// if (Data[i] > 0xFFd0 && Data[i] < 0xFFFF) {return 1;} // cause qemu to crash
|
||||||
// crash
|
|
||||||
for (int j = i + 1; j < Size; j++) {
|
for (int j = i + 1; j < Size; j++) {
|
||||||
if (Data[j] == 0) { continue; }
|
if (Data[j] == 0) { continue; }
|
||||||
if (Data[j] > Data[i]) {
|
if (Data[j] > Data[i]) {
|
||||||
|
@ -37,6 +37,8 @@ use libafl_qemu::{
|
|||||||
pub static mut MAX_INPUT_SIZE: usize = 50;
|
pub static mut MAX_INPUT_SIZE: usize = 50;
|
||||||
|
|
||||||
pub fn fuzz() {
|
pub fn fuzz() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
if let Ok(s) = env::var("FUZZ_SIZE") {
|
if let Ok(s) = env::var("FUZZ_SIZE") {
|
||||||
str::parse::<usize>(&s).expect("FUZZ_SIZE was not a number");
|
str::parse::<usize>(&s).expect("FUZZ_SIZE was not a number");
|
||||||
};
|
};
|
||||||
@ -193,7 +195,7 @@ pub fn fuzz() {
|
|||||||
let mut hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageHelper::default()));
|
let mut hooks = QemuHooks::new(&emu, tuple_list!(QemuEdgeCoverageHelper::default()));
|
||||||
|
|
||||||
// Create a QEMU in-process executor
|
// Create a QEMU in-process executor
|
||||||
let executor = QemuExecutor::new(
|
let mut executor = QemuExecutor::new(
|
||||||
&mut hooks,
|
&mut hooks,
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, time_observer),
|
tuple_list!(edges_observer, time_observer),
|
||||||
@ -203,6 +205,9 @@ pub fn fuzz() {
|
|||||||
)
|
)
|
||||||
.expect("Failed to create QemuExecutor");
|
.expect("Failed to create QemuExecutor");
|
||||||
|
|
||||||
|
// Instead of calling the timeout handler and restart the process, trigger a breakpoint ASAP
|
||||||
|
executor.break_on_timeout();
|
||||||
|
|
||||||
// Wrap the executor to keep track of the timeout
|
// Wrap the executor to keep track of the timeout
|
||||||
let mut executor = TimeoutExecutor::new(executor, timeout);
|
let mut executor = TimeoutExecutor::new(executor, timeout);
|
||||||
|
|
||||||
|
@ -845,7 +845,7 @@ pub fn generate_minibsod<W: Write>(
|
|||||||
writeln!(writer, "{:━^100}", " REGISTERS ")?;
|
writeln!(writer, "{:━^100}", " REGISTERS ")?;
|
||||||
dump_registers(writer, uctx)?;
|
dump_registers(writer, uctx)?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(writer, "Received signal {}", signal)?;
|
writeln!(writer, "Received signal {signal}")?;
|
||||||
}
|
}
|
||||||
writeln!(writer, "{:━^100}", " BACKTRACE ")?;
|
writeln!(writer, "{:━^100}", " BACKTRACE ")?;
|
||||||
writeln!(writer, "{:?}", backtrace::Backtrace::new())?;
|
writeln!(writer, "{:?}", backtrace::Backtrace::new())?;
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
//! A `QEMU`-based executor for binary-only instrumentation in `LibAFL`
|
//! A `QEMU`-based executor for binary-only instrumentation in `LibAFL`
|
||||||
#[cfg(emulation_mode = "usermode")]
|
use core::{
|
||||||
use core::ffi::c_void;
|
ffi::c_void,
|
||||||
use core::fmt::{self, Debug, Formatter};
|
fmt::{self, Debug, Formatter},
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
|
||||||
use libafl::executors::inprocess::InProcessExecutorHandlerData;
|
|
||||||
#[cfg(feature = "fork")]
|
#[cfg(feature = "fork")]
|
||||||
use libafl::{
|
use libafl::{
|
||||||
events::EventManager,
|
events::EventManager,
|
||||||
@ -13,7 +12,10 @@ use libafl::{
|
|||||||
};
|
};
|
||||||
use libafl::{
|
use libafl::{
|
||||||
events::{EventFirer, EventRestarter},
|
events::{EventFirer, EventRestarter},
|
||||||
executors::{inprocess::InProcessExecutor, Executor, ExitKind, HasObservers},
|
executors::{
|
||||||
|
inprocess::{InProcessExecutor, InProcessExecutorHandlerData},
|
||||||
|
Executor, ExitKind, HasObservers,
|
||||||
|
},
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
fuzzer::HasObjective,
|
fuzzer::HasObjective,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
@ -21,7 +23,6 @@ use libafl::{
|
|||||||
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState},
|
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
#[cfg(emulation_mode = "usermode")]
|
|
||||||
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Signal};
|
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Signal};
|
||||||
#[cfg(feature = "fork")]
|
#[cfg(feature = "fork")]
|
||||||
use libafl_bolts::shmem::ShMemProvider;
|
use libafl_bolts::shmem::ShMemProvider;
|
||||||
@ -74,7 +75,7 @@ pub unsafe extern "C" fn libafl_executor_reinstall_handlers() {
|
|||||||
pub unsafe fn inproc_qemu_crash_handler<E, EM, OF, Z>(
|
pub unsafe fn inproc_qemu_crash_handler<E, EM, OF, Z>(
|
||||||
signal: Signal,
|
signal: Signal,
|
||||||
info: &mut siginfo_t,
|
info: &mut siginfo_t,
|
||||||
context: &mut ucontext_t,
|
mut context: Option<&mut ucontext_t>,
|
||||||
data: &mut InProcessExecutorHandlerData,
|
data: &mut InProcessExecutorHandlerData,
|
||||||
) where
|
) where
|
||||||
E: Executor<EM, Z> + HasObservers,
|
E: Executor<EM, Z> + HasObservers,
|
||||||
@ -86,7 +87,11 @@ pub unsafe fn inproc_qemu_crash_handler<E, EM, OF, Z>(
|
|||||||
let real_crash = if USE_LIBAFL_CRASH_HANDLER {
|
let real_crash = if USE_LIBAFL_CRASH_HANDLER {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
libafl_qemu_handle_crash(signal as i32, info, context as *mut _ as *mut c_void) != 0
|
let puc = match &mut context {
|
||||||
|
Some(v) => (*v) as *mut ucontext_t as *mut c_void,
|
||||||
|
None => core::ptr::null_mut(),
|
||||||
|
};
|
||||||
|
libafl_qemu_handle_crash(signal as i32, info, puc) != 0
|
||||||
};
|
};
|
||||||
if real_crash {
|
if real_crash {
|
||||||
libafl::executors::inprocess::unix_signal_handler::inproc_crash_handler::<E, EM, OF, Z>(
|
libafl::executors::inprocess::unix_signal_handler::inproc_crash_handler::<E, EM, OF, Z>(
|
||||||
@ -95,6 +100,36 @@ pub unsafe fn inproc_qemu_crash_handler<E, EM, OF, Z>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
|
static mut BREAK_ON_TMOUT: bool = false;
|
||||||
|
|
||||||
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
|
extern "C" {
|
||||||
|
fn qemu_system_debug_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
|
pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
|
||||||
|
signal: Signal,
|
||||||
|
info: &mut siginfo_t,
|
||||||
|
context: Option<&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>,
|
||||||
|
{
|
||||||
|
if BREAK_ON_TMOUT {
|
||||||
|
qemu_system_debug_request();
|
||||||
|
} else {
|
||||||
|
libafl::executors::inprocess::unix_signal_handler::inproc_timeout_handler::<E, EM, OF, Z>(
|
||||||
|
signal, info, context, data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, H, OT, QT, S> QemuExecutor<'a, H, OT, QT, S>
|
impl<'a, H, OT, QT, S> QemuExecutor<'a, H, OT, QT, S>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input) -> ExitKind,
|
H: FnMut(&S::Input) -> ExitKind,
|
||||||
@ -116,31 +151,37 @@ where
|
|||||||
S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor,
|
S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor,
|
||||||
Z: HasObjective<Objective = OF, State = S>,
|
Z: HasObjective<Objective = OF, State = S>,
|
||||||
{
|
{
|
||||||
|
let mut inner = InProcessExecutor::new(harness_fn, observers, fuzzer, state, event_mgr)?;
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
{
|
{
|
||||||
let mut inner =
|
|
||||||
InProcessExecutor::new(harness_fn, observers, fuzzer, state, event_mgr)?;
|
|
||||||
inner.handlers_mut().crash_handler =
|
inner.handlers_mut().crash_handler =
|
||||||
inproc_qemu_crash_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
|
inproc_qemu_crash_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
|
||||||
as *const c_void;
|
as *const c_void;
|
||||||
|
}
|
||||||
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
|
{
|
||||||
|
inner.handlers_mut().timeout_handler =
|
||||||
|
inproc_qemu_timeout_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
|
||||||
|
as *const c_void;
|
||||||
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
first_exec: true,
|
first_exec: true,
|
||||||
hooks,
|
hooks,
|
||||||
inner,
|
inner,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
#[cfg(not(emulation_mode = "usermode"))]
|
|
||||||
Ok(Self {
|
|
||||||
first_exec: true,
|
|
||||||
hooks,
|
|
||||||
inner: InProcessExecutor::new(harness_fn, observers, fuzzer, state, event_mgr)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inner(&self) -> &InProcessExecutor<'a, H, OT, S> {
|
pub fn inner(&self) -> &InProcessExecutor<'a, H, OT, S> {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
|
pub fn break_on_timeout(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
BREAK_ON_TMOUT = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn inner_mut(&mut self) -> &mut InProcessExecutor<'a, H, OT, S> {
|
pub fn inner_mut(&mut self) -> &mut InProcessExecutor<'a, H, OT, S> {
|
||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user