inprocessfork executor (#237)
* inprocessfork executor * fmt * cfg * no_std * no volatile rw * wrapping_add * fix * mutable pointer * ptr initialization in __sanitizer_cov_trace_pc_guard_init * features * more cfg * fmt * fix * fmt * post_fork * fmt * pre_fork * test * cfg
This commit is contained in:
parent
18abf8f78a
commit
7f4e341741
@ -9,6 +9,15 @@ use core::{
|
|||||||
sync::atomic::{compiler_fence, Ordering},
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
use nix::{
|
||||||
|
sys::wait::{waitpid, WaitStatus},
|
||||||
|
unistd::{fork, ForkResult},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
use crate::bolts::shmem::ShMemProvider;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use crate::bolts::os::unix_signals::setup_signal_handler;
|
use crate::bolts::os::unix_signals::setup_signal_handler;
|
||||||
#[cfg(all(windows, feature = "std"))]
|
#[cfg(all(windows, feature = "std"))]
|
||||||
@ -696,6 +705,130 @@ mod windows_exception_handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
pub struct InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&I) -> ExitKind,
|
||||||
|
I: Input,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
harness_fn: &'a mut H,
|
||||||
|
shmem_provider: SP,
|
||||||
|
observers: OT,
|
||||||
|
phantom: PhantomData<(I, S)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
impl<'a, EM, H, I, OT, S, Z, SP> Executor<EM, I, S, Z>
|
||||||
|
for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&I) -> ExitKind,
|
||||||
|
I: Input,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
#[inline]
|
||||||
|
fn run_target(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
) -> Result<ExitKind, Error> {
|
||||||
|
unsafe {
|
||||||
|
self.shmem_provider.pre_fork()?;
|
||||||
|
match fork() {
|
||||||
|
Ok(ForkResult::Child) => {
|
||||||
|
// Child
|
||||||
|
self.shmem_provider.post_fork(true)?;
|
||||||
|
|
||||||
|
(self.harness_fn)(input);
|
||||||
|
|
||||||
|
std::process::exit(0);
|
||||||
|
|
||||||
|
Ok(ExitKind::Ok)
|
||||||
|
}
|
||||||
|
Ok(ForkResult::Parent { child }) => {
|
||||||
|
// Parent
|
||||||
|
self.shmem_provider.post_fork(false)?;
|
||||||
|
|
||||||
|
let res = waitpid(child, None)?;
|
||||||
|
match res {
|
||||||
|
WaitStatus::Signaled(_, _, _) => Ok(ExitKind::Crash),
|
||||||
|
_ => Ok(ExitKind::Ok),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Err(Error::from(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&I) -> ExitKind,
|
||||||
|
I: Input,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
pub fn new<EM, OC, OF, Z>(
|
||||||
|
harness_fn: &'a mut H,
|
||||||
|
observers: OT,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_event_mgr: &mut EM,
|
||||||
|
shmem_provider: SP,
|
||||||
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I, S> + EventRestarter<S>,
|
||||||
|
OC: Corpus<I>,
|
||||||
|
OF: Feedback<I, S>,
|
||||||
|
S: HasSolutions<OC, I> + HasClientPerfStats,
|
||||||
|
Z: HasObjective<I, OF, S>,
|
||||||
|
{
|
||||||
|
Ok(Self {
|
||||||
|
harness_fn,
|
||||||
|
shmem_provider,
|
||||||
|
observers,
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the harness function.
|
||||||
|
#[inline]
|
||||||
|
pub fn harness(&self) -> &H {
|
||||||
|
self.harness_fn
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the harness function for a mutable reference.
|
||||||
|
#[inline]
|
||||||
|
pub fn harness_mut(&mut self) -> &mut H {
|
||||||
|
self.harness_fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> for InProcessForkExecutor<'a, H, I, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&I) -> ExitKind,
|
||||||
|
I: Input,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn observers(&self) -> &OT {
|
||||||
|
&self.observers
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn observers_mut(&mut self) -> &mut OT {
|
||||||
|
&mut self.observers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::{marker::PhantomData, ptr};
|
use core::{marker::PhantomData, ptr};
|
||||||
@ -706,6 +839,12 @@ mod tests {
|
|||||||
inputs::NopInput,
|
inputs::NopInput,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
use crate::{
|
||||||
|
bolts::shmem::{ShMemProvider, StdShMemProvider},
|
||||||
|
executors::InProcessForkExecutor,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_inmem_exec() {
|
fn test_inmem_exec() {
|
||||||
let mut harness = |_buf: &NopInput| ExitKind::Ok;
|
let mut harness = |_buf: &NopInput| ExitKind::Ok;
|
||||||
@ -722,4 +861,22 @@ mod tests {
|
|||||||
.run_target(&mut (), &mut (), &mut (), &input)
|
.run_target(&mut (), &mut (), &mut (), &input)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
fn test_inprocessfork_exec() {
|
||||||
|
let provider = StdShMemProvider::new().unwrap();
|
||||||
|
|
||||||
|
let mut harness = |_buf: &NopInput| ExitKind::Ok;
|
||||||
|
let mut in_process_fork_executor = InProcessForkExecutor::<_, NopInput, (), (), _> {
|
||||||
|
harness_fn: &mut harness,
|
||||||
|
shmem_provider: provider,
|
||||||
|
observers: tuple_list!(),
|
||||||
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
let input = NopInput {};
|
||||||
|
assert!(in_process_fork_executor
|
||||||
|
.run_target(&mut (), &mut (), &mut (), &input)
|
||||||
|
.is_ok());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
pub mod inprocess;
|
pub mod inprocess;
|
||||||
pub use inprocess::InProcessExecutor;
|
pub use inprocess::InProcessExecutor;
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
pub use inprocess::InProcessForkExecutor;
|
||||||
|
|
||||||
pub mod timeout;
|
pub mod timeout;
|
||||||
pub use timeout::TimeoutExecutor;
|
pub use timeout::TimeoutExecutor;
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ default = []
|
|||||||
libfuzzer = []
|
libfuzzer = []
|
||||||
sancov_pcguard_edges = []
|
sancov_pcguard_edges = []
|
||||||
sancov_pcguard_hitcounts = []
|
sancov_pcguard_hitcounts = []
|
||||||
|
sancov_pcguard_edges_ptr = []
|
||||||
|
sancov_pcguard_hitcounts_ptr = []
|
||||||
sancov_value_profile = []
|
sancov_value_profile = []
|
||||||
sancov_cmplog = []
|
sancov_cmplog = []
|
||||||
sancov_pcguard = ["sancov_pcguard_hitcounts"]
|
sancov_pcguard = ["sancov_pcguard_hitcounts"]
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
//! Coverage maps as static mut array
|
//! Coverage maps as static mut array
|
||||||
|
|
||||||
use crate::EDGES_MAP_SIZE;
|
use crate::EDGES_MAP_SIZE;
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
/// The map for edges.
|
/// The map for edges.
|
||||||
pub static mut EDGES_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
pub static mut EDGES_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
|
pub static mut EDGES_MAP_PTR: *mut u8 = ptr::null_mut();
|
||||||
|
|
||||||
/// The max count of edges tracked.
|
/// The max count of edges tracked.
|
||||||
pub static mut MAX_EDGES_NUM: usize = 0;
|
pub static mut MAX_EDGES_NUM: usize = 0;
|
||||||
|
@ -2,9 +2,19 @@
|
|||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
|
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
|
||||||
|
|
||||||
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges",
|
||||||
|
feature = "sancov_pcguard_hitcounts",
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
pub mod sancov_pcguard;
|
pub mod sancov_pcguard;
|
||||||
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges",
|
||||||
|
feature = "sancov_pcguard_hitcounts",
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
pub use sancov_pcguard::*;
|
pub use sancov_pcguard::*;
|
||||||
|
|
||||||
#[cfg(any(feature = "sancov_cmplog", feature = "sancov_value_profile"))]
|
#[cfg(any(feature = "sancov_cmplog", feature = "sancov_value_profile"))]
|
||||||
|
@ -1,7 +1,21 @@
|
|||||||
//! [`LLVM` `PcGuard`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`.
|
//! [`LLVM` `PcGuard`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`.
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
|
use crate::coverage::EDGES_MAP_PTR;
|
||||||
use crate::coverage::{EDGES_MAP, MAX_EDGES_NUM};
|
use crate::coverage::{EDGES_MAP, MAX_EDGES_NUM};
|
||||||
|
|
||||||
|
#[cfg(all(
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
|
#[cfg(not(any(doc, feature = "clippy")))]
|
||||||
|
compile_error!(
|
||||||
|
"the libafl_targets `pcguard_edges_ptr` and `pcguard_hitcounts_ptr` features are mutually exclusive."
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
#[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
||||||
#[cfg(not(any(doc, feature = "clippy")))]
|
#[cfg(not(any(doc, feature = "clippy")))]
|
||||||
compile_error!(
|
compile_error!(
|
||||||
@ -13,7 +27,12 @@ compile_error!(
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
/// Dereferences `guard`, reads the position from there, then dereferences the [`EDGES_MAP`] at that position.
|
/// Dereferences `guard`, reads the position from there, then dereferences the [`EDGES_MAP`] at that position.
|
||||||
/// Should usually not be called directly.
|
/// Should usually not be called directly.
|
||||||
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges",
|
||||||
|
feature = "sancov_pcguard_hitcounts",
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
||||||
let pos = *guard as usize;
|
let pos = *guard as usize;
|
||||||
@ -26,15 +45,38 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
|||||||
let val = (*EDGES_MAP.get_unchecked(pos) as u8).wrapping_add(1);
|
let val = (*EDGES_MAP.get_unchecked(pos) as u8).wrapping_add(1);
|
||||||
*EDGES_MAP.get_unchecked_mut(pos) = val;
|
*EDGES_MAP.get_unchecked_mut(pos) = val;
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "sancov_pcguard_edges_ptr")]
|
||||||
|
{
|
||||||
|
(EDGES_MAP_PTR as *mut u8).add(pos).write(1);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "sancov_pcguard_hitcounts_ptr")]
|
||||||
|
{
|
||||||
|
let addr = (EDGES_MAP_PTR as *mut u8).add(pos);
|
||||||
|
let val = addr.read().wrapping_add(1);
|
||||||
|
addr.write(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the sancov `pc_guard` - usually called by `llvm`.
|
/// Initialize the sancov `pc_guard` - usually called by `llvm`.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Dereferences at `start` and writes to it.
|
/// Dereferences at `start` and writes to it.
|
||||||
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges",
|
||||||
|
feature = "sancov_pcguard_hitcounts",
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
|
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "sancov_pcguard_edges_ptr",
|
||||||
|
feature = "sancov_pcguard_hitcounts_ptr"
|
||||||
|
))]
|
||||||
|
if EDGES_MAP_PTR.is_null() {
|
||||||
|
EDGES_MAP_PTR = EDGES_MAP.as_mut_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
if start == stop || *start != 0 {
|
if start == stop || *start != 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user