Use Unix timer_* API instead of setitimer (#510)
* fix linter errors for armv7 (docs) * introduce HasOnCrashReset trait; use timer_* API instead of setitimer for unix TimeoutExecutor * fixes: PR #469 annotations and CI issues * reintroduce setitimer for apple as macOS does not feature the POSIX timer API * more macos and windows CI fixes * more macos and windows CI fixes cont. * HasOnCrashReset -> HasPostRunReset * remove drop impl for Windows TimeoutExecutor * adjust target cfgs for timeout stuff (android also did not work) * add call to inner post_run_reset * remove HasPostRunReset in favor of making it a trait fn of Executor * add post_run_reset's to CombinedExecutor * clippy: addr_of! instead of raw pointer casts * link librt in libafl_cc (required by timer_* API) * minor fixes and cleanup * remove unused import for targets other than linux * fix win * merge * fix Co-authored-by: pr0me <g33sus@gmail.com>
This commit is contained in:
parent
9dfc6aa404
commit
c61fed6ca9
@ -17,42 +17,72 @@ use std::ffi::CString;
|
|||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
pub use libc::c_ulong;
|
pub use libc::c_ulong;
|
||||||
|
|
||||||
|
/// ARMv7-specific representation of a saved context
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
|
#[derive(Debug)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct mcontext_t {
|
pub struct mcontext_t {
|
||||||
|
/// Signal Number
|
||||||
pub trap_no: c_ulong,
|
pub trap_no: c_ulong,
|
||||||
|
/// Error Code
|
||||||
pub error_code: c_ulong,
|
pub error_code: c_ulong,
|
||||||
|
/// Old signal mask
|
||||||
pub oldmask: c_ulong,
|
pub oldmask: c_ulong,
|
||||||
|
/// GPR R0
|
||||||
pub arm_r0: c_ulong,
|
pub arm_r0: c_ulong,
|
||||||
|
/// GPR R1
|
||||||
pub arm_r1: c_ulong,
|
pub arm_r1: c_ulong,
|
||||||
|
/// GPR R2
|
||||||
pub arm_r2: c_ulong,
|
pub arm_r2: c_ulong,
|
||||||
|
/// GPR R3
|
||||||
pub arm_r3: c_ulong,
|
pub arm_r3: c_ulong,
|
||||||
|
/// GPR R4
|
||||||
pub arm_r4: c_ulong,
|
pub arm_r4: c_ulong,
|
||||||
|
/// GPR R5
|
||||||
pub arm_r5: c_ulong,
|
pub arm_r5: c_ulong,
|
||||||
|
/// GPR R6
|
||||||
pub arm_r6: c_ulong,
|
pub arm_r6: c_ulong,
|
||||||
|
/// GPR R7
|
||||||
pub arm_r7: c_ulong,
|
pub arm_r7: c_ulong,
|
||||||
|
/// GPR R8
|
||||||
pub arm_r8: c_ulong,
|
pub arm_r8: c_ulong,
|
||||||
|
/// GPR R9
|
||||||
pub arm_r9: c_ulong,
|
pub arm_r9: c_ulong,
|
||||||
|
/// GPR R10
|
||||||
pub arm_r10: c_ulong,
|
pub arm_r10: c_ulong,
|
||||||
|
/// Frame Pointer
|
||||||
pub arm_fp: c_ulong,
|
pub arm_fp: c_ulong,
|
||||||
|
/// Intra-Procedure Scratch Register
|
||||||
pub arm_ip: c_ulong,
|
pub arm_ip: c_ulong,
|
||||||
|
/// Stack Pointer
|
||||||
pub arm_sp: c_ulong,
|
pub arm_sp: c_ulong,
|
||||||
|
/// Link Register
|
||||||
pub arm_lr: c_ulong,
|
pub arm_lr: c_ulong,
|
||||||
|
/// Program Counter
|
||||||
pub arm_pc: c_ulong,
|
pub arm_pc: c_ulong,
|
||||||
|
/// Current Program Status Register
|
||||||
pub arm_cpsr: c_ulong,
|
pub arm_cpsr: c_ulong,
|
||||||
|
/// Fault Address
|
||||||
pub fault_address: c_ulong,
|
pub fault_address: c_ulong,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// User Context Struct
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
|
#[derive(Debug)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ucontext_t {
|
pub struct ucontext_t {
|
||||||
|
/// Flags
|
||||||
pub uc_flags: u32,
|
pub uc_flags: u32,
|
||||||
|
/// Pointer to the context that will be resumed when this context returns
|
||||||
pub uc_link: *mut ucontext_t,
|
pub uc_link: *mut ucontext_t,
|
||||||
|
/// Stack used by this context
|
||||||
pub uc_stack: stack_t,
|
pub uc_stack: stack_t,
|
||||||
|
/// Machine-specific representation of the saved context
|
||||||
pub uc_mcontext: mcontext_t,
|
pub uc_mcontext: mcontext_t,
|
||||||
pub uc_sigmask: nix::sys::signal::SigSet,
|
/// Set of signals that are blocked when this context is active
|
||||||
|
pub uc_sigmask: libc::sigset_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "arm"))]
|
#[cfg(not(target_arch = "arm"))]
|
||||||
|
@ -1118,7 +1118,6 @@ pub mod win32_shmem {
|
|||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
ptr, slice,
|
ptr, slice,
|
||||||
};
|
};
|
||||||
use std::convert::TryInto;
|
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const INVALID_HANDLE_VALUE: isize = -1;
|
const INVALID_HANDLE_VALUE: isize = -1;
|
||||||
|
@ -50,7 +50,10 @@ where
|
|||||||
mgr: &mut EM,
|
mgr: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
self.primary.run_target(fuzzer, state, mgr, input)
|
let ret = self.primary.run_target(fuzzer, state, mgr, input);
|
||||||
|
self.primary.post_run_reset();
|
||||||
|
self.secondary.post_run_reset();
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ impl InProcessHandlers {
|
|||||||
pub fn new<E, EM, I, OF, OT, S, Z, H>() -> Result<Self, Error>
|
pub fn new<E, EM, I, OF, OT, S, Z, H>() -> Result<Self, Error>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
E: HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
EM: EventFirer<I> + EventRestarter<S>,
|
EM: EventFirer<I> + EventRestarter<S>,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
@ -628,8 +628,7 @@ mod unix_signal_handler {
|
|||||||
events::{Event, EventFirer, EventRestarter},
|
events::{Event, EventFirer, EventRestarter},
|
||||||
executors::{
|
executors::{
|
||||||
inprocess::{InProcessExecutorHandlerData, GLOBAL_STATE},
|
inprocess::{InProcessExecutorHandlerData, GLOBAL_STATE},
|
||||||
timeout::unix_remove_timeout,
|
Executor, ExitKind, HasObservers,
|
||||||
ExitKind, HasObservers,
|
|
||||||
},
|
},
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
fuzzer::HasObjective,
|
fuzzer::HasObjective,
|
||||||
@ -775,7 +774,7 @@ mod unix_signal_handler {
|
|||||||
_context: &mut ucontext_t,
|
_context: &mut ucontext_t,
|
||||||
data: &mut InProcessExecutorHandlerData,
|
data: &mut InProcessExecutorHandlerData,
|
||||||
) where
|
) where
|
||||||
E: HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
EM: EventFirer<I> + EventRestarter<S>,
|
EM: EventFirer<I> + EventRestarter<S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
@ -783,8 +782,6 @@ mod unix_signal_handler {
|
|||||||
I: Input,
|
I: Input,
|
||||||
Z: HasObjective<I, OF, S>,
|
Z: HasObjective<I, OF, S>,
|
||||||
{
|
{
|
||||||
unix_remove_timeout();
|
|
||||||
|
|
||||||
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
|
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
|
||||||
let _context = &mut *(((_context as *mut _ as *mut libc::c_void as usize) + 128)
|
let _context = &mut *(((_context as *mut _ as *mut libc::c_void as usize) + 128)
|
||||||
as *mut libc::c_void as *mut ucontext_t);
|
as *mut libc::c_void as *mut ucontext_t);
|
||||||
@ -825,11 +822,14 @@ mod unix_signal_handler {
|
|||||||
|
|
||||||
// TODO tell the parent to not restart
|
// TODO tell the parent to not restart
|
||||||
} else {
|
} else {
|
||||||
|
let executor = (data.executor_ptr as *mut E).as_mut().unwrap();
|
||||||
|
// disarms timeout in case of TimeoutExecutor
|
||||||
|
executor.post_run_reset();
|
||||||
let state = (data.state_ptr as *mut S).as_mut().unwrap();
|
let state = (data.state_ptr as *mut S).as_mut().unwrap();
|
||||||
let event_mgr = (data.event_mgr_ptr as *mut EM).as_mut().unwrap();
|
let event_mgr = (data.event_mgr_ptr as *mut EM).as_mut().unwrap();
|
||||||
let fuzzer = (data.fuzzer_ptr as *mut Z).as_mut().unwrap();
|
let fuzzer = (data.fuzzer_ptr as *mut Z).as_mut().unwrap();
|
||||||
let executor = (data.executor_ptr as *mut E).as_mut().unwrap();
|
|
||||||
let observers = executor.observers_mut();
|
let observers = executor.observers_mut();
|
||||||
|
|
||||||
let input = (data.current_input_ptr as *const I).as_ref().unwrap();
|
let input = (data.current_input_ptr as *const I).as_ref().unwrap();
|
||||||
data.current_input_ptr = ptr::null();
|
data.current_input_ptr = ptr::null();
|
||||||
|
|
||||||
@ -908,8 +908,7 @@ mod windows_exception_handler {
|
|||||||
events::{Event, EventFirer, EventRestarter},
|
events::{Event, EventFirer, EventRestarter},
|
||||||
executors::{
|
executors::{
|
||||||
inprocess::{InProcessExecutorHandlerData, GLOBAL_STATE},
|
inprocess::{InProcessExecutorHandlerData, GLOBAL_STATE},
|
||||||
timeout::windows_delete_timer_queue,
|
Executor, ExitKind, HasObservers,
|
||||||
ExitKind, HasObservers,
|
|
||||||
},
|
},
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
fuzzer::HasObjective,
|
fuzzer::HasObjective,
|
||||||
@ -1053,7 +1052,7 @@ mod windows_exception_handler {
|
|||||||
exception_pointers: *mut EXCEPTION_POINTERS,
|
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||||
data: &mut InProcessExecutorHandlerData,
|
data: &mut InProcessExecutorHandlerData,
|
||||||
) where
|
) where
|
||||||
E: HasObservers<I, OT, S>,
|
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||||
EM: EventFirer<I> + EventRestarter<S>,
|
EM: EventFirer<I> + EventRestarter<S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
OF: Feedback<I, S>,
|
OF: Feedback<I, S>,
|
||||||
@ -1062,7 +1061,7 @@ mod windows_exception_handler {
|
|||||||
Z: HasObjective<I, OF, S>,
|
Z: HasObjective<I, OF, S>,
|
||||||
{
|
{
|
||||||
// Have we set a timer_before?
|
// Have we set a timer_before?
|
||||||
if let Some(x) =
|
if let Some(_) =
|
||||||
(data.tp_timer as *mut windows::Win32::System::Threading::TP_TIMER).as_mut()
|
(data.tp_timer as *mut windows::Win32::System::Threading::TP_TIMER).as_mut()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -1077,9 +1076,6 @@ mod windows_exception_handler {
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
LeaveCriticalSection(data.critical as *mut RTL_CRITICAL_SECTION);
|
LeaveCriticalSection(data.critical as *mut RTL_CRITICAL_SECTION);
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
windows_delete_timer_queue(x);
|
|
||||||
data.tp_timer = ptr::null_mut();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let code = ExceptionCode::try_from(
|
let code = ExceptionCode::try_from(
|
||||||
@ -1124,10 +1120,16 @@ mod windows_exception_handler {
|
|||||||
|
|
||||||
// TODO tell the parent to not restart
|
// TODO tell the parent to not restart
|
||||||
} else {
|
} else {
|
||||||
|
let executor = (data.executor_ptr as *mut E).as_mut().unwrap();
|
||||||
|
// reset timer
|
||||||
|
if !data.tp_timer.is_null() {
|
||||||
|
executor.post_run_reset();
|
||||||
|
data.tp_timer = ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
let state = (data.state_ptr as *mut S).as_mut().unwrap();
|
let state = (data.state_ptr as *mut S).as_mut().unwrap();
|
||||||
let event_mgr = (data.event_mgr_ptr as *mut EM).as_mut().unwrap();
|
let event_mgr = (data.event_mgr_ptr as *mut EM).as_mut().unwrap();
|
||||||
let fuzzer = (data.fuzzer_ptr as *mut Z).as_mut().unwrap();
|
let fuzzer = (data.fuzzer_ptr as *mut Z).as_mut().unwrap();
|
||||||
let executor = (data.executor_ptr as *const E).as_ref().unwrap();
|
|
||||||
let observers = executor.observers();
|
let observers = executor.observers();
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
@ -95,6 +95,10 @@ where
|
|||||||
{
|
{
|
||||||
WithObservers::new(self, observers)
|
WithObservers::new(self, observers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Custom Reset Handler, e.g., to reset timers
|
||||||
|
#[inline]
|
||||||
|
fn post_run_reset(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple executor that does nothing.
|
/// A simple executor that does nothing.
|
||||||
|
@ -18,16 +18,20 @@ use crate::executors::inprocess::{HasInProcessHandlers, GLOBAL_STATE};
|
|||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use core::{mem::zeroed, ptr::null_mut};
|
use core::{mem::zeroed, ptr::null_mut};
|
||||||
#[cfg(unix)]
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use core::ptr::{addr_of, addr_of_mut};
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
#[cfg(all(windows, feature = "std"))]
|
#[cfg(all(windows, feature = "std"))]
|
||||||
use windows::Win32::{
|
use windows::Win32::{
|
||||||
Foundation::FILETIME,
|
Foundation::FILETIME,
|
||||||
System::Threading::{
|
System::Threading::{
|
||||||
CloseThreadpoolTimer, CreateThreadpoolTimer, EnterCriticalSection,
|
CreateThreadpoolTimer, EnterCriticalSection, InitializeCriticalSection,
|
||||||
InitializeCriticalSection, LeaveCriticalSection, SetThreadpoolTimer, RTL_CRITICAL_SECTION,
|
LeaveCriticalSection, SetThreadpoolTimer, RTL_CRITICAL_SECTION, TP_CALLBACK_ENVIRON_V3,
|
||||||
TP_CALLBACK_ENVIRON_V3, TP_CALLBACK_INSTANCE, TP_TIMER,
|
TP_CALLBACK_INSTANCE, TP_TIMER,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,13 +42,13 @@ use core::{ffi::c_void, ptr::write_volatile};
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
struct Timeval {
|
struct Timeval {
|
||||||
pub tv_sec: i64,
|
pub tv_sec: i64,
|
||||||
pub tv_usec: i64,
|
pub tv_usec: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
impl Debug for Timeval {
|
impl Debug for Timeval {
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
@ -59,42 +63,29 @@ impl Debug for Timeval {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Itimerval {
|
struct Itimerval {
|
||||||
pub it_interval: Timeval,
|
pub it_interval: Timeval,
|
||||||
pub it_value: Timeval,
|
pub it_value: Timeval,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
|
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
const ITIMER_REAL: c_int = 0;
|
const ITIMER_REAL: c_int = 0;
|
||||||
|
|
||||||
/// Reset and remove the timeout
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub(crate) fn unix_remove_timeout() {
|
|
||||||
unsafe {
|
|
||||||
let mut itimerval_zero: Itimerval = zeroed();
|
|
||||||
setitimer(ITIMER_REAL, &mut itimerval_zero, null_mut());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes this timer queue
|
|
||||||
/// # Safety
|
|
||||||
/// Will dereference the given `tp_timer` pointer, unchecked.
|
|
||||||
#[cfg(all(windows, feature = "std"))]
|
|
||||||
pub(crate) unsafe fn windows_delete_timer_queue(tp_timer: *mut TP_TIMER) {
|
|
||||||
CloseThreadpoolTimer(tp_timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The timeout excutor is a wrapper that sets a timeout before each run
|
/// The timeout excutor is a wrapper that sets a timeout before each run
|
||||||
pub struct TimeoutExecutor<E> {
|
pub struct TimeoutExecutor<E> {
|
||||||
executor: E,
|
executor: E,
|
||||||
#[cfg(unix)]
|
#[cfg(target_os = "linux")]
|
||||||
|
itimerspec: libc::itimerspec,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
timerid: libc::timer_t,
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
itimerval: Itimerval,
|
itimerval: Itimerval,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
milli_sec: i64,
|
milli_sec: i64,
|
||||||
@ -113,7 +104,19 @@ impl<E: Debug> Debug for TimeoutExecutor<E> {
|
|||||||
.finish_non_exhaustive()
|
.finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(target_os = "linux")]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("TimeoutExecutor")
|
||||||
|
.field("executor", &self.executor)
|
||||||
|
.field(
|
||||||
|
"milli_sec",
|
||||||
|
&(&self.itimerspec.it_value.tv_sec * 1000
|
||||||
|
+ &self.itimerspec.it_value.tv_nsec / 1000 / 1000),
|
||||||
|
)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("TimeoutExecutor")
|
f.debug_struct("TimeoutExecutor")
|
||||||
.field("executor", &self.executor)
|
.field("executor", &self.executor)
|
||||||
@ -130,7 +133,56 @@ type PTP_TIMER_CALLBACK = unsafe extern "system" fn(
|
|||||||
param2: *mut TP_TIMER,
|
param2: *mut TP_TIMER,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(target_os = "linux")]
|
||||||
|
impl<E> TimeoutExecutor<E> {
|
||||||
|
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
||||||
|
/// This should usually be used for `InProcess` fuzzing.
|
||||||
|
pub fn new(executor: E, exec_tmout: Duration) -> Self {
|
||||||
|
let milli_sec = exec_tmout.as_millis();
|
||||||
|
let it_value = libc::timespec {
|
||||||
|
tv_sec: (milli_sec / 1000) as _,
|
||||||
|
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
||||||
|
};
|
||||||
|
let it_interval = libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
};
|
||||||
|
let itimerspec = libc::itimerspec {
|
||||||
|
it_interval,
|
||||||
|
it_value,
|
||||||
|
};
|
||||||
|
let mut timerid: libc::timer_t = null_mut();
|
||||||
|
unsafe {
|
||||||
|
// creates a new per-process interval timer
|
||||||
|
libc::timer_create(libc::CLOCK_MONOTONIC, null_mut(), addr_of_mut!(timerid));
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
executor,
|
||||||
|
itimerspec,
|
||||||
|
timerid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the timeout for this executor
|
||||||
|
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
||||||
|
let milli_sec = exec_tmout.as_millis();
|
||||||
|
let it_value = libc::timespec {
|
||||||
|
tv_sec: (milli_sec / 1000) as _,
|
||||||
|
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
||||||
|
};
|
||||||
|
let it_interval = libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
};
|
||||||
|
let itimerspec = libc::itimerspec {
|
||||||
|
it_interval,
|
||||||
|
it_value,
|
||||||
|
};
|
||||||
|
self.itimerspec = itimerspec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
impl<E> TimeoutExecutor<E> {
|
impl<E> TimeoutExecutor<E> {
|
||||||
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
||||||
/// This should usually be used for `InProcess` fuzzing.
|
/// This should usually be used for `InProcess` fuzzing.
|
||||||
@ -153,6 +205,24 @@ impl<E> TimeoutExecutor<E> {
|
|||||||
itimerval,
|
itimerval,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the timeout for this executor
|
||||||
|
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
||||||
|
let milli_sec = exec_tmout.as_millis();
|
||||||
|
let it_value = Timeval {
|
||||||
|
tv_sec: (milli_sec / 1000) as i64,
|
||||||
|
tv_usec: (milli_sec % 1000) as i64,
|
||||||
|
};
|
||||||
|
let it_interval = Timeval {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_usec: 0,
|
||||||
|
};
|
||||||
|
let itimerval = Itimerval {
|
||||||
|
it_interval,
|
||||||
|
it_value,
|
||||||
|
};
|
||||||
|
self.itimerval = itimerval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -183,25 +253,6 @@ impl<E: HasInProcessHandlers> TimeoutExecutor<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the timeout for this executor
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
|
||||||
let milli_sec = exec_tmout.as_millis();
|
|
||||||
let it_value = Timeval {
|
|
||||||
tv_sec: (milli_sec / 1000) as i64,
|
|
||||||
tv_usec: (milli_sec % 1000) as i64,
|
|
||||||
};
|
|
||||||
let it_interval = Timeval {
|
|
||||||
tv_sec: 0,
|
|
||||||
tv_usec: 0,
|
|
||||||
};
|
|
||||||
let itimerval = Itimerval {
|
|
||||||
it_interval,
|
|
||||||
it_value,
|
|
||||||
};
|
|
||||||
self.itimerval = itimerval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the timeout for this executor
|
/// Set the timeout for this executor
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
||||||
@ -212,15 +263,6 @@ impl<E: HasInProcessHandlers> TimeoutExecutor<E> {
|
|||||||
pub fn inner(&mut self) -> &mut E {
|
pub fn inner(&mut self) -> &mut E {
|
||||||
&mut self.executor
|
&mut self.executor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the timeout for this executor
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn windows_reset_timeout(&self) -> Result<(), Error> {
|
|
||||||
unsafe {
|
|
||||||
SetThreadpoolTimer(self.tp_timer, core::ptr::null(), 0, 0);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -277,13 +319,54 @@ where
|
|||||||
|
|
||||||
write_volatile(&mut data.timeout_input_ptr, core::ptr::null_mut());
|
write_volatile(&mut data.timeout_input_ptr, core::ptr::null_mut());
|
||||||
|
|
||||||
self.windows_reset_timeout()?;
|
self.post_run_reset();
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes this timer queue
|
||||||
|
/// # Safety
|
||||||
|
/// Will dereference the given `tp_timer` pointer, unchecked.
|
||||||
|
fn post_run_reset(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
SetThreadpoolTimer(self.tp_timer, core::ptr::null(), 0, 0);
|
||||||
|
}
|
||||||
|
self.executor.post_run_reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(target_os = "linux")]
|
||||||
|
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E>
|
||||||
|
where
|
||||||
|
E: Executor<EM, I, S, Z>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
fn run_target(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
) -> Result<ExitKind, Error> {
|
||||||
|
unsafe {
|
||||||
|
libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut());
|
||||||
|
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
||||||
|
// reset timer
|
||||||
|
self.post_run_reset();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_run_reset(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let disarmed: libc::itimerspec = zeroed();
|
||||||
|
libc::timer_settime(self.timerid, 0, addr_of!(disarmed), null_mut());
|
||||||
|
}
|
||||||
|
self.executor.post_run_reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E>
|
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E>
|
||||||
where
|
where
|
||||||
E: Executor<EM, I, S, Z>,
|
E: Executor<EM, I, S, Z>,
|
||||||
@ -296,14 +379,21 @@ where
|
|||||||
mgr: &mut EM,
|
mgr: &mut EM,
|
||||||
input: &I,
|
input: &I,
|
||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
#[cfg(unix)]
|
|
||||||
unsafe {
|
unsafe {
|
||||||
setitimer(ITIMER_REAL, &mut self.itimerval, null_mut());
|
setitimer(ITIMER_REAL, &mut self.itimerval, null_mut());
|
||||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
||||||
unix_remove_timeout();
|
self.post_run_reset();
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn post_run_reset(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let mut itimerval_zero: Itimerval = zeroed();
|
||||||
|
setitimer(ITIMER_REAL, &mut itimerval_zero, null_mut());
|
||||||
|
}
|
||||||
|
self.executor.post_run_reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, I, OT, S> HasObservers<I, OT, S> for TimeoutExecutor<E>
|
impl<E, I, OT, S> HasObservers<I, OT, S> for TimeoutExecutor<E>
|
||||||
@ -321,12 +411,3 @@ where
|
|||||||
self.executor.observers_mut()
|
self.executor.observers_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
impl<E> Drop for TimeoutExecutor<E> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
windows_delete_timer_queue(self.tp_timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -154,6 +154,11 @@ impl CompilerWrapper for ClangWrapper {
|
|||||||
new_args.push("-lBcrypt".into());
|
new_args.push("-lBcrypt".into());
|
||||||
new_args.push("-lAdvapi32".into());
|
new_args.push("-lAdvapi32".into());
|
||||||
}
|
}
|
||||||
|
// required by timer API (timer_create, timer_settime)
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
if linking {
|
||||||
|
new_args.push("-lrt".into());
|
||||||
|
}
|
||||||
// MacOS has odd linker behavior sometimes
|
// MacOS has odd linker behavior sometimes
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
if linking {
|
if linking {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user