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:
Toka 2021-08-07 19:09:54 +09:00 committed by GitHub
parent 18abf8f78a
commit 7f4e341741
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 229 additions and 4 deletions

View File

@ -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());
}
} }

View File

@ -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;

View File

@ -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"]

View File

@ -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;

View File

@ -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"))]

View File

@ -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;
} }