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},
|
||||
};
|
||||
|
||||
#[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)]
|
||||
use crate::bolts::os::unix_signals::setup_signal_handler;
|
||||
#[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)]
|
||||
mod tests {
|
||||
use core::{marker::PhantomData, ptr};
|
||||
@ -706,6 +839,12 @@ mod tests {
|
||||
inputs::NopInput,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
use crate::{
|
||||
bolts::shmem::{ShMemProvider, StdShMemProvider},
|
||||
executors::InProcessForkExecutor,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_inmem_exec() {
|
||||
let mut harness = |_buf: &NopInput| ExitKind::Ok;
|
||||
@ -722,4 +861,22 @@ mod tests {
|
||||
.run_target(&mut (), &mut (), &mut (), &input)
|
||||
.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 use inprocess::InProcessExecutor;
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
pub use inprocess::InProcessForkExecutor;
|
||||
|
||||
pub mod timeout;
|
||||
pub use timeout::TimeoutExecutor;
|
||||
|
||||
|
@ -15,6 +15,8 @@ default = []
|
||||
libfuzzer = []
|
||||
sancov_pcguard_edges = []
|
||||
sancov_pcguard_hitcounts = []
|
||||
sancov_pcguard_edges_ptr = []
|
||||
sancov_pcguard_hitcounts_ptr = []
|
||||
sancov_value_profile = []
|
||||
sancov_cmplog = []
|
||||
sancov_pcguard = ["sancov_pcguard_hitcounts"]
|
||||
|
@ -1,8 +1,19 @@
|
||||
//! Coverage maps as static mut array
|
||||
|
||||
use crate::EDGES_MAP_SIZE;
|
||||
#[cfg(any(
|
||||
feature = "sancov_pcguard_edges_ptr",
|
||||
feature = "sancov_pcguard_hitcounts_ptr"
|
||||
))]
|
||||
use core::ptr;
|
||||
|
||||
/// The map for edges.
|
||||
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.
|
||||
pub static mut MAX_EDGES_NUM: usize = 0;
|
||||
|
@ -2,9 +2,19 @@
|
||||
|
||||
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;
|
||||
#[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::*;
|
||||
|
||||
#[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`.
|
||||
|
||||
#[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};
|
||||
|
||||
#[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(not(any(doc, feature = "clippy")))]
|
||||
compile_error!(
|
||||
@ -13,7 +27,12 @@ compile_error!(
|
||||
/// # Safety
|
||||
/// Dereferences `guard`, reads the position from there, then dereferences the [`EDGES_MAP`] at that position.
|
||||
/// 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]
|
||||
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
||||
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);
|
||||
*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`.
|
||||
///
|
||||
/// # Safety
|
||||
/// 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]
|
||||
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 {
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user