Better SigInt handler (#1710)
* fix simd * better exit * chg * more * more * use * change to proper name * w * aaaaaaa * delete * just separate them * shell check
This commit is contained in:
parent
210315da0f
commit
fad59987d9
78
.github/workflows/build_and_test.yml
vendored
78
.github/workflows/build_and_test.yml
vendored
@ -282,40 +282,84 @@ jobs:
|
|||||||
if: runner.os == 'macOS' # use bash v4
|
if: runner.os == 'macOS' # use bash v4
|
||||||
run: /usr/local/bin/bash -c 'RUN_ON_CI=1 ./scripts/test_all_fuzzers.sh'
|
run: /usr/local/bin/bash -c 'RUN_ON_CI=1 ./scripts/test_all_fuzzers.sh'
|
||||||
|
|
||||||
executions-check:
|
qemu_fuzzers:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: stable
|
toolchain: stable
|
||||||
- name: Fix python (macOS)
|
- name: Free Disk Space (Ubuntu)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'Linux'
|
||||||
run: rm /usr/local/bin/2to3* /usr/local/bin/idle3* /usr/local/bin/pydoc3* /usr/local/bin/python3*
|
uses: jlumbroso/free-disk-space@main
|
||||||
- name: Remove obsolete llvm (macOS)
|
with:
|
||||||
if: runner.os == 'macOS'
|
# this might remove tools that are actually needed,
|
||||||
run: brew remove --force llvm clang
|
# if set to "true" but frees about 6 GB
|
||||||
|
tool-cache: false
|
||||||
|
|
||||||
|
# all of these default to true, but feel free to set to
|
||||||
|
# "false" if necessary for your workflow
|
||||||
|
android: true
|
||||||
|
dotnet: true
|
||||||
|
haskell: true
|
||||||
|
large-packages: false
|
||||||
|
docker-images: true
|
||||||
|
swap-storage: true
|
||||||
|
- name: Add nightly rustfmt and clippy
|
||||||
|
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||||
|
- name: Add no_std toolchain
|
||||||
|
run: rustup toolchain install nightly-x86_64-unknown-linux-gnu ; rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
||||||
|
- name: Add wasm target
|
||||||
|
run: rustup target add wasm32-unknown-unknown
|
||||||
|
- name: Install ucd-generate
|
||||||
|
run: cargo install -f ucd-generate
|
||||||
- name: Remove obsolete llvm (Linux)
|
- name: Remove obsolete llvm (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: sudo apt purge llvm* clang*
|
run: sudo apt purge llvm* clang*
|
||||||
- uses: lyricwulf/abc@v1
|
- uses: lyricwulf/abc@v1
|
||||||
with:
|
with:
|
||||||
linux: llvm-15 llvm-15-dev clang-15
|
linux: llvm-15 llvm-15-dev clang-15 nasm ninja-build gcc-arm-linux-gnueabi g++-arm-linux-gnueabi gcc-aarch64-linux-gnu g++-aarch64-linux-gnu gcc-mipsel-linux-gnu g++-mipsel-linux-gnu gcc-powerpc-linux-gnu g++-powerpc-linux-gnu libc6-dev-i386-cross libc6-dev libc6-dev-i386 lib32gcc-11-dev lib32stdc++-11-dev libgtk-3-dev pax-utils libz3-dev
|
||||||
macos: python@3.11 llvm@15 bash coreutils
|
# update bash for macos to support `declare -A` command`
|
||||||
|
macos: llvm@15 libpng nasm coreutils z3 bash wget
|
||||||
|
- name: Set clang version
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-15 100
|
||||||
|
- name: Set clang++ version
|
||||||
|
if: runner.os == 'Linux'
|
||||||
|
run: sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-15 100
|
||||||
|
- name: pip install
|
||||||
|
run: python3 -m pip install msgpack jinja2 find_libpython
|
||||||
|
# Note that nproc needs to have coreutils installed on macOS, so the order of CI commands matters.
|
||||||
|
- name: enable mult-thread for `make`
|
||||||
|
run: export MAKEFLAGS="-j$(expr $(nproc) \+ 1)"
|
||||||
|
- name: install cargo-make
|
||||||
|
uses: baptiste0928/cargo-install@v1.3.0
|
||||||
|
with:
|
||||||
|
crate: cargo-make
|
||||||
|
- name: install wasm-pack
|
||||||
|
uses: baptiste0928/cargo-install@v1.3.0
|
||||||
|
with:
|
||||||
|
crate: wasm-pack
|
||||||
|
- name: install chrome
|
||||||
|
uses: browser-actions/setup-chrome@v1
|
||||||
|
with:
|
||||||
|
chrome-version: stable
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: true # recursively checkout submodules
|
submodules: true # recursively checkout submodules
|
||||||
fetch-depth: 0
|
fetch-depth: 0 # to diff with origin/main
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: Build and run libfuzzer_libpng (Linux)
|
- name: Symlink Headers
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: ./scripts/executions-check.sh
|
# We can't install gcc-multilib which would usually do this for us due to collisions with other packages
|
||||||
- name: Build and run libfuzzer_libpng (macOS)
|
run: sudo ln -s /usr/include/asm-generic /usr/include/asm
|
||||||
if: runner.os == 'macOS'
|
- name: Build and run example fuzzers (Linux)
|
||||||
run: /usr/local/bin/bash -c './scripts/executions-check.sh'
|
if: runner.os == 'Linux'
|
||||||
|
run: RUN_ON_CI=1 RUN_QEMU_FUZZER=1 LLVM_CONFIG=llvm-config-15 ./scripts/test_all_fuzzers.sh
|
||||||
|
|
||||||
|
|
||||||
nostd-build:
|
nostd-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
@ -44,7 +44,10 @@ use typed_builder::TypedBuilder;
|
|||||||
use crate::events::{CentralizedEventManager, CentralizedLlmpEventBroker};
|
use crate::events::{CentralizedEventManager, CentralizedLlmpEventBroker};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{EventConfig, LlmpRestartingEventManager, ManagerKind, RestartingMgr},
|
events::{
|
||||||
|
llmp::{LlmpRestartingEventManager, ManagerKind, RestartingMgr},
|
||||||
|
EventConfig,
|
||||||
|
},
|
||||||
monitors::Monitor,
|
monitors::Monitor,
|
||||||
state::{HasExecutions, State},
|
state::{HasExecutions, State},
|
||||||
Error,
|
Error,
|
||||||
|
@ -41,7 +41,7 @@ use typed_builder::TypedBuilder;
|
|||||||
|
|
||||||
use super::{CustomBufEventResult, CustomBufHandlerFn};
|
use super::{CustomBufEventResult, CustomBufHandlerFn};
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
use crate::events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA};
|
use crate::events::EVENTMGR_SIGHANDLER_STATE;
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{
|
events::{
|
||||||
BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId,
|
BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId,
|
||||||
@ -1155,6 +1155,19 @@ where
|
|||||||
S: State + HasExecutions,
|
S: State + HasExecutions,
|
||||||
MT: Monitor + Clone,
|
MT: Monitor + Clone,
|
||||||
{
|
{
|
||||||
|
/// Internal function, returns true when shuttdown is requested by a `SIGINT` signal
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
fn is_shutting_down() -> bool {
|
||||||
|
#[cfg(unix)]
|
||||||
|
unsafe {
|
||||||
|
core::ptr::read_volatile(core::ptr::addr_of!(EVENTMGR_SIGHANDLER_STATE.shutting_down))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Launch the restarting manager
|
/// Launch the restarting manager
|
||||||
pub fn launch(&mut self) -> Result<(Option<S>, LlmpRestartingEventManager<S, SP>), Error> {
|
pub fn launch(&mut self) -> Result<(Option<S>, LlmpRestartingEventManager<S, SP>), Error> {
|
||||||
// We start ourself as child process to actually fuzz
|
// We start ourself as child process to actually fuzz
|
||||||
@ -1235,7 +1248,7 @@ where
|
|||||||
|
|
||||||
// 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.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let mut staterestorer: StateRestorer<SP> =
|
let staterestorer: StateRestorer<SP> =
|
||||||
StateRestorer::new(self.shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
StateRestorer::new(self.shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
@ -1244,21 +1257,9 @@ where
|
|||||||
// 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
|
// We setup signal handlers to clean up shmem segments used by state restorer
|
||||||
#[cfg(all(unix, not(miri)))]
|
#[cfg(all(unix, not(miri)))]
|
||||||
if let Err(_e) = unsafe { setup_signal_handler(&mut SHUTDOWN_SIGHANDLER_DATA) } {
|
if let Err(_e) = unsafe { setup_signal_handler(&mut EVENTMGR_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.
|
||||||
log::error!("Failed to setup signal handlers: {_e}");
|
log::error!("Failed to setup signal handlers: {_e}");
|
||||||
}
|
}
|
||||||
@ -1305,7 +1306,7 @@ where
|
|||||||
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! This can happen if the child calls `exit()`, in that case make sure it uses `abort()`, if it got killed unrecoverable (OOM), or if there is a bug in the fuzzer itself. (Child exited with: {child_status})");
|
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! This can happen if the child calls `exit()`, in that case make sure it uses `abort()`, if it got killed unrecoverable (OOM), or if there is a bug in the fuzzer itself. (Child exited with: {child_status})");
|
||||||
}
|
}
|
||||||
|
|
||||||
if staterestorer.wants_to_exit() {
|
if staterestorer.wants_to_exit() || Self::is_shutting_down() {
|
||||||
return Err(Error::shutting_down());
|
return Err(Error::shutting_down());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1739,7 +1740,7 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::{Corpus, InMemoryCorpus, Testcase},
|
corpus::{Corpus, InMemoryCorpus, Testcase},
|
||||||
events::{llmp::_ENV_FUZZER_SENDER, LlmpEventManager},
|
events::llmp::{LlmpEventManager, _ENV_FUZZER_SENDER},
|
||||||
executors::{ExitKind, InProcessExecutor},
|
executors::{ExitKind, InProcessExecutor},
|
||||||
feedbacks::ConstFeedback,
|
feedbacks::ConstFeedback,
|
||||||
fuzzer::Fuzzer,
|
fuzzer::Fuzzer,
|
||||||
|
@ -18,8 +18,6 @@ pub mod tcp;
|
|||||||
#[cfg(feature = "scalability_introspection")]
|
#[cfg(feature = "scalability_introspection")]
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||||
#[cfg(all(unix, feature = "std"))]
|
|
||||||
use core::ffi::c_void;
|
|
||||||
use core::{
|
use core::{
|
||||||
fmt,
|
fmt,
|
||||||
hash::{BuildHasher, Hasher},
|
hash::{BuildHasher, Hasher},
|
||||||
@ -33,8 +31,6 @@ pub use launcher::*;
|
|||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
|
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
|
||||||
use libafl_bolts::{current_time, ClientId};
|
use libafl_bolts::{current_time, ClientId};
|
||||||
#[cfg(all(unix, feature = "std"))]
|
|
||||||
use libafl_bolts::{shmem::ShMemProvider, staterestore::StateRestorer};
|
|
||||||
pub use llmp::*;
|
pub use llmp::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -58,10 +54,8 @@ use crate::{
|
|||||||
|
|
||||||
/// Check if ctrl-c is sent with this struct
|
/// Check if ctrl-c is sent with this struct
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
pub static mut SHUTDOWN_SIGHANDLER_DATA: ShutdownSignalData = ShutdownSignalData {
|
pub static mut EVENTMGR_SIGHANDLER_STATE: ShutdownSignalData = ShutdownSignalData {
|
||||||
allocator_pid: 0,
|
shutting_down: false,
|
||||||
staterestorer_ptr: core::ptr::null_mut(),
|
|
||||||
shutdown_handler: core::ptr::null(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A signal handler for releasing `StateRestore` `ShMem`
|
/// A signal handler for releasing `StateRestore` `ShMem`
|
||||||
@ -69,60 +63,21 @@ pub static mut SHUTDOWN_SIGHANDLER_DATA: ShutdownSignalData = ShutdownSignalData
|
|||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ShutdownSignalData {
|
pub struct ShutdownSignalData {
|
||||||
allocator_pid: usize,
|
shutting_down: bool,
|
||||||
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, &mut siginfo_t, Option<&mut ucontext_t>, data: &mut ShutdownSignalData);
|
|
||||||
|
|
||||||
/// Shutdown handler. `SigTerm`, `SigInterrupt`, `SigQuit` call this
|
/// 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
|
/// 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
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// This will acceess `data` and write to the global `data.staterestorer_ptr` if it's not null.
|
|
||||||
#[cfg(all(unix, feature = "std"))]
|
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
|
||||||
pub unsafe fn shutdown_handler<SP>(
|
|
||||||
signal: Signal,
|
|
||||||
_info: &mut siginfo_t,
|
|
||||||
_context: Option<&mut ucontext_t>,
|
|
||||||
data: &ShutdownSignalData,
|
|
||||||
) where
|
|
||||||
SP: ShMemProvider,
|
|
||||||
{
|
|
||||||
log::info!(
|
|
||||||
"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();
|
|
||||||
// log::trace!("{:#?}", sr);
|
|
||||||
std::ptr::drop_in_place(sr);
|
|
||||||
}
|
|
||||||
log::info!("Bye!");
|
|
||||||
libc::_exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
impl Handler for ShutdownSignalData {
|
impl Handler for ShutdownSignalData {
|
||||||
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: Option<&mut ucontext_t>) {
|
fn handle(
|
||||||
|
&mut self,
|
||||||
|
_signal: Signal,
|
||||||
|
_info: &mut siginfo_t,
|
||||||
|
_context: Option<&mut ucontext_t>,
|
||||||
|
) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = &mut SHUTDOWN_SIGHANDLER_DATA;
|
core::ptr::write_volatile(core::ptr::addr_of_mut!(self.shutting_down), true);
|
||||||
if !data.shutdown_handler.is_null() {
|
|
||||||
let func: ShutdownFuncPtr = std::mem::transmute(data.shutdown_handler);
|
|
||||||
(func)(signal, info, context, data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,6 @@ 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;
|
|
||||||
use core::{fmt::Debug, marker::PhantomData};
|
use core::{fmt::Debug, marker::PhantomData};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use core::{
|
use core::{
|
||||||
@ -30,7 +26,7 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||||||
|
|
||||||
use super::{CustomBufEventResult, CustomBufHandlerFn, HasCustomBufHandlers, ProgressReporter};
|
use super::{CustomBufEventResult, CustomBufHandlerFn, HasCustomBufHandlers, ProgressReporter};
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
use crate::events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA};
|
use crate::events::EVENTMGR_SIGHANDLER_STATE;
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{
|
events::{
|
||||||
BrokerEventResult, Event, EventFirer, EventManager, EventManagerId, EventProcessor,
|
BrokerEventResult, Event, EventFirer, EventManager, EventManagerId, EventProcessor,
|
||||||
@ -450,6 +446,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal function, returns true when shuttdown is requested by a `SIGINT` signal
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
fn is_shutting_down() -> bool {
|
||||||
|
#[cfg(unix)]
|
||||||
|
unsafe {
|
||||||
|
core::ptr::read_volatile(core::ptr::addr_of!(EVENTMGR_SIGHANDLER_STATE.shutting_down))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Launch the simple restarting manager.
|
/// Launch the simple restarting manager.
|
||||||
/// This [`EventManager`] is simple and single threaded,
|
/// This [`EventManager`] is simple and single threaded,
|
||||||
/// but can still used shared maps to recover from crashes and timeouts.
|
/// but can still used shared maps to recover from crashes and timeouts.
|
||||||
@ -463,7 +472,7 @@ where
|
|||||||
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.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let mut staterestorer: StateRestorer<SP> =
|
let staterestorer: StateRestorer<SP> =
|
||||||
StateRestorer::new(shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
StateRestorer::new(shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
let staterestorer: StateRestorer<SP> =
|
let staterestorer: StateRestorer<SP> =
|
||||||
@ -472,21 +481,9 @@ where
|
|||||||
//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
|
// We setup signal handlers to clean up shmem segments used by state restorer
|
||||||
#[cfg(all(unix, not(miri)))]
|
#[cfg(all(unix, not(miri)))]
|
||||||
if let Err(_e) = unsafe { setup_signal_handler(&mut SHUTDOWN_SIGHANDLER_DATA) } {
|
if let Err(_e) = unsafe { setup_signal_handler(&mut EVENTMGR_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.
|
||||||
log::error!("Failed to setup signal handlers: {_e}");
|
log::error!("Failed to setup signal handlers: {_e}");
|
||||||
}
|
}
|
||||||
@ -520,7 +517,7 @@ where
|
|||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
if staterestorer.wants_to_exit() {
|
if staterestorer.wants_to_exit() || Self::is_shutting_down() {
|
||||||
return Err(Error::shutting_down());
|
return Err(Error::shutting_down());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ use typed_builder::TypedBuilder;
|
|||||||
|
|
||||||
use super::{CustomBufEventResult, CustomBufHandlerFn};
|
use super::{CustomBufEventResult, CustomBufHandlerFn};
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
use crate::events::{shutdown_handler, SHUTDOWN_SIGHANDLER_DATA};
|
use crate::events::EVENTMGR_SIGHANDLER_STATE;
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{
|
events::{
|
||||||
BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId,
|
BrokerEventResult, Event, EventConfig, EventFirer, EventManager, EventManagerId,
|
||||||
@ -953,7 +953,7 @@ where
|
|||||||
/// The kind of manager we're creating right now
|
/// The kind of manager we're creating right now
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ManagerKind {
|
pub enum TcpManagerKind {
|
||||||
/// Any kind will do
|
/// Any kind will do
|
||||||
Any,
|
Any,
|
||||||
/// A client, getting messages from a local broker.
|
/// A client, getting messages from a local broker.
|
||||||
@ -979,7 +979,7 @@ where
|
|||||||
MT: Monitor + Clone,
|
MT: Monitor + Clone,
|
||||||
S: State + HasExecutions,
|
S: State + HasExecutions,
|
||||||
{
|
{
|
||||||
RestartingMgr::builder()
|
TcpRestartingMgr::builder()
|
||||||
.shmem_provider(StdShMemProvider::new()?)
|
.shmem_provider(StdShMemProvider::new()?)
|
||||||
.monitor(Some(monitor))
|
.monitor(Some(monitor))
|
||||||
.broker_port(broker_port)
|
.broker_port(broker_port)
|
||||||
@ -988,13 +988,13 @@ where
|
|||||||
.launch()
|
.launch()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides a `builder` which can be used to build a [`RestartingMgr`], which is a combination of a
|
/// Provides a `builder` which can be used to build a [`TcpRestartingMgr`], which is a combination of a
|
||||||
/// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The
|
/// `restarter` and `runner`, that can be used on systems both with and without `fork` support. The
|
||||||
/// `restarter` will start a new process each time the child crashes or times out.
|
/// `restarter` will start a new process each time the child crashes or times out.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[allow(clippy::default_trait_access, clippy::ignored_unit_patterns)]
|
#[allow(clippy::default_trait_access, clippy::ignored_unit_patterns)]
|
||||||
#[derive(TypedBuilder, Debug)]
|
#[derive(TypedBuilder, Debug)]
|
||||||
pub struct RestartingMgr<MT, S, SP>
|
pub struct TcpRestartingMgr<MT, S, SP>
|
||||||
where
|
where
|
||||||
S: UsesInput + DeserializeOwned,
|
S: UsesInput + DeserializeOwned,
|
||||||
SP: ShMemProvider + 'static,
|
SP: ShMemProvider + 'static,
|
||||||
@ -1016,8 +1016,8 @@ where
|
|||||||
#[builder(default = None)]
|
#[builder(default = None)]
|
||||||
remote_broker_addr: Option<SocketAddr>,
|
remote_broker_addr: Option<SocketAddr>,
|
||||||
/// The type of manager to build
|
/// The type of manager to build
|
||||||
#[builder(default = ManagerKind::Any)]
|
#[builder(default = TcpManagerKind::Any)]
|
||||||
kind: ManagerKind,
|
kind: TcpManagerKind,
|
||||||
/// The amount of external clients that should have connected (not counting our own tcp client)
|
/// The amount of external clients that should have connected (not counting our own tcp client)
|
||||||
/// before this broker quits _after the last client exited_.
|
/// before this broker quits _after the last client exited_.
|
||||||
/// If `None`, the broker will never quit when the last client exits, but run forever.
|
/// If `None`, the broker will never quit when the last client exits, but run forever.
|
||||||
@ -1035,12 +1035,21 @@ where
|
|||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[allow(clippy::type_complexity, clippy::too_many_lines)]
|
#[allow(clippy::type_complexity, clippy::too_many_lines)]
|
||||||
impl<MT, S, SP> RestartingMgr<MT, S, SP>
|
impl<MT, S, SP> TcpRestartingMgr<MT, S, SP>
|
||||||
where
|
where
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
S: State + HasExecutions,
|
S: State + HasExecutions,
|
||||||
MT: Monitor + Clone,
|
MT: Monitor + Clone,
|
||||||
{
|
{
|
||||||
|
/// Internal function, returns true when shuttdown is requested by a `SIGINT` signal
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
fn is_shutting_down() -> bool {
|
||||||
|
unsafe {
|
||||||
|
core::ptr::read_volatile(core::ptr::addr_of!(EVENTMGR_SIGHANDLER_STATE.shutting_down))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Launch the restarting manager
|
/// Launch the restarting manager
|
||||||
pub fn launch(&mut self) -> Result<(Option<S>, TcpRestartingEventManager<S, SP>), Error> {
|
pub fn launch(&mut self) -> Result<(Option<S>, TcpRestartingEventManager<S, SP>), Error> {
|
||||||
// We start ourself as child process to actually fuzz
|
// We start ourself as child process to actually fuzz
|
||||||
@ -1057,7 +1066,7 @@ where
|
|||||||
|
|
||||||
// We get here if we are on Unix, or we are a broker on Windows (or without forks).
|
// We get here if we are on Unix, or we are a broker on Windows (or without forks).
|
||||||
let (mgr, core_id) = match self.kind {
|
let (mgr, core_id) = match self.kind {
|
||||||
ManagerKind::Any => {
|
TcpManagerKind::Any => {
|
||||||
let connection = create_nonblocking_listener(("127.0.0.1", self.broker_port));
|
let connection = create_nonblocking_listener(("127.0.0.1", self.broker_port));
|
||||||
match connection {
|
match connection {
|
||||||
Ok(listener) => {
|
Ok(listener) => {
|
||||||
@ -1088,7 +1097,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ManagerKind::Broker => {
|
TcpManagerKind::Broker => {
|
||||||
let event_broker = TcpEventBroker::<S::Input, MT>::new(
|
let event_broker = TcpEventBroker::<S::Input, MT>::new(
|
||||||
format!("127.0.0.1:{}", self.broker_port),
|
format!("127.0.0.1:{}", self.broker_port),
|
||||||
self.monitor.take().unwrap(),
|
self.monitor.take().unwrap(),
|
||||||
@ -1097,7 +1106,7 @@ where
|
|||||||
broker_things(event_broker, self.remote_broker_addr)?;
|
broker_things(event_broker, self.remote_broker_addr)?;
|
||||||
unreachable!("The broker may never return normally, only on errors or when shutting down.");
|
unreachable!("The broker may never return normally, only on errors or when shutting down.");
|
||||||
}
|
}
|
||||||
ManagerKind::Client { cpu_core } => {
|
TcpManagerKind::Client { cpu_core } => {
|
||||||
// We are a client
|
// We are a client
|
||||||
let mgr = TcpEventManager::<S>::on_port(self.broker_port, self.configuration)?;
|
let mgr = TcpEventManager::<S>::on_port(self.broker_port, self.configuration)?;
|
||||||
|
|
||||||
@ -1116,7 +1125,7 @@ where
|
|||||||
|
|
||||||
// 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.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let mut staterestorer: StateRestorer<SP> =
|
let staterestorer: StateRestorer<SP> =
|
||||||
StateRestorer::new(self.shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
StateRestorer::new(self.shmem_provider.new_shmem(256 * 1024 * 1024)?);
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
@ -1125,21 +1134,9 @@ where
|
|||||||
// 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
|
// We setup signal handlers to clean up shmem segments used by state restorer
|
||||||
#[cfg(all(unix, not(miri)))]
|
#[cfg(all(unix, not(miri)))]
|
||||||
if let Err(_e) = unsafe { setup_signal_handler(&mut SHUTDOWN_SIGHANDLER_DATA) } {
|
if let Err(_e) = unsafe { setup_signal_handler(&mut EVENTMGR_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.
|
||||||
log::error!("Failed to setup signal handlers: {_e}");
|
log::error!("Failed to setup signal handlers: {_e}");
|
||||||
}
|
}
|
||||||
@ -1187,7 +1184,7 @@ where
|
|||||||
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! This can happen if the child calls `exit()`, in that case make sure it uses `abort()`, if it got killed unrecoverable (OOM), or if there is a bug in the fuzzer itself. (Child exited with: {child_status})");
|
panic!("Fuzzer-respawner: Storing state in crashed fuzzer instance did not work, no point to spawn the next client! This can happen if the child calls `exit()`, in that case make sure it uses `abort()`, if it got killed unrecoverable (OOM), or if there is a bug in the fuzzer itself. (Child exited with: {child_status})");
|
||||||
}
|
}
|
||||||
|
|
||||||
if staterestorer.wants_to_exit() {
|
if staterestorer.wants_to_exit() || Self::is_shutting_down() {
|
||||||
return Err(Error::shutting_down());
|
return Err(Error::shutting_down());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1977,7 +1977,7 @@ impl Handler for LlmpShutdownSignalHandler {
|
|||||||
_context: Option<&mut ucontext_t>,
|
_context: Option<&mut ucontext_t>,
|
||||||
) {
|
) {
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::write_volatile(&mut self.shutting_down, true);
|
ptr::write_volatile(ptr::addr_of_mut!(self.shutting_down), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2245,7 +2245,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(&LLMP_SIGHANDLER_STATE.shutting_down) }
|
unsafe { ptr::read_volatile(ptr::addr_of!(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
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
install_libpng() {
|
|
||||||
cd ./fuzzers/libfuzzer_libpng && wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
|
|
||||||
tar -xvf libpng-1.6.37.tar.xz || echo "Failed to download libpng"
|
|
||||||
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes && cd ..
|
|
||||||
}
|
|
||||||
|
|
||||||
build_libpng(){
|
|
||||||
cargo build --release || echo "ERROR: Failed to build libfuzzer_libpng"
|
|
||||||
|
|
||||||
cd libpng-1.6.37 && make CC="$(pwd)/../target/release/libafl_cc" CXX="$(pwd)/../target/release/ libafl_cxx" -j "$(nproc)" && cd ..
|
|
||||||
}
|
|
||||||
|
|
||||||
git_checkout(){
|
|
||||||
git reset --hard HEAD^
|
|
||||||
}
|
|
||||||
|
|
||||||
build_run_fuzzer(){
|
|
||||||
./target/release/libafl_cxx ./harness.cc libpng-1.6.37/.libs/libpng16.a -I libpng-1.6.37/ -o fuzzer_libpng -lz -lm || exit 2
|
|
||||||
|
|
||||||
./fuzzer_libpng > log.txt &
|
|
||||||
|
|
||||||
# wait that fuzzer_libpng become the broker
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
timeout 5m ./fuzzer_libpng > /dev/null 2>&1 &
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
if grep -q "Broker" log.txt ; then
|
|
||||||
pkill -9 "fuzzer_libpng"
|
|
||||||
executions=$(grep -m 1 "Broker" log.txt | awk '{print $14}')
|
|
||||||
rm -rf ./libafl_unix_shmem_server
|
|
||||||
echo "${executions%,}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
main(){
|
|
||||||
install_libpng
|
|
||||||
|
|
||||||
build_libpng
|
|
||||||
echo "start to run the new fuzzer"
|
|
||||||
new_executions=$(build_run_fuzzer)
|
|
||||||
|
|
||||||
git_checkout
|
|
||||||
|
|
||||||
build_libpng
|
|
||||||
echo "start to run the last fuzzer"
|
|
||||||
last_executions=$(build_run_fuzzer)
|
|
||||||
|
|
||||||
echo "the execution count of the new fuzzer is $new_executions"
|
|
||||||
echo "the execution count of the last fuzzer is $last_executions"
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
@ -15,6 +15,19 @@ else
|
|||||||
export PROFILE_DIR=debug
|
export PROFILE_DIR=debug
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [[ -z "${RUN_ON_CI}" ]]; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
if [[ -z "${RUN_QEMU_FUZZER}" ]]; then
|
||||||
|
fuzzers=$(echo "$fuzzers" | tr ' ' '\n' | grep -v "qemu")
|
||||||
|
backtrace_fuzzers=$(echo "$backtrace_fuzzers" | tr ' ' '\n' | grep "qemu")
|
||||||
|
else
|
||||||
|
fuzzers=$(echo "$fuzzers" | tr ' ' '\n' | grep "qemu")
|
||||||
|
backtrace_fuzzers=$(echo "$backtrace_fuzzers" | tr ' ' '\n' | grep -v "qemu")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
libafl=$(pwd)
|
libafl=$(pwd)
|
||||||
|
|
||||||
# build with a shared target dir for all fuzzers. this should speed up
|
# build with a shared target dir for all fuzzers. this should speed up
|
||||||
|
Loading…
x
Reference in New Issue
Block a user