Skip to content

Commit 7f4e341

Browse files
authored
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
1 parent 18abf8f commit 7f4e341

File tree

6 files changed

+229
-4
lines changed

6 files changed

+229
-4
lines changed

libafl/src/executors/inprocess.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ use core::{
99
sync::atomic::{compiler_fence, Ordering},
1010
};
1111

12+
#[cfg(all(feature = "std", unix))]
13+
use nix::{
14+
sys::wait::{waitpid, WaitStatus},
15+
unistd::{fork, ForkResult},
16+
};
17+
18+
#[cfg(all(feature = "std", unix))]
19+
use crate::bolts::shmem::ShMemProvider;
20+
1221
#[cfg(unix)]
1322
use crate::bolts::os::unix_signals::setup_signal_handler;
1423
#[cfg(all(windows, feature = "std"))]
@@ -696,6 +705,130 @@ mod windows_exception_handler {
696705
}
697706
}
698707

708+
#[cfg(all(feature = "std", unix))]
709+
pub struct InProcessForkExecutor<'a, H, I, OT, S, SP>
710+
where
711+
H: FnMut(&I) -> ExitKind,
712+
I: Input,
713+
OT: ObserversTuple<I, S>,
714+
SP: ShMemProvider,
715+
{
716+
harness_fn: &'a mut H,
717+
shmem_provider: SP,
718+
observers: OT,
719+
phantom: PhantomData<(I, S)>,
720+
}
721+
722+
#[cfg(all(feature = "std", unix))]
723+
impl<'a, EM, H, I, OT, S, Z, SP> Executor<EM, I, S, Z>
724+
for InProcessForkExecutor<'a, H, I, OT, S, SP>
725+
where
726+
H: FnMut(&I) -> ExitKind,
727+
I: Input,
728+
OT: ObserversTuple<I, S>,
729+
SP: ShMemProvider,
730+
{
731+
#[allow(unreachable_code)]
732+
#[inline]
733+
fn run_target(
734+
&mut self,
735+
_fuzzer: &mut Z,
736+
_state: &mut S,
737+
_mgr: &mut EM,
738+
input: &I,
739+
) -> Result<ExitKind, Error> {
740+
unsafe {
741+
self.shmem_provider.pre_fork()?;
742+
match fork() {
743+
Ok(ForkResult::Child) => {
744+
// Child
745+
self.shmem_provider.post_fork(true)?;
746+
747+
(self.harness_fn)(input);
748+
749+
std::process::exit(0);
750+
751+
Ok(ExitKind::Ok)
752+
}
753+
Ok(ForkResult::Parent { child }) => {
754+
// Parent
755+
self.shmem_provider.post_fork(false)?;
756+
757+
let res = waitpid(child, None)?;
758+
match res {
759+
WaitStatus::Signaled(_, _, _) => Ok(ExitKind::Crash),
760+
_ => Ok(ExitKind::Ok),
761+
}
762+
}
763+
Err(e) => Err(Error::from(e)),
764+
}
765+
}
766+
}
767+
}
768+
769+
#[cfg(all(feature = "std", unix))]
770+
impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP>
771+
where
772+
H: FnMut(&I) -> ExitKind,
773+
I: Input,
774+
OT: ObserversTuple<I, S>,
775+
SP: ShMemProvider,
776+
{
777+
pub fn new<EM, OC, OF, Z>(
778+
harness_fn: &'a mut H,
779+
observers: OT,
780+
_fuzzer: &mut Z,
781+
_state: &mut S,
782+
_event_mgr: &mut EM,
783+
shmem_provider: SP,
784+
) -> Result<Self, Error>
785+
where
786+
EM: EventFirer<I, S> + EventRestarter<S>,
787+
OC: Corpus<I>,
788+
OF: Feedback<I, S>,
789+
S: HasSolutions<OC, I> + HasClientPerfStats,
790+
Z: HasObjective<I, OF, S>,
791+
{
792+
Ok(Self {
793+
harness_fn,
794+
shmem_provider,
795+
observers,
796+
phantom: PhantomData,
797+
})
798+
}
799+
800+
/// Retrieve the harness function.
801+
#[inline]
802+
pub fn harness(&self) -> &H {
803+
self.harness_fn
804+
}
805+
806+
/// Retrieve the harness function for a mutable reference.
807+
#[inline]
808+
pub fn harness_mut(&mut self) -> &mut H {
809+
self.harness_fn
810+
}
811+
}
812+
813+
#[cfg(all(feature = "std", unix))]
814+
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> for InProcessForkExecutor<'a, H, I, OT, S, SP>
815+
where
816+
H: FnMut(&I) -> ExitKind,
817+
I: Input,
818+
OT: ObserversTuple<I, S>,
819+
SP: ShMemProvider,
820+
{
821+
#[inline]
822+
fn observers(&self) -> &OT {
823+
&self.observers
824+
}
825+
826+
#[inline]
827+
fn observers_mut(&mut self) -> &mut OT {
828+
&mut self.observers
829+
}
830+
}
831+
699832
#[cfg(test)]
700833
mod tests {
701834
use core::{marker::PhantomData, ptr};
@@ -706,6 +839,12 @@ mod tests {
706839
inputs::NopInput,
707840
};
708841

842+
#[cfg(all(feature = "std", unix))]
843+
use crate::{
844+
bolts::shmem::{ShMemProvider, StdShMemProvider},
845+
executors::InProcessForkExecutor,
846+
};
847+
709848
#[test]
710849
fn test_inmem_exec() {
711850
let mut harness = |_buf: &NopInput| ExitKind::Ok;
@@ -722,4 +861,22 @@ mod tests {
722861
.run_target(&mut (), &mut (), &mut (), &input)
723862
.is_ok());
724863
}
864+
865+
#[test]
866+
#[cfg(all(feature = "std", unix))]
867+
fn test_inprocessfork_exec() {
868+
let provider = StdShMemProvider::new().unwrap();
869+
870+
let mut harness = |_buf: &NopInput| ExitKind::Ok;
871+
let mut in_process_fork_executor = InProcessForkExecutor::<_, NopInput, (), (), _> {
872+
harness_fn: &mut harness,
873+
shmem_provider: provider,
874+
observers: tuple_list!(),
875+
phantom: PhantomData,
876+
};
877+
let input = NopInput {};
878+
assert!(in_process_fork_executor
879+
.run_target(&mut (), &mut (), &mut (), &input)
880+
.is_ok());
881+
}
725882
}

