inprocess::windows_exception_handler

This commit is contained in:
Andrea Fioraldi 2021-03-18 17:04:59 +01:00
parent 35782d2e9a
commit b4e061750b
3 changed files with 162 additions and 2 deletions

View File

@ -1,7 +1,7 @@
fn main() { fn main() {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
windows::build!( windows::build!(
windows::win32::system_services::{HANDLE, BOOL, PAGE_TYPE, PSTR}, 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},

View File

@ -1,5 +1,7 @@
pub use crate::bolts::bindings::windows::win32::debug::EXCEPTION_POINTERS;
use crate::{ use crate::{
bolts::bindings::windows::win32::debug::{SetUnhandledExceptionFilter, EXCEPTION_POINTERS}, bolts::bindings::windows::win32::debug::{SetUnhandledExceptionFilter},
Error, Error,
}; };

View File

@ -409,6 +409,164 @@ mod unix_signal_handler {
} }
} }
#[cfg(windows)]
mod windows_exception_handler {
use alloc::vec::Vec;
use core::ptr;
#[cfg(feature = "std")]
use std::{
fs,
io::{stdout, Write},
};
use crate::{
bolts::{
os::windows_exceptions::{Handler, ExceptionCode, EXCEPTION_POINTERS, CRASH_EXCEPTIONS},
bindings::windows::win32::system_services::ExitProcess
},
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, data: &mut Self),
pub timeout_handler: unsafe fn(ExceptionCode, *mut EXCEPTION_POINTERS, data: &mut Self),
}
unsafe impl Send for InProcessExecutorHandlerData {}
unsafe impl Sync for InProcessExecutorHandlerData {}
unsafe fn nop_handler(
_code: ExceptionCode,
_exception_pointers: *mut EXCEPTION_POINTERS,
) {
}
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 excaptions(&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!");
unsafe { 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
unsafe { ExitProcess(1) };
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {