SIGINT handlers, and Release StateRestorer shmem (#894)
* drop not working * why drop_in_place works but drop does not * stop shmem leak * don't kill -9 fuzzer * don't put fuzzer background * no & * nostd * fix * fix * windows, clippy * fix * fmt * windows
This commit is contained in:
parent
3bad100cb7
commit
cd8367d3e9
@ -390,8 +390,8 @@ fn fuzz(
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
let null_fd = file_null.as_raw_fd();
|
let null_fd = file_null.as_raw_fd();
|
||||||
dup2(null_fd, io::stdout().as_raw_fd())?;
|
// dup2(null_fd, io::stdout().as_raw_fd())?;
|
||||||
dup2(null_fd, io::stderr().as_raw_fd())?;
|
// dup2(null_fd, io::stderr().as_raw_fd())?;
|
||||||
}
|
}
|
||||||
// reopen file to make sure we're at the end
|
// reopen file to make sure we're at the end
|
||||||
log.replace(
|
log.replace(
|
||||||
|
@ -82,7 +82,7 @@ windows_alias = "unsupported"
|
|||||||
[tasks.run_unix]
|
[tasks.run_unix]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script='''
|
script='''
|
||||||
./${FUZZER_NAME} --cores 0 --input ./corpus &
|
./${FUZZER_NAME} --cores 0 --input ./corpus
|
||||||
'''
|
'''
|
||||||
dependencies = [ "fuzzer" ]
|
dependencies = [ "fuzzer" ]
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ windows_alias = "unsupported"
|
|||||||
[tasks.run_unix]
|
[tasks.run_unix]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script='''
|
script='''
|
||||||
./${FUZZER_NAME} --cores 0 --input ./corpus &
|
./${FUZZER_NAME} --cores 0 --input ./corpus
|
||||||
'''
|
'''
|
||||||
dependencies = [ "fuzzer" ]
|
dependencies = [ "fuzzer" ]
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ windows_alias = "unsupported"
|
|||||||
[tasks.run_unix]
|
[tasks.run_unix]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script='''
|
script='''
|
||||||
./${FUZZER_NAME} --cores 0 --input ./corpus &
|
./${FUZZER_NAME} --cores 0 --input ./corpus
|
||||||
'''
|
'''
|
||||||
dependencies = [ "fuzzer" ]
|
dependencies = [ "fuzzer" ]
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ const LLMP_PAGE_HEADER_LEN: usize = size_of::<LlmpPage>();
|
|||||||
|
|
||||||
/// The llmp broker registers a signal handler for cleanups on `SIGINT`.
|
/// The llmp broker registers a signal handler for cleanups on `SIGINT`.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
static mut GLOBAL_SIGHANDLER_STATE: LlmpBrokerSignalHandler = LlmpBrokerSignalHandler {
|
static mut LLMP_SIGHANDLER_STATE: LlmpShutdownSignalHandler = LlmpShutdownSignalHandler {
|
||||||
shutting_down: false,
|
shutting_down: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1770,12 +1770,12 @@ where
|
|||||||
/// A signal handler for the [`LlmpBroker`].
|
/// A signal handler for the [`LlmpBroker`].
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LlmpBrokerSignalHandler {
|
pub struct LlmpShutdownSignalHandler {
|
||||||
shutting_down: bool,
|
shutting_down: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
impl Handler for LlmpBrokerSignalHandler {
|
impl Handler for LlmpShutdownSignalHandler {
|
||||||
fn handle(&mut self, _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t) {
|
fn handle(&mut self, _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t) {
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::write_volatile(&mut self.shutting_down, true);
|
ptr::write_volatile(&mut self.shutting_down, true);
|
||||||
@ -1957,7 +1957,7 @@ where
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
fn is_shutting_down(&self) -> bool {
|
fn is_shutting_down(&self) -> bool {
|
||||||
unsafe { ptr::read_volatile(&GLOBAL_SIGHANDLER_STATE.shutting_down) }
|
unsafe { ptr::read_volatile(&LLMP_SIGHANDLER_STATE.shutting_down) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Always returns true on platforms, where no shutdown signal handlers are supported
|
/// Always returns true on platforms, where no shutdown signal handlers are supported
|
||||||
@ -1976,7 +1976,7 @@ where
|
|||||||
F: FnMut(ClientId, Tag, Flags, &[u8]) -> Result<LlmpMsgHookResult, Error>,
|
F: FnMut(ClientId, Tag, Flags, &[u8]) -> Result<LlmpMsgHookResult, Error>,
|
||||||
{
|
{
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
if let Err(_e) = unsafe { setup_signal_handler(&mut GLOBAL_SIGHANDLER_STATE) } {
|
if let Err(_e) = unsafe { setup_signal_handler(&mut LLMP_SIGHANDLER_STATE) } {
|
||||||
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
println!("Failed to setup signal handlers: {_e}");
|
println!("Failed to setup signal handlers: {_e}");
|
||||||
|
@ -31,6 +31,11 @@ use crate::bolts::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer};
|
use crate::bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer};
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use crate::{
|
||||||
|
bolts::os::unix_signals::setup_signal_handler,
|
||||||
|
events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA},
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{
|
bolts::{
|
||||||
llmp::{self, Flags, LlmpClient, LlmpClientDescription, Tag},
|
llmp::{self, Flags, LlmpClient, LlmpClientDescription, Tag},
|
||||||
@ -885,17 +890,37 @@ where
|
|||||||
mgr.to_env(_ENV_FUZZER_BROKER_CLIENT_INITIAL);
|
mgr.to_env(_ENV_FUZZER_BROKER_CLIENT_INITIAL);
|
||||||
|
|
||||||
// First, create a channel from the current fuzzer to the next to store state between restarts.
|
// First, create a channel from the current fuzzer to the next to store state between restarts.
|
||||||
let staterestorer: StateRestorer<SP> =
|
let mut staterestorer: StateRestorer<SP> =
|
||||||
StateRestorer::new(self.shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
StateRestorer::new(self.shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
||||||
// Store the information to a map.
|
// Store the information to a map.
|
||||||
staterestorer.write_to_env(_ENV_FUZZER_SENDER)?;
|
staterestorer.write_to_env(_ENV_FUZZER_SENDER)?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
unsafe {
|
||||||
|
let data = &mut SHUTDOWN_SIGHANDLER_DATA;
|
||||||
|
// Write the pointer to staterestorer so we can release its shmem later
|
||||||
|
core::ptr::write_volatile(
|
||||||
|
&mut data.staterestorer_ptr,
|
||||||
|
&mut staterestorer as *mut _ as *mut std::ffi::c_void,
|
||||||
|
);
|
||||||
|
data.allocator_pid = std::process::id() as usize;
|
||||||
|
data.shutdown_handler = shutdown_handler::<SP> as *const std::ffi::c_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We setup signal handlers to clean up shmem segments used by state restorer
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Err(_e) = unsafe { setup_signal_handler(&mut SHUTDOWN_SIGHANDLER_DATA) } {
|
||||||
|
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
println!("Failed to setup signal handlers: {_e}");
|
||||||
|
}
|
||||||
|
|
||||||
let mut ctr: u64 = 0;
|
let mut ctr: u64 = 0;
|
||||||
// Client->parent loop
|
// Client->parent loop
|
||||||
loop {
|
loop {
|
||||||
println!("Spawning next client (id {ctr})");
|
println!("Spawning next client (id {ctr})");
|
||||||
|
|
||||||
// On Unix, we fork
|
// On Unix, we fork (when fork feature is enabled)
|
||||||
#[cfg(all(unix, feature = "fork"))]
|
#[cfg(all(unix, feature = "fork"))]
|
||||||
let child_status = {
|
let child_status = {
|
||||||
self.shmem_provider.pre_fork()?;
|
self.shmem_provider.pre_fork()?;
|
||||||
|
@ -8,6 +8,8 @@ use alloc::{
|
|||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use core::ffi::c_void;
|
||||||
use core::{fmt, hash::Hasher, marker::PhantomData, time::Duration};
|
use core::{fmt, hash::Hasher, marker::PhantomData, time::Duration};
|
||||||
|
|
||||||
use ahash::AHasher;
|
use ahash::AHasher;
|
||||||
@ -16,6 +18,10 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use crate::bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use crate::bolts::{shmem::ShMemProvider, staterestore::StateRestorer};
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::current_time,
|
bolts::current_time,
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
@ -27,6 +33,76 @@ use crate::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Check if ctrl-c is sent with this struct
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
pub static mut SHUTDOWN_SIGHANDLER_DATA: ShutdownSignalData = ShutdownSignalData {
|
||||||
|
allocator_pid: 0,
|
||||||
|
staterestorer_ptr: core::ptr::null_mut(),
|
||||||
|
shutdown_handler: core::ptr::null(),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A signal handler for releasing staterestore shmem
|
||||||
|
/// This struct holds a pointer to StateRestore and clean up the shmem segment used by it.
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ShutdownSignalData {
|
||||||
|
allocator_pid: usize,
|
||||||
|
staterestorer_ptr: *mut c_void,
|
||||||
|
shutdown_handler: *const c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type for shutdown handler
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
pub type ShutdownFuncPtr =
|
||||||
|
unsafe fn(Signal, siginfo_t, &mut ucontext_t, data: &mut ShutdownSignalData);
|
||||||
|
|
||||||
|
/// Shutdown handler. `SigTerm`, `SigInterrupt`, `SigQuit` call this
|
||||||
|
/// We can't handle SIGKILL in the signal handler, this means that you shouldn't kill your fuzzer with `kill -9` because then the shmem segments are never freed
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
pub unsafe fn shutdown_handler<SP>(
|
||||||
|
signal: Signal,
|
||||||
|
_info: siginfo_t,
|
||||||
|
_context: &mut ucontext_t,
|
||||||
|
data: &mut ShutdownSignalData,
|
||||||
|
) where
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"Fuzzer shutdown by Signal: {} Pid: {}",
|
||||||
|
signal,
|
||||||
|
std::process::id()
|
||||||
|
);
|
||||||
|
|
||||||
|
let ptr = data.staterestorer_ptr;
|
||||||
|
if ptr.is_null() || data.allocator_pid != std::process::id() as usize {
|
||||||
|
// Do nothing
|
||||||
|
} else {
|
||||||
|
// The process allocated the staterestorer map must take care of it
|
||||||
|
let sr = (ptr as *mut StateRestorer<SP>).as_mut().unwrap();
|
||||||
|
// println!("{:#?}", sr);
|
||||||
|
std::ptr::drop_in_place(sr);
|
||||||
|
}
|
||||||
|
println!("Bye!");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
impl Handler for ShutdownSignalData {
|
||||||
|
fn handle(&mut self, signal: Signal, info: siginfo_t, context: &mut ucontext_t) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut SHUTDOWN_SIGHANDLER_DATA;
|
||||||
|
if !data.shutdown_handler.is_null() {
|
||||||
|
let func: ShutdownFuncPtr = std::mem::transmute(data.shutdown_handler);
|
||||||
|
(func)(signal, info, context, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signals(&self) -> Vec<Signal> {
|
||||||
|
vec![Signal::SigTerm, Signal::SigInterrupt, Signal::SigQuit]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A per-fuzzer unique `ID`, usually starting with `0` and increasing
|
/// A per-fuzzer unique `ID`, usually starting with `0` and increasing
|
||||||
/// by `1` in multiprocessed `EventManager`s, such as [`self::llmp::LlmpEventManager`].
|
/// by `1` in multiprocessed `EventManager`s, such as [`self::llmp::LlmpEventManager`].
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
|
@ -5,6 +5,10 @@ use alloc::{
|
|||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use core::ffi::c_void;
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use core::ptr::write_volatile;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::{fmt::Debug, marker::PhantomData};
|
use core::{fmt::Debug, marker::PhantomData};
|
||||||
@ -17,6 +21,11 @@ use super::{CustomBufEventResult, CustomBufHandlerFn, HasCustomBufHandlers, Prog
|
|||||||
use crate::bolts::os::startable_self;
|
use crate::bolts::os::startable_self;
|
||||||
#[cfg(all(feature = "std", feature = "fork", unix))]
|
#[cfg(all(feature = "std", feature = "fork", unix))]
|
||||||
use crate::bolts::os::{fork, ForkResult};
|
use crate::bolts::os::{fork, ForkResult};
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use crate::{
|
||||||
|
bolts::os::unix_signals::setup_signal_handler,
|
||||||
|
events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA},
|
||||||
|
};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{shmem::ShMemProvider, staterestore::StateRestorer},
|
bolts::{shmem::ShMemProvider, staterestore::StateRestorer},
|
||||||
@ -436,11 +445,31 @@ where
|
|||||||
// We start ourself as child process to actually fuzz
|
// We start ourself as child process to actually fuzz
|
||||||
let mut staterestorer = if std::env::var(_ENV_FUZZER_SENDER).is_err() {
|
let mut staterestorer = if std::env::var(_ENV_FUZZER_SENDER).is_err() {
|
||||||
// First, create a place to store state in, for restarts.
|
// First, create a place to store state in, for restarts.
|
||||||
let staterestorer: StateRestorer<SP> =
|
let mut staterestorer: StateRestorer<SP> =
|
||||||
StateRestorer::new(shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
StateRestorer::new(shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
||||||
//let staterestorer = { LlmpSender::new(shmem_provider.clone(), 0, false)? };
|
//let staterestorer = { LlmpSender::new(shmem_provider.clone(), 0, false)? };
|
||||||
staterestorer.write_to_env(_ENV_FUZZER_SENDER)?;
|
staterestorer.write_to_env(_ENV_FUZZER_SENDER)?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
unsafe {
|
||||||
|
let data = &mut SHUTDOWN_SIGHANDLER_DATA;
|
||||||
|
// Write the pointer to staterestorer so we can release its shmem later
|
||||||
|
write_volatile(
|
||||||
|
&mut data.staterestorer_ptr,
|
||||||
|
&mut staterestorer as *mut _ as *mut c_void,
|
||||||
|
);
|
||||||
|
data.allocator_pid = std::process::id() as usize;
|
||||||
|
data.shutdown_handler = shutdown_handler::<SP> as *const c_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We setup signal handlers to clean up shmem segments used by state restorer
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Err(_e) = unsafe { setup_signal_handler(&mut SHUTDOWN_SIGHANDLER_DATA) } {
|
||||||
|
// We can live without a proper ctrl+c signal handler. Print and ignore.
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
println!("Failed to setup signal handlers: {_e}");
|
||||||
|
}
|
||||||
|
|
||||||
let mut ctr: u64 = 0;
|
let mut ctr: u64 = 0;
|
||||||
// Client->parent loop
|
// Client->parent loop
|
||||||
loop {
|
loop {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user