libafl/src/executors/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
33
pub mod inprocess;
44
pub use inprocess::InProcessExecutor;
5+
#[cfg(all(feature = "std", unix))]
6+
pub use inprocess::InProcessForkExecutor;
7+
58
pub mod timeout;
69
pub use timeout::TimeoutExecutor;
710

libafl_targets/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ default = []
1515
libfuzzer = []
1616
sancov_pcguard_edges = []
1717
sancov_pcguard_hitcounts = []
18+
sancov_pcguard_edges_ptr = []
19+
sancov_pcguard_hitcounts_ptr = []
1820
sancov_value_profile = []
1921
sancov_cmplog = []
2022
sancov_pcguard = ["sancov_pcguard_hitcounts"]

libafl_targets/src/coverage.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
//! Coverage maps as static mut array
22
33
use crate::EDGES_MAP_SIZE;
4+
#[cfg(any(
5+
feature = "sancov_pcguard_edges_ptr",
6+
feature = "sancov_pcguard_hitcounts_ptr"
7+
))]
8+
use core::ptr;
49

510
/// The map for edges.
611
pub static mut EDGES_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
12+
#[cfg(any(
13+
feature = "sancov_pcguard_edges_ptr",
14+
feature = "sancov_pcguard_hitcounts_ptr"
15+
))]
16+
pub static mut EDGES_MAP_PTR: *mut u8 = ptr::null_mut();
17+
718
/// The max count of edges tracked.
819
pub static mut MAX_EDGES_NUM: usize = 0;

libafl_targets/src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,19 @@
22
33
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
44

5-
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
5+
#[cfg(any(
6+
feature = "sancov_pcguard_edges",
7+
feature = "sancov_pcguard_hitcounts",
8+
feature = "sancov_pcguard_edges_ptr",
9+
feature = "sancov_pcguard_hitcounts_ptr"
10+
))]
611
pub mod sancov_pcguard;
7-
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
12+
#[cfg(any(
13+
feature = "sancov_pcguard_edges",
14+
feature = "sancov_pcguard_hitcounts",
15+
feature = "sancov_pcguard_edges_ptr",
16+
feature = "sancov_pcguard_hitcounts_ptr"
17+
))]
818
pub use sancov_pcguard::*;
919

1020
#[cfg(any(feature = "sancov_cmplog", feature = "sancov_value_profile"))]

libafl_targets/src/sancov_pcguard.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
//! [`LLVM` `PcGuard`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`.
22
3+
#[cfg(any(
4+
feature = "sancov_pcguard_edges_ptr",
5+
feature = "sancov_pcguard_hitcounts_ptr"
6+
))]
7+
use crate::coverage::EDGES_MAP_PTR;
38
use crate::coverage::{EDGES_MAP, MAX_EDGES_NUM};
49

10+
#[cfg(all(
11+
feature = "sancov_pcguard_edges_ptr",
12+
feature = "sancov_pcguard_hitcounts_ptr"
13+
))]
14+
#[cfg(not(any(doc, feature = "clippy")))]
15+
compile_error!(
16+
"the libafl_targets `pcguard_edges_ptr` and `pcguard_hitcounts_ptr` features are mutually exclusive."
17+
);
18+
519
#[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
620
#[cfg(not(any(doc, feature = "clippy")))]
721
compile_error!(
@@ -13,7 +27,12 @@ compile_error!(
1327
/// # Safety
1428
/// Dereferences `guard`, reads the position from there, then dereferences the [`EDGES_MAP`] at that position.
1529
/// Should usually not be called directly.
16-
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
30+
#[cfg(any(
31+
feature = "sancov_pcguard_edges",
32+
feature = "sancov_pcguard_hitcounts",
33+
feature = "sancov_pcguard_edges_ptr",
34+
feature = "sancov_pcguard_hitcounts_ptr"
35+
))]
1736
#[no_mangle]
1837
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
1938
let pos = *guard as usize;
@@ -26,15 +45,38 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
2645
let val = (*EDGES_MAP.get_unchecked(pos) as u8).wrapping_add(1);
2746
*EDGES_MAP.get_unchecked_mut(pos) = val;
2847
}
48+
#[cfg(feature = "sancov_pcguard_edges_ptr")]
49+
{
50+
(EDGES_MAP_PTR as *mut u8).add(pos).write(1);
51+
}
52+
#[cfg(feature = "sancov_pcguard_hitcounts_ptr")]
53+
{
54+
let addr = (EDGES_MAP_PTR as *mut u8).add(pos);
55+
let val = addr.read().wrapping_add(1);
56+
addr.write(val);
57+
}
2958
}
3059

3160
/// Initialize the sancov `pc_guard` - usually called by `llvm`.
3261
///
3362
/// # Safety
3463
/// Dereferences at `start` and writes to it.
35-
#[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
64+
#[cfg(any(
65+
feature = "sancov_pcguard_edges",
66+
feature = "sancov_pcguard_hitcounts",
67+
feature = "sancov_pcguard_edges_ptr",
68+
feature = "sancov_pcguard_hitcounts_ptr"
69+
))]
3670
#[no_mangle]
3771
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
72+
#[cfg(any(
73+
feature = "sancov_pcguard_edges_ptr",
74+
feature = "sancov_pcguard_hitcounts_ptr"
75+
))]
76+
if EDGES_MAP_PTR.is_null() {
77+
EDGES_MAP_PTR = EDGES_MAP.as_mut_ptr();
78+
}
79+
3880
if start == stop || *start != 0 {
3981
return;
4082
}

0 commit comments

Comments
 (0)