commit
48791ddb75
@ -63,7 +63,8 @@ nix = "0.20.0"
|
|||||||
uds = "0.2.3"
|
uds = "0.2.3"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows = "0.3.1"
|
windows = "0.4.0"
|
||||||
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.build-dependencies]
|
[target.'cfg(windows)'.build-dependencies]
|
||||||
windows = "0.3.1"
|
windows = "0.4.0"
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
windows::build!(
|
windows::build!(
|
||||||
windows::win32::system_services::HANDLE,
|
windows::win32::system_services::{HANDLE, BOOL, PAGE_TYPE, PSTR, ExitProcess},
|
||||||
windows::win32::windows_programming::CloseHandle,
|
windows::win32::windows_programming::CloseHandle,
|
||||||
// API needed for the shared memory
|
// API needed for the shared memory
|
||||||
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
|
windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile},
|
||||||
|
windows::win32::debug::{SetUnhandledExceptionFilter, EXCEPTION_POINTERS, EXCEPTION_RECORD, LPTOP_LEVEL_EXCEPTION_FILTER}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub mod unix_signals;
|
pub mod unix_signals;
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub mod windows_exceptions;
|
||||||
|
332
libafl/src/bolts/os/windows_exceptions.rs
Normal file
332
libafl/src/bolts/os/windows_exceptions.rs
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
pub use crate::bolts::bindings::windows::win32::debug::EXCEPTION_POINTERS;
|
||||||
|
|
||||||
|
use crate::{bolts::bindings::windows::win32::debug::SetUnhandledExceptionFilter, Error};
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::{
|
||||||
|
cell::UnsafeCell,
|
||||||
|
convert::TryFrom,
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
|
ptr::write_volatile,
|
||||||
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
|
};
|
||||||
|
use std::os::raw::{c_long, c_void};
|
||||||
|
|
||||||
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
|
|
||||||
|
const EXCEPTION_CONTINUE_EXECUTION: c_long = -1;
|
||||||
|
//const EXCEPTION_CONTINUE_SEARCH: c_long = 0;
|
||||||
|
const EXCEPTION_EXECUTE_HANDLER: c_long = 1;
|
||||||
|
|
||||||
|
// From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611
|
||||||
|
pub const STATUS_WAIT_0: u32 = 0x00000000;
|
||||||
|
pub const STATUS_ABANDONED_WAIT_0: u32 = 0x00000080;
|
||||||
|
pub const STATUS_USER_APC: u32 = 0x000000C0;
|
||||||
|
pub const STATUS_TIMEOUT: u32 = 0x00000102;
|
||||||
|
pub const STATUS_PENDING: u32 = 0x00000103;
|
||||||
|
pub const STATUS_SEGMENT_NOTIFICATION: u32 = 0x40000005;
|
||||||
|
pub const STATUS_FATAL_APP_EXIT: u32 = 0x40000015;
|
||||||
|
pub const STATUS_GUARD_PAGE_VIOLATION: u32 = 0x80000001;
|
||||||
|
pub const STATUS_DATATYPE_MISALIGNMENT: u32 = 0x80000002;
|
||||||
|
pub const STATUS_BREAKPOINT: u32 = 0x80000003;
|
||||||
|
pub const STATUS_SINGLE_STEP: u32 = 0x80000004;
|
||||||
|
pub const STATUS_LONGJUMP: u32 = 0x80000026;
|
||||||
|
pub const STATUS_UNWIND_CONSOLIDATE: u32 = 0x80000029;
|
||||||
|
pub const STATUS_ACCESS_VIOLATION: u32 = 0xC0000005;
|
||||||
|
pub const STATUS_IN_PAGE_ERROR: u32 = 0xC0000006;
|
||||||
|
pub const STATUS_INVALID_HANDLE: u32 = 0xC0000008;
|
||||||
|
pub const STATUS_NO_MEMORY: u32 = 0xC0000017;
|
||||||
|
pub const STATUS_ILLEGAL_INSTRUCTION: u32 = 0xC000001D;
|
||||||
|
pub const STATUS_NONCONTINUABLE_EXCEPTION: u32 = 0xC0000025;
|
||||||
|
pub const STATUS_INVALID_DISPOSITION: u32 = 0xC0000026;
|
||||||
|
pub const STATUS_ARRAY_BOUNDS_EXCEEDED: u32 = 0xC000008C;
|
||||||
|
pub const STATUS_FLOAT_DENORMAL_OPERAND: u32 = 0xC000008D;
|
||||||
|
pub const STATUS_FLOAT_DIVIDE_BY_ZERO: u32 = 0xC000008E;
|
||||||
|
pub const STATUS_FLOAT_INEXACT_RESULT: u32 = 0xC000008F;
|
||||||
|
pub const STATUS_FLOAT_INVALID_OPERATION: u32 = 0xC0000090;
|
||||||
|
pub const STATUS_FLOAT_OVERFLOW: u32 = 0xC0000091;
|
||||||
|
pub const STATUS_FLOAT_STACK_CHECK: u32 = 0xC0000092;
|
||||||
|
pub const STATUS_FLOAT_UNDERFLOW: u32 = 0xC0000093;
|
||||||
|
pub const STATUS_INTEGER_DIVIDE_BY_ZERO: u32 = 0xC0000094;
|
||||||
|
pub const STATUS_INTEGER_OVERFLOW: u32 = 0xC0000095;
|
||||||
|
pub const STATUS_PRIVILEGED_INSTRUCTION: u32 = 0xC0000096;
|
||||||
|
pub const STATUS_STACK_OVERFLOW: u32 = 0xC00000FD;
|
||||||
|
pub const STATUS_DLL_NOT_FOUND: u32 = 0xC0000135;
|
||||||
|
pub const STATUS_ORDINAL_NOT_FOUND: u32 = 0xC0000138;
|
||||||
|
pub const STATUS_ENTRYPOINT_NOT_FOUND: u32 = 0xC0000139;
|
||||||
|
pub const STATUS_CONTROL_C_EXIT: u32 = 0xC000013A;
|
||||||
|
pub const STATUS_DLL_INIT_FAILED: u32 = 0xC0000142;
|
||||||
|
pub const STATUS_FLOAT_MULTIPLE_FAULTS: u32 = 0xC00002B4;
|
||||||
|
pub const STATUS_FLOAT_MULTIPLE_TRAPS: u32 = 0xC00002B5;
|
||||||
|
pub const STATUS_REG_NAT_CONSUMPTION: u32 = 0xC00002C9;
|
||||||
|
pub const STATUS_HEAP_CORRUPTION: u32 = 0xC0000374;
|
||||||
|
pub const STATUS_STACK_BUFFER_OVERRUN: u32 = 0xC0000409;
|
||||||
|
pub const STATUS_INVALID_CRUNTIME_PARAMETER: u32 = 0xC0000417;
|
||||||
|
pub const STATUS_ASSERTION_FAILURE: u32 = 0xC0000420;
|
||||||
|
pub const STATUS_SXS_EARLY_DEACTIVATION: u32 = 0xC015000F;
|
||||||
|
pub const STATUS_SXS_INVALID_DEACTIVATION: u32 = 0xC0150010;
|
||||||
|
|
||||||
|
#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum ExceptionCode {
|
||||||
|
// From https://docs.microsoft.com/en-us/windows/win32/debug/getexceptioncode
|
||||||
|
AccessViolation = STATUS_ACCESS_VIOLATION,
|
||||||
|
ArrayBoundsExceeded = STATUS_ARRAY_BOUNDS_EXCEEDED,
|
||||||
|
Breakpoint = STATUS_BREAKPOINT,
|
||||||
|
DatatypeMisalignment = STATUS_DATATYPE_MISALIGNMENT,
|
||||||
|
FltDenormalOperand = STATUS_FLOAT_DENORMAL_OPERAND,
|
||||||
|
FltDivideByZero = STATUS_FLOAT_DIVIDE_BY_ZERO,
|
||||||
|
FltInexactResult = STATUS_FLOAT_INEXACT_RESULT,
|
||||||
|
FltInvalidOperation = STATUS_FLOAT_INVALID_OPERATION,
|
||||||
|
FltOverflow = STATUS_FLOAT_OVERFLOW,
|
||||||
|
FltStackCheck = STATUS_FLOAT_STACK_CHECK,
|
||||||
|
FltUnderflow = STATUS_FLOAT_UNDERFLOW,
|
||||||
|
GuardPageViolation = STATUS_GUARD_PAGE_VIOLATION,
|
||||||
|
IllegalInstruction = STATUS_ILLEGAL_INSTRUCTION,
|
||||||
|
InPageError = STATUS_IN_PAGE_ERROR,
|
||||||
|
IntegerDivideByZero = STATUS_INTEGER_DIVIDE_BY_ZERO,
|
||||||
|
IntegerOverflow = STATUS_INTEGER_OVERFLOW,
|
||||||
|
InvalidDisposition = STATUS_INVALID_DISPOSITION,
|
||||||
|
InvalidHandle = STATUS_INVALID_HANDLE,
|
||||||
|
NoncontinuableException = STATUS_NONCONTINUABLE_EXCEPTION,
|
||||||
|
PrivilegedInstruction = STATUS_PRIVILEGED_INSTRUCTION,
|
||||||
|
SingleStep = STATUS_SINGLE_STEP,
|
||||||
|
StackOverflow = STATUS_STACK_OVERFLOW,
|
||||||
|
UnwindConsolidate = STATUS_UNWIND_CONSOLIDATE,
|
||||||
|
// Addition exceptions
|
||||||
|
Wait0 = STATUS_WAIT_0,
|
||||||
|
AbandonedWait0 = STATUS_ABANDONED_WAIT_0,
|
||||||
|
UserAPC = STATUS_USER_APC,
|
||||||
|
Timeout = STATUS_TIMEOUT,
|
||||||
|
Pending = STATUS_PENDING,
|
||||||
|
SegmentNotification = STATUS_SEGMENT_NOTIFICATION,
|
||||||
|
FatalAppExit = STATUS_FATAL_APP_EXIT,
|
||||||
|
Longjump = STATUS_LONGJUMP,
|
||||||
|
DLLNotFound = STATUS_DLL_NOT_FOUND,
|
||||||
|
OrdinalNotFound = STATUS_ORDINAL_NOT_FOUND,
|
||||||
|
EntryPointNotFound = STATUS_ENTRYPOINT_NOT_FOUND,
|
||||||
|
ControlCExit = STATUS_CONTROL_C_EXIT,
|
||||||
|
DllInitFailed = STATUS_DLL_INIT_FAILED,
|
||||||
|
FltMultipleFaults = STATUS_FLOAT_MULTIPLE_FAULTS,
|
||||||
|
FltMultipleTraps = STATUS_FLOAT_MULTIPLE_TRAPS,
|
||||||
|
RegNatConsumption = STATUS_REG_NAT_CONSUMPTION,
|
||||||
|
HeapCorruption = STATUS_HEAP_CORRUPTION,
|
||||||
|
StackBufferOverrun = STATUS_STACK_BUFFER_OVERRUN,
|
||||||
|
InvalidCRuntimeParameter = STATUS_INVALID_CRUNTIME_PARAMETER,
|
||||||
|
AssertionFailure = STATUS_ASSERTION_FAILURE,
|
||||||
|
SXSEarlyDeactivation = STATUS_SXS_EARLY_DEACTIVATION,
|
||||||
|
SXSInvalidDeactivation = STATUS_SXS_INVALID_DEACTIVATION,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static CRASH_EXCEPTIONS: &[ExceptionCode] = &[
|
||||||
|
ExceptionCode::AccessViolation,
|
||||||
|
ExceptionCode::ArrayBoundsExceeded,
|
||||||
|
ExceptionCode::FltDivideByZero,
|
||||||
|
ExceptionCode::GuardPageViolation,
|
||||||
|
ExceptionCode::IllegalInstruction,
|
||||||
|
ExceptionCode::InPageError,
|
||||||
|
ExceptionCode::IntegerDivideByZero,
|
||||||
|
ExceptionCode::InvalidHandle,
|
||||||
|
ExceptionCode::NoncontinuableException,
|
||||||
|
ExceptionCode::PrivilegedInstruction,
|
||||||
|
ExceptionCode::StackOverflow,
|
||||||
|
ExceptionCode::HeapCorruption,
|
||||||
|
ExceptionCode::StackBufferOverrun,
|
||||||
|
ExceptionCode::AssertionFailure,
|
||||||
|
];
|
||||||
|
|
||||||
|
impl PartialEq for ExceptionCode {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
*self as u32 == *other as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for ExceptionCode {}
|
||||||
|
|
||||||
|
unsafe impl Sync for ExceptionCode {}
|
||||||
|
|
||||||
|
impl Display for ExceptionCode {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
|
match self {
|
||||||
|
ExceptionCode::AccessViolation => write!(f, "STATUS_ACCESS_VIOLATION")?,
|
||||||
|
ExceptionCode::ArrayBoundsExceeded => write!(f, "STATUS_ARRAY_BOUNDS_EXCEEDED")?,
|
||||||
|
ExceptionCode::Breakpoint => write!(f, "STATUS_BREAKPOINT")?,
|
||||||
|
ExceptionCode::DatatypeMisalignment => write!(f, "STATUS_DATATYPE_MISALIGNMENT")?,
|
||||||
|
ExceptionCode::FltDenormalOperand => write!(f, "STATUS_FLOAT_DENORMAL_OPERAND")?,
|
||||||
|
ExceptionCode::FltDivideByZero => write!(f, "STATUS_FLOAT_DIVIDE_BY_ZERO")?,
|
||||||
|
ExceptionCode::FltInexactResult => write!(f, "STATUS_FLOAT_INEXACT_RESULT")?,
|
||||||
|
ExceptionCode::FltInvalidOperation => write!(f, "STATUS_FLOAT_INVALID_OPERATION")?,
|
||||||
|
ExceptionCode::FltOverflow => write!(f, "STATUS_FLOAT_OVERFLOW")?,
|
||||||
|
ExceptionCode::FltStackCheck => write!(f, "STATUS_FLOAT_STACK_CHECK")?,
|
||||||
|
ExceptionCode::FltUnderflow => write!(f, "STATUS_FLOAT_UNDERFLOW")?,
|
||||||
|
ExceptionCode::GuardPageViolation => write!(f, "STATUS_GUARD_PAGE_VIOLATION")?,
|
||||||
|
ExceptionCode::IllegalInstruction => write!(f, "STATUS_ILLEGAL_INSTRUCTION")?,
|
||||||
|
ExceptionCode::InPageError => write!(f, "STATUS_IN_PAGE_ERROR")?,
|
||||||
|
ExceptionCode::IntegerDivideByZero => write!(f, "STATUS_INTEGER_DIVIDE_BY_ZERO")?,
|
||||||
|
ExceptionCode::IntegerOverflow => write!(f, "STATUS_INTEGER_OVERFLOW")?,
|
||||||
|
ExceptionCode::InvalidDisposition => write!(f, "STATUS_INVALID_DISPOSITION")?,
|
||||||
|
ExceptionCode::InvalidHandle => write!(f, "STATUS_INVALID_HANDLE")?,
|
||||||
|
ExceptionCode::NoncontinuableException => write!(f, "STATUS_NONCONTINUABLE_EXCEPTION")?,
|
||||||
|
ExceptionCode::PrivilegedInstruction => write!(f, "STATUS_PRIVILEGED_INSTRUCTION")?,
|
||||||
|
ExceptionCode::SingleStep => write!(f, "STATUS_SINGLE_STEP")?,
|
||||||
|
ExceptionCode::StackOverflow => write!(f, "STATUS_STACK_OVERFLOW")?,
|
||||||
|
ExceptionCode::UnwindConsolidate => write!(f, "STATUS_UNWIND_CONSOLIDATE")?,
|
||||||
|
ExceptionCode::Wait0 => write!(f, "STATUS_WAIT_0")?,
|
||||||
|
ExceptionCode::AbandonedWait0 => write!(f, "STATUS_ABANDONED_WAIT_0")?,
|
||||||
|
ExceptionCode::UserAPC => write!(f, "STATUS_USER_APC")?,
|
||||||
|
ExceptionCode::Timeout => write!(f, "STATUS_TIMEOUT")?,
|
||||||
|
ExceptionCode::Pending => write!(f, "STATUS_PENDING")?,
|
||||||
|
ExceptionCode::SegmentNotification => write!(f, "STATUS_SEGMENT_NOTIFICATION")?,
|
||||||
|
ExceptionCode::FatalAppExit => write!(f, "STATUS_FATAL_APP_EXIT")?,
|
||||||
|
ExceptionCode::Longjump => write!(f, "STATUS_LONGJUMP")?,
|
||||||
|
ExceptionCode::DLLNotFound => write!(f, "STATUS_DLL_NOT_FOUND")?,
|
||||||
|
ExceptionCode::OrdinalNotFound => write!(f, "STATUS_ORDINAL_NOT_FOUND")?,
|
||||||
|
ExceptionCode::EntryPointNotFound => write!(f, "STATUS_ENTRYPOINT_NOT_FOUND")?,
|
||||||
|
ExceptionCode::ControlCExit => write!(f, "STATUS_CONTROL_C_EXIT")?,
|
||||||
|
ExceptionCode::DllInitFailed => write!(f, "STATUS_DLL_INIT_FAILED")?,
|
||||||
|
ExceptionCode::FltMultipleFaults => write!(f, "STATUS_FLOAT_MULTIPLE_FAULTS")?,
|
||||||
|
ExceptionCode::FltMultipleTraps => write!(f, "STATUS_FLOAT_MULTIPLE_TRAPS")?,
|
||||||
|
ExceptionCode::RegNatConsumption => write!(f, "STATUS_REG_NAT_CONSUMPTION")?,
|
||||||
|
ExceptionCode::HeapCorruption => write!(f, "STATUS_HEAP_CORRUPTION")?,
|
||||||
|
ExceptionCode::StackBufferOverrun => write!(f, "STATUS_STACK_BUFFER_OVERRUN")?,
|
||||||
|
ExceptionCode::InvalidCRuntimeParameter => {
|
||||||
|
write!(f, "STATUS_INVALID_CRUNTIME_PARAMETER")?
|
||||||
|
}
|
||||||
|
ExceptionCode::AssertionFailure => write!(f, "STATUS_ASSERTION_FAILURE")?,
|
||||||
|
ExceptionCode::SXSEarlyDeactivation => write!(f, "STATUS_SXS_EARLY_DEACTIVATION")?,
|
||||||
|
ExceptionCode::SXSInvalidDeactivation => write!(f, "STATUS_SXS_INVALID_DEACTIVATION")?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static EXCEPTION_CODES_MAPPING: [ExceptionCode; 45] = [
|
||||||
|
ExceptionCode::AccessViolation,
|
||||||
|
ExceptionCode::ArrayBoundsExceeded,
|
||||||
|
ExceptionCode::Breakpoint,
|
||||||
|
ExceptionCode::DatatypeMisalignment,
|
||||||
|
ExceptionCode::FltDenormalOperand,
|
||||||
|
ExceptionCode::FltDivideByZero,
|
||||||
|
ExceptionCode::FltInexactResult,
|
||||||
|
ExceptionCode::FltInvalidOperation,
|
||||||
|
ExceptionCode::FltOverflow,
|
||||||
|
ExceptionCode::FltStackCheck,
|
||||||
|
ExceptionCode::FltUnderflow,
|
||||||
|
ExceptionCode::GuardPageViolation,
|
||||||
|
ExceptionCode::IllegalInstruction,
|
||||||
|
ExceptionCode::InPageError,
|
||||||
|
ExceptionCode::IntegerDivideByZero,
|
||||||
|
ExceptionCode::IntegerOverflow,
|
||||||
|
ExceptionCode::InvalidDisposition,
|
||||||
|
ExceptionCode::InvalidHandle,
|
||||||
|
ExceptionCode::NoncontinuableException,
|
||||||
|
ExceptionCode::PrivilegedInstruction,
|
||||||
|
ExceptionCode::SingleStep,
|
||||||
|
ExceptionCode::StackOverflow,
|
||||||
|
ExceptionCode::UnwindConsolidate,
|
||||||
|
ExceptionCode::Wait0,
|
||||||
|
ExceptionCode::AbandonedWait0,
|
||||||
|
ExceptionCode::UserAPC,
|
||||||
|
ExceptionCode::Timeout,
|
||||||
|
ExceptionCode::Pending,
|
||||||
|
ExceptionCode::SegmentNotification,
|
||||||
|
ExceptionCode::FatalAppExit,
|
||||||
|
ExceptionCode::Longjump,
|
||||||
|
ExceptionCode::DLLNotFound,
|
||||||
|
ExceptionCode::OrdinalNotFound,
|
||||||
|
ExceptionCode::EntryPointNotFound,
|
||||||
|
ExceptionCode::ControlCExit,
|
||||||
|
ExceptionCode::DllInitFailed,
|
||||||
|
ExceptionCode::FltMultipleFaults,
|
||||||
|
ExceptionCode::FltMultipleTraps,
|
||||||
|
ExceptionCode::RegNatConsumption,
|
||||||
|
ExceptionCode::HeapCorruption,
|
||||||
|
ExceptionCode::StackBufferOverrun,
|
||||||
|
ExceptionCode::InvalidCRuntimeParameter,
|
||||||
|
ExceptionCode::AssertionFailure,
|
||||||
|
ExceptionCode::SXSEarlyDeactivation,
|
||||||
|
ExceptionCode::SXSInvalidDeactivation,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub trait Handler {
|
||||||
|
/// Handle an exception
|
||||||
|
fn handle(
|
||||||
|
&mut self,
|
||||||
|
exception_code: ExceptionCode,
|
||||||
|
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||||
|
);
|
||||||
|
/// Return a list of exceptions to handle
|
||||||
|
fn exceptions(&self) -> Vec<ExceptionCode>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HandlerHolder {
|
||||||
|
handler: UnsafeCell<*mut dyn Handler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for HandlerHolder {}
|
||||||
|
|
||||||
|
/// Keep track of which handler is registered for which exception
|
||||||
|
static mut EXCEPTION_HANDLERS: [Option<HandlerHolder>; 64] = [
|
||||||
|
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||||
|
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||||
|
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||||
|
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||||
|
];
|
||||||
|
|
||||||
|
type NativeHandlerType = extern "system" fn(*mut EXCEPTION_POINTERS) -> c_long;
|
||||||
|
static mut PREVIOUS_HANDLER: Option<NativeHandlerType> = None;
|
||||||
|
|
||||||
|
/// Internal function that is being called whenever an exception arrives (stdcall).
|
||||||
|
unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_POINTERS) -> c_long {
|
||||||
|
let code = exception_pointers
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.exception_record
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.exception_code;
|
||||||
|
let exception_code = ExceptionCode::try_from(code).unwrap();
|
||||||
|
let index = EXCEPTION_CODES_MAPPING
|
||||||
|
.iter()
|
||||||
|
.position(|x| *x == exception_code)
|
||||||
|
.unwrap();
|
||||||
|
let ret = match &EXCEPTION_HANDLERS[index] {
|
||||||
|
Some(handler_holder) => {
|
||||||
|
let handler = &mut **handler_holder.handler.get();
|
||||||
|
handler.handle(exception_code, exception_pointers);
|
||||||
|
EXCEPTION_EXECUTE_HANDLER
|
||||||
|
}
|
||||||
|
None => EXCEPTION_EXECUTE_HANDLER,
|
||||||
|
};
|
||||||
|
if let Some(prev_handler) = PREVIOUS_HANDLER {
|
||||||
|
prev_handler(exception_pointers)
|
||||||
|
} else {
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Setup Win32 exception handlers in a somewhat rusty way.
|
||||||
|
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
|
||||||
|
let exceptions = handler.exceptions();
|
||||||
|
for exception_code in exceptions {
|
||||||
|
let index = EXCEPTION_CODES_MAPPING
|
||||||
|
.iter()
|
||||||
|
.position(|x| *x == exception_code)
|
||||||
|
.unwrap();
|
||||||
|
write_volatile(
|
||||||
|
&mut EXCEPTION_HANDLERS[index],
|
||||||
|
Some(HandlerHolder {
|
||||||
|
handler: UnsafeCell::new(handler as *mut dyn Handler),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
if let Some(prev) = SetUnhandledExceptionFilter(Some(core::mem::transmute(
|
||||||
|
handle_exception as *const c_void,
|
||||||
|
))) {
|
||||||
|
PREVIOUS_HANDLER = Some(core::mem::transmute(prev as *const c_void));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -318,14 +318,14 @@ pub mod unix_shmem {
|
|||||||
impl Drop for UnixShMem {
|
impl Drop for UnixShMem {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
afl_shmem_deinit(self);
|
unix_shmem_deinit(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an uninitialized shmap
|
/// Create an uninitialized shmap
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
const fn afl_shmem_unitialized() -> UnixShMem {
|
const fn unix_shmem_unitialized() -> UnixShMem {
|
||||||
UnixShMem {
|
UnixShMem {
|
||||||
shm_str: [0; 20],
|
shm_str: [0; 20],
|
||||||
shm_id: -1,
|
shm_id: -1,
|
||||||
@ -337,8 +337,8 @@ pub mod unix_shmem {
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl UnixShMem {
|
impl UnixShMem {
|
||||||
pub fn from_str(shm_str: &CStr, map_size: usize) -> Result<Self, Error> {
|
pub fn from_str(shm_str: &CStr, map_size: usize) -> Result<Self, Error> {
|
||||||
let mut ret = afl_shmem_unitialized();
|
let mut ret = unix_shmem_unitialized();
|
||||||
let map = unsafe { afl_shmem_by_str(&mut ret, shm_str, map_size) };
|
let map = unsafe { unix_shmem_by_str(&mut ret, shm_str, map_size) };
|
||||||
if !map.is_null() {
|
if !map.is_null() {
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
} else {
|
} else {
|
||||||
@ -350,8 +350,8 @@ pub mod unix_shmem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(map_size: usize) -> Result<Self, Error> {
|
pub fn new(map_size: usize) -> Result<Self, Error> {
|
||||||
let mut ret = afl_shmem_unitialized();
|
let mut ret = unix_shmem_unitialized();
|
||||||
let map = unsafe { afl_shmem_init(&mut ret, map_size) };
|
let map = unsafe { unix_shmem_init(&mut ret, map_size) };
|
||||||
if !map.is_null() {
|
if !map.is_null() {
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
} else {
|
} else {
|
||||||
@ -364,7 +364,7 @@ pub mod unix_shmem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Deinitialize this shmem instance
|
/// Deinitialize this shmem instance
|
||||||
unsafe fn afl_shmem_deinit(shm: *mut UnixShMem) {
|
unsafe fn unix_shmem_deinit(shm: *mut UnixShMem) {
|
||||||
if shm.is_null() || (*shm).map.is_null() {
|
if shm.is_null() || (*shm).map.is_null() {
|
||||||
/* Serialized map id */
|
/* Serialized map id */
|
||||||
// Not set or not initialized;
|
// Not set or not initialized;
|
||||||
@ -377,7 +377,7 @@ pub mod unix_shmem {
|
|||||||
|
|
||||||
/// Functions to create Shared memory region, for observation channels and
|
/// Functions to create Shared memory region, for observation channels and
|
||||||
/// opening inputs and stuff.
|
/// opening inputs and stuff.
|
||||||
unsafe fn afl_shmem_init(shm: *mut UnixShMem, map_size: usize) -> *mut c_uchar {
|
unsafe fn unix_shmem_init(shm: *mut UnixShMem, map_size: usize) -> *mut c_uchar {
|
||||||
(*shm).map_size = map_size;
|
(*shm).map_size = map_size;
|
||||||
(*shm).map = ptr::null_mut();
|
(*shm).map = ptr::null_mut();
|
||||||
(*shm).shm_id = shmget(
|
(*shm).shm_id = shmget(
|
||||||
@ -409,7 +409,7 @@ pub mod unix_shmem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Uses a shmap id string to open a shared map
|
/// Uses a shmap id string to open a shared map
|
||||||
unsafe fn afl_shmem_by_str(
|
unsafe fn unix_shmem_by_str(
|
||||||
shm: *mut UnixShMem,
|
shm: *mut UnixShMem,
|
||||||
shm_str: &CStr,
|
shm_str: &CStr,
|
||||||
map_size: usize,
|
map_size: usize,
|
||||||
@ -443,18 +443,140 @@ pub mod unix_shmem {
|
|||||||
#[cfg(all(feature = "std", windows))]
|
#[cfg(all(feature = "std", windows))]
|
||||||
pub mod shmem {
|
pub mod shmem {
|
||||||
|
|
||||||
//TODO use super::ShMem;
|
use super::ShMem;
|
||||||
|
use crate::{
|
||||||
|
bolts::bindings::{
|
||||||
|
windows::win32::system_services::{
|
||||||
|
CreateFileMappingA, MapViewOfFile, OpenFileMappingA, UnmapViewOfFile,
|
||||||
|
},
|
||||||
|
windows::win32::system_services::{BOOL, HANDLE, PAGE_TYPE, PSTR},
|
||||||
|
windows::win32::windows_programming::CloseHandle,
|
||||||
|
},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use core::{ffi::c_void, ptr, slice};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
const INVALID_HANDLE_VALUE: isize = -1;
|
||||||
|
const FILE_MAP_ALL_ACCESS: u32 = 0xf001f;
|
||||||
|
|
||||||
/// The default Sharedmap impl for windows using shmctl & shmget
|
/// The default Sharedmap impl for windows using shmctl & shmget
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Win32ShMem {
|
pub struct Win32ShMem {
|
||||||
pub filename: [u8; 64],
|
pub shm_str: [u8; 20],
|
||||||
//TODO pub handle: windows::win32::system_services::HANDLE,
|
pub handle: HANDLE,
|
||||||
pub map: *mut u8,
|
pub map: *mut u8,
|
||||||
pub map_size: usize,
|
pub map_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO complete
|
impl ShMem for Win32ShMem {
|
||||||
|
fn existing_from_shm_slice(
|
||||||
|
map_str_bytes: &[u8; 20],
|
||||||
|
map_size: usize,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
Self::from_str(map_str_bytes, map_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_map(map_size: usize) -> Result<Self, Error> {
|
||||||
|
Self::new(map_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shm_slice(&self) -> &[u8; 20] {
|
||||||
|
&self.shm_str
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(&self) -> &[u8] {
|
||||||
|
unsafe { slice::from_raw_parts(self.map, self.map_size) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_mut(&mut self) -> &mut [u8] {
|
||||||
|
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deinit sharedmaps on drop
|
||||||
|
impl Drop for Win32ShMem {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
UnmapViewOfFile(self.map as *mut c_void);
|
||||||
|
CloseHandle(self.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Win32ShMem {
|
||||||
|
pub fn from_str(map_str_bytes: &[u8; 20], map_size: usize) -> Result<Self, Error> {
|
||||||
|
unsafe {
|
||||||
|
let handle = OpenFileMappingA(
|
||||||
|
FILE_MAP_ALL_ACCESS,
|
||||||
|
BOOL(0),
|
||||||
|
PSTR(map_str_bytes as *const u8 as *mut u8),
|
||||||
|
);
|
||||||
|
if handle == HANDLE(0) {
|
||||||
|
return Err(Error::Unknown(format!(
|
||||||
|
"Cannot open shared memory {}",
|
||||||
|
String::from_utf8_lossy(map_str_bytes)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let map =
|
||||||
|
MapViewOfFile(handle.clone(), FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||||
|
if map == ptr::null_mut() {
|
||||||
|
return Err(Error::Unknown(format!(
|
||||||
|
"Cannot map shared memory {}",
|
||||||
|
String::from_utf8_lossy(map_str_bytes)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let mut ret = Self {
|
||||||
|
shm_str: [0; 20],
|
||||||
|
handle: handle,
|
||||||
|
map: map,
|
||||||
|
map_size: map_size,
|
||||||
|
};
|
||||||
|
ret.shm_str.clone_from_slice(map_str_bytes);
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(map_size: usize) -> Result<Self, Error> {
|
||||||
|
unsafe {
|
||||||
|
let uuid = Uuid::new_v4();
|
||||||
|
let mut map_str = format!("libafl_{}", uuid.to_simple());
|
||||||
|
let map_str_bytes = map_str.as_mut_vec();
|
||||||
|
map_str_bytes[19] = 0; // Trucate to size 20
|
||||||
|
let handle = CreateFileMappingA(
|
||||||
|
HANDLE(INVALID_HANDLE_VALUE),
|
||||||
|
ptr::null_mut(),
|
||||||
|
PAGE_TYPE::PAGE_READWRITE,
|
||||||
|
0,
|
||||||
|
map_size as u32,
|
||||||
|
PSTR(map_str_bytes.as_mut_ptr()),
|
||||||
|
);
|
||||||
|
if handle == HANDLE(0) {
|
||||||
|
return Err(Error::Unknown(format!(
|
||||||
|
"Cannot create shared memory {}",
|
||||||
|
String::from_utf8_lossy(map_str_bytes)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let map =
|
||||||
|
MapViewOfFile(handle.clone(), FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||||
|
if map == ptr::null_mut() {
|
||||||
|
return Err(Error::Unknown(format!(
|
||||||
|
"Cannot map shared memory {}",
|
||||||
|
String::from_utf8_lossy(map_str_bytes)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let mut ret = Self {
|
||||||
|
shm_str: [0; 20],
|
||||||
|
handle: handle,
|
||||||
|
map: map,
|
||||||
|
map_size: map_size,
|
||||||
|
};
|
||||||
|
ret.shm_str.clone_from_slice(&map_str_bytes[0..20]);
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
//! The InProcess Executor is a libfuzzer-like executor, that will simply call a function.
|
//! The InProcess Executor is a libfuzzer-like executor, that will simply call a function.
|
||||||
//! It should usually be paired with extra error-handling, such as a restarting event manager, to be effective.
|
//! It should usually be paired with extra error-handling, such as a restarting event manager, to be effective.
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
use core::{
|
use core::{
|
||||||
|
ffi::c_void,
|
||||||
|
marker::PhantomData,
|
||||||
ptr::{self, write_volatile},
|
ptr::{self, write_volatile},
|
||||||
sync::atomic::{compiler_fence, Ordering},
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use crate::bolts::os::unix_signals::{c_void, setup_signal_handler};
|
use crate::bolts::os::unix_signals::setup_signal_handler;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use crate::bolts::os::windows_exceptions::setup_exception_handler;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::tuples::Named,
|
bolts::tuples::Named,
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
@ -60,6 +62,27 @@ where
|
|||||||
&mut data.current_input_ptr,
|
&mut data.current_input_ptr,
|
||||||
_input as *const _ as *const c_void,
|
_input as *const _ as *const c_void,
|
||||||
);
|
);
|
||||||
|
write_volatile(
|
||||||
|
&mut data.observers_ptr,
|
||||||
|
&self.observers as *const _ as *const c_void,
|
||||||
|
);
|
||||||
|
// Direct raw pointers access /aliasing is pretty undefined behavior.
|
||||||
|
// Since the state and event may have moved in memory, refresh them right before the signal may happen
|
||||||
|
write_volatile(&mut data.state_ptr, _state as *mut _ as *mut c_void);
|
||||||
|
write_volatile(&mut data.event_mgr_ptr, _event_mgr as *mut _ as *mut c_void);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
unsafe {
|
||||||
|
let data = &mut windows_exception_handler::GLOBAL_STATE;
|
||||||
|
write_volatile(
|
||||||
|
&mut data.current_input_ptr,
|
||||||
|
_input as *const _ as *const c_void,
|
||||||
|
);
|
||||||
|
write_volatile(
|
||||||
|
&mut data.observers_ptr,
|
||||||
|
&self.observers as *const _ as *const c_void,
|
||||||
|
);
|
||||||
// Direct raw pointers access /aliasing is pretty undefined behavior.
|
// Direct raw pointers access /aliasing is pretty undefined behavior.
|
||||||
// Since the state and event may have moved in memory, refresh them right before the signal may happen
|
// Since the state and event may have moved in memory, refresh them right before the signal may happen
|
||||||
write_volatile(&mut data.state_ptr, _state as *mut _ as *mut c_void);
|
write_volatile(&mut data.state_ptr, _state as *mut _ as *mut c_void);
|
||||||
@ -73,6 +96,16 @@ where
|
|||||||
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
|
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
|
||||||
let bytes = input.target_bytes();
|
let bytes = input.target_bytes();
|
||||||
let ret = (self.harness_fn)(self, bytes.as_slice());
|
let ret = (self.harness_fn)(self, bytes.as_slice());
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn post_exec<EM, S>(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut S,
|
||||||
|
_event_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) -> Result<(), Error> {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
unsafe {
|
unsafe {
|
||||||
write_volatile(
|
write_volatile(
|
||||||
@ -81,7 +114,15 @@ where
|
|||||||
);
|
);
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
Ok(ret)
|
#[cfg(windows)]
|
||||||
|
unsafe {
|
||||||
|
write_volatile(
|
||||||
|
&mut windows_exception_handler::GLOBAL_STATE.current_input_ptr,
|
||||||
|
ptr::null(),
|
||||||
|
);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,10 +180,6 @@ where
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = &mut unix_signal_handler::GLOBAL_STATE;
|
let data = &mut unix_signal_handler::GLOBAL_STATE;
|
||||||
write_volatile(
|
|
||||||
&mut data.observers_ptr,
|
|
||||||
&observers as *const _ as *const c_void,
|
|
||||||
);
|
|
||||||
write_volatile(
|
write_volatile(
|
||||||
&mut data.crash_handler,
|
&mut data.crash_handler,
|
||||||
unix_signal_handler::inproc_crash_handler::<EM, I, OC, OFT, OT, S>,
|
unix_signal_handler::inproc_crash_handler::<EM, I, OC, OFT, OT, S>,
|
||||||
@ -155,6 +192,21 @@ where
|
|||||||
setup_signal_handler(data)?;
|
setup_signal_handler(data)?;
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
unsafe {
|
||||||
|
let data = &mut windows_exception_handler::GLOBAL_STATE;
|
||||||
|
write_volatile(
|
||||||
|
&mut data.crash_handler,
|
||||||
|
windows_exception_handler::inproc_crash_handler::<EM, I, OC, OFT, OT, S>,
|
||||||
|
);
|
||||||
|
//write_volatile(
|
||||||
|
// &mut data.timeout_handler,
|
||||||
|
// windows_exception_handler::inproc_timeout_handler::<EM, I, OC, OFT, OT, S>,
|
||||||
|
//);
|
||||||
|
|
||||||
|
setup_exception_handler(data)?;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
harness_fn,
|
harness_fn,
|
||||||
@ -187,6 +239,8 @@ mod unix_signal_handler {
|
|||||||
state::{HasObjectives, HasSolutions},
|
state::{HasObjectives, HasSolutions},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO merge GLOBAL_STATE with the Windows one
|
||||||
|
|
||||||
/// Signal handling on unix systems needs some nasty unsafe.
|
/// Signal handling on unix systems needs some nasty unsafe.
|
||||||
pub static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHandlerData {
|
pub static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHandlerData {
|
||||||
/// The state ptr for signal handling
|
/// The state ptr for signal handling
|
||||||
@ -408,6 +462,166 @@ mod unix_signal_handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
mod windows_exception_handler {
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::{ffi::c_void, ptr};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use std::io::{stdout, Write};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bolts::{
|
||||||
|
bindings::windows::win32::system_services::ExitProcess,
|
||||||
|
os::windows_exceptions::{
|
||||||
|
ExceptionCode, Handler, CRASH_EXCEPTIONS, EXCEPTION_POINTERS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
corpus::{Corpus, Testcase},
|
||||||
|
events::{Event, EventManager},
|
||||||
|
executors::ExitKind,
|
||||||
|
feedbacks::FeedbacksTuple,
|
||||||
|
inputs::{HasTargetBytes, Input},
|
||||||
|
observers::ObserversTuple,
|
||||||
|
state::{HasObjectives, HasSolutions},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Signal handling on unix systems needs some nasty unsafe.
|
||||||
|
pub static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHandlerData {
|
||||||
|
/// The state ptr for signal handling
|
||||||
|
state_ptr: ptr::null_mut(),
|
||||||
|
/// The event manager ptr for signal handling
|
||||||
|
event_mgr_ptr: ptr::null_mut(),
|
||||||
|
/// The observers ptr for signal handling
|
||||||
|
observers_ptr: ptr::null(),
|
||||||
|
/// The current input for signal handling
|
||||||
|
current_input_ptr: ptr::null(),
|
||||||
|
/// The crash handler fn
|
||||||
|
crash_handler: nop_handler,
|
||||||
|
// The timeout handler fn
|
||||||
|
//timeout_handler: nop_handler,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct InProcessExecutorHandlerData {
|
||||||
|
pub state_ptr: *mut c_void,
|
||||||
|
pub event_mgr_ptr: *mut c_void,
|
||||||
|
pub observers_ptr: *const c_void,
|
||||||
|
pub current_input_ptr: *const c_void,
|
||||||
|
pub crash_handler: unsafe fn(ExceptionCode, *mut EXCEPTION_POINTERS, &mut Self),
|
||||||
|
//pub timeout_handler: unsafe fn(ExceptionCode, *mut EXCEPTION_POINTERS, &mut Self),
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for InProcessExecutorHandlerData {}
|
||||||
|
unsafe impl Sync for InProcessExecutorHandlerData {}
|
||||||
|
|
||||||
|
unsafe fn nop_handler(
|
||||||
|
_code: ExceptionCode,
|
||||||
|
_exception_pointers: *mut EXCEPTION_POINTERS,
|
||||||
|
_data: &mut InProcessExecutorHandlerData,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler for InProcessExecutorHandlerData {
|
||||||
|
fn handle(&mut self, code: ExceptionCode, exception_pointers: *mut EXCEPTION_POINTERS) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
(data.crash_handler)(code, exception_pointers, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exceptions(&self) -> Vec<ExceptionCode> {
|
||||||
|
CRASH_EXCEPTIONS.to_vec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn inproc_crash_handler<EM, I, OC, OFT, OT, S>(
|
||||||
|
code: ExceptionCode,
|
||||||
|
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||||
|
data: &mut InProcessExecutorHandlerData,
|
||||||
|
) where
|
||||||
|
EM: EventManager<I, S>,
|
||||||
|
OT: ObserversTuple,
|
||||||
|
OC: Corpus<I>,
|
||||||
|
OFT: FeedbacksTuple<I>,
|
||||||
|
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
|
||||||
|
I: Input + HasTargetBytes,
|
||||||
|
{
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
println!("Crashed with {}", code);
|
||||||
|
if !data.current_input_ptr.is_null() {
|
||||||
|
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 observers = (data.observers_ptr as *const OT).as_ref().unwrap();
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
println!("Child crashed!");
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
let _ = stdout().flush();
|
||||||
|
|
||||||
|
let input = (data.current_input_ptr as *const I).as_ref().unwrap();
|
||||||
|
// Make sure we don't crash in the crash handler forever.
|
||||||
|
data.current_input_ptr = ptr::null();
|
||||||
|
|
||||||
|
let obj_fitness = state
|
||||||
|
.objectives_mut()
|
||||||
|
.is_interesting_all(&input, observers, ExitKind::Crash)
|
||||||
|
.expect("In crash handler objectives failure.");
|
||||||
|
if obj_fitness > 0 {
|
||||||
|
let new_input = input.clone();
|
||||||
|
state
|
||||||
|
.solutions_mut()
|
||||||
|
.add(Testcase::new(new_input))
|
||||||
|
.expect("In crash handler solutions failure.");
|
||||||
|
event_mgr
|
||||||
|
.fire(
|
||||||
|
state,
|
||||||
|
Event::Objective {
|
||||||
|
objective_size: state.solutions().count(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("Could not send crashing input");
|
||||||
|
}
|
||||||
|
|
||||||
|
event_mgr.on_restart(state).unwrap();
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
println!("Waiting for broker...");
|
||||||
|
event_mgr.await_restart_safe();
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
println!("Bye!");
|
||||||
|
|
||||||
|
ExitProcess(1);
|
||||||
|
} else {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
{
|
||||||
|
println!("Double crash\n");
|
||||||
|
let crash_addr = exception_pointers
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.exception_record
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.exception_address as usize;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"We crashed at addr 0x{:x}, but are not in the target... Bug in the fuzzer? Exiting.",
|
||||||
|
crash_addr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
{
|
||||||
|
println!("Type QUIT to restart the child");
|
||||||
|
let mut line = String::new();
|
||||||
|
while line.trim() != "QUIT" {
|
||||||
|
std::io::stdin().read_line(&mut line).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO tell the parent to not restart
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
@ -96,7 +96,12 @@ where
|
|||||||
|
|
||||||
/// Called right after execution finished.
|
/// Called right after execution finished.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn post_exec<EM, S>(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error>
|
fn post_exec<EM, S>(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut S,
|
||||||
|
_event_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
EM: EventManager<I, S>,
|
EM: EventManager<I, S>,
|
||||||
{
|
{
|
||||||
|
@ -132,7 +132,7 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn post_exec<EM: EventManager<I, S>, S>(
|
fn post_exec<EM: EventManager<I, S>, S>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_state: &S,
|
_state: &mut S,
|
||||||
_event_mgr: &mut EM,
|
_event_mgr: &mut EM,
|
||||||
_input: &I,
|
_input: &I,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user