Skip to content

Commit e06efaa

Browse files
Observers refactor (#84)
* new observer structure with HasExecHooks * adapt libafl_frida to new observers * docstrings
1 parent 17c6fcd commit e06efaa

File tree

16 files changed

+335
-371
lines changed

16 files changed

+335
-371
lines changed

fuzzers/baby_fuzzer/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ pub fn main() {
7777

7878
// Create the executor for an in-process function with just one observer
7979
let mut executor = InProcessExecutor::new(
80-
"in-process(signals)",
8180
&mut harness,
8281
tuple_list!(observer),
8382
&mut state,

fuzzers/frida_libpng/src/fuzzer.rs

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
//! The example harness is built for libpng.
33
44
use libafl::{
5-
bolts::tuples::{tuple_list, Named},
5+
bolts::tuples::tuple_list,
66
corpus::{
77
ondisk::OnDiskMetadataFormat, Corpus, InMemoryCorpus,
88
IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler,
99
},
10-
events::{setup_restarting_mgr_std, EventManager},
10+
events::setup_restarting_mgr_std,
1111
executors::{
12-
inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasObservers,
12+
inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasExecHooks,
13+
HasExecHooksTuple, HasObservers, HasObserversHooks,
1314
},
1415
feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback},
1516
fuzzer::{Fuzzer, StdFuzzer},
@@ -37,14 +38,14 @@ use libafl_frida::{
3738
FridaOptions,
3839
};
3940

40-
struct FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT>
41+
struct FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
4142
where
4243
FH: FridaHelper<'b>,
4344
H: FnMut(&[u8]) -> ExitKind,
4445
I: Input + HasTargetBytes,
4546
OT: ObserversTuple,
4647
{
47-
base: TimeoutExecutor<InProcessExecutor<'a, H, I, OT>, I, OT>,
48+
base: TimeoutExecutor<InProcessExecutor<'a, EM, H, I, OT, S>, I>,
4849
/// Frida's dynamic rewriting engine
4950
stalker: Stalker<'a>,
5051
/// User provided callback for instrumentation
@@ -53,19 +54,17 @@ where
5354
_phantom: PhantomData<&'b u8>,
5455
}
5556

56-
impl<'a, 'b, 'c, FH, H, I, OT> Executor<I> for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT>
57+
impl<'a, 'b, 'c, EM, FH, H, I, OT, S> Executor<I>
58+
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
5759
where
5860
FH: FridaHelper<'b>,
5961
H: FnMut(&[u8]) -> ExitKind,
6062
I: Input + HasTargetBytes,
6163
OT: ObserversTuple,
6264
{
63-
/// Called right before exexution starts
65+
/// Instruct the target about the input and run
6466
#[inline]
65-
fn pre_exec<EM, S>(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error>
66-
where
67-
EM: EventManager<I, S>,
68-
{
67+
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
6968
if self.helper.stalker_enabled() {
7069
if !self.followed {
7170
self.followed = true;
@@ -77,45 +76,45 @@ where
7776
))
7877
}
7978
}
80-
81-
self.helper.pre_exec(input);
82-
83-
self.base.pre_exec(state, event_mgr, input)
84-
}
85-
86-
/// Instruct the target about the input and run
87-
#[inline]
88-
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
8979
let res = self.base.run_target(input);
9080
if unsafe { ASAN_ERRORS.is_some() && !ASAN_ERRORS.as_ref().unwrap().is_empty() } {
9181
println!("Crashing target as it had ASAN errors");
9282
unsafe {
9383
libc::raise(libc::SIGABRT);
9484
}
9585
}
86+
if self.helper.stalker_enabled() {
87+
self.stalker.deactivate();
88+
}
9689
res
9790
}
91+
}
92+
93+
impl<'a, 'b, 'c, EM, FH, H, I, OT, S> HasExecHooks<EM, I, S>
94+
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
95+
where
96+
FH: FridaHelper<'b>,
97+
H: FnMut(&[u8]) -> ExitKind,
98+
I: Input + HasTargetBytes,
99+
OT: ObserversTuple,
100+
{
101+
/// Called right before exexution starts
102+
#[inline]
103+
fn pre_exec(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error> {
104+
self.helper.pre_exec(input);
105+
self.base.pre_exec(state, event_mgr, input)
106+
}
98107

99108
/// Called right after execution finished.
100109
#[inline]
101-
fn post_exec<EM, S>(
102-
&mut self,
103-
state: &mut S,
104-
event_mgr: &mut EM,
105-
input: &I,
106-
) -> Result<(), Error>
107-
where
108-
EM: EventManager<I, S>,
109-
{
110-
if self.helper.stalker_enabled() {
111-
self.stalker.deactivate();
112-
}
110+
fn post_exec(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error> {
113111
self.helper.post_exec(input);
114112
self.base.post_exec(state, event_mgr, input)
115113
}
116114
}
117115

118-
impl<'a, 'b, 'c, FH, H, I, OT> HasObservers<OT> for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT>
116+
impl<'a, 'b, 'c, EM, FH, H, I, OT, S> HasObservers<OT>
117+
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
119118
where
120119
FH: FridaHelper<'b>,
121120
H: FnMut(&[u8]) -> ExitKind,
@@ -133,19 +132,17 @@ where
133132
}
134133
}
135134

136-
impl<'a, 'b, 'c, FH, H, I, OT> Named for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT>
135+
impl<'a, 'b, 'c, EM, FH, H, I, OT, S> HasObserversHooks<EM, I, OT, S>
136+
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
137137
where
138138
FH: FridaHelper<'b>,
139139
H: FnMut(&[u8]) -> ExitKind,
140140
I: Input + HasTargetBytes,
141-
OT: ObserversTuple,
141+
OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
142142
{
143-
fn name(&self) -> &str {
144-
self.base.name()
145-
}
146143
}
147144

148-
impl<'a, 'b, 'c, FH, H, I, OT> FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT>
145+
impl<'a, 'b, 'c, EM, FH, H, I, OT, S> FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
149146
where
150147
FH: FridaHelper<'b>,
151148
H: FnMut(&[u8]) -> ExitKind,
@@ -154,7 +151,7 @@ where
154151
{
155152
pub fn new(
156153
gum: &'a Gum,
157-
base: InProcessExecutor<'a, H, I, OT>,
154+
base: InProcessExecutor<'a, EM, H, I, OT, S>,
158155
helper: &'c mut FH,
159156
timeout: Duration,
160157
) -> Self {
@@ -324,7 +321,6 @@ unsafe fn fuzz(
324321
let mut executor = FridaInProcessExecutor::new(
325322
&gum,
326323
InProcessExecutor::new(
327-
"in-process(edges)",
328324
&mut frida_harness,
329325
tuple_list!(edges_observer, AsanErrorsObserver::new(&ASAN_ERRORS)),
330326
&mut state,

fuzzers/libfuzzer_libmozjpeg/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
113113

114114
// Create the executor for an in-process function with observers for edge coverage, value-profile and allocations sizes
115115
let mut executor = InProcessExecutor::new(
116-
"in-process(edges,cmp,alloc)",
117116
&mut harness,
118117
tuple_list!(edges_observer, cmps_observer, allocs_observer),
119118
&mut state,

fuzzers/libfuzzer_libpng/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
120120
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
121121
let mut executor = TimeoutExecutor::new(
122122
InProcessExecutor::new(
123-
"in-process(edges,time)",
124123
&mut harness,
125124
tuple_list!(edges_observer, TimeObserver::new("time")),
126125
&mut state,

fuzzers/libfuzzer_stb_image/src/main.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
116116

117117
// Create the executor for an in-process function with just one observer for edge coverage
118118
let mut executor = InProcessExecutor::new(
119-
"in-process(edges,time)",
120119
&mut harness,
121120
tuple_list!(edges_observer, TimeObserver::new("time")),
122121
&mut state,

libafl/src/executors/inprocess.rs

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ use crate::bolts::os::unix_signals::setup_signal_handler;
1414
use crate::bolts::os::windows_exceptions::setup_exception_handler;
1515

1616
use crate::{
17-
bolts::tuples::Named,
1817
corpus::Corpus,
1918
events::EventManager,
20-
executors::{Executor, ExitKind, HasObservers},
19+
executors::{
20+
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
21+
},
2122
feedbacks::FeedbacksTuple,
2223
inputs::{HasTargetBytes, Input},
2324
observers::ObserversTuple,
@@ -26,34 +27,41 @@ use crate::{
2627
};
2728

2829
/// The inmem executor simply calls a target function, then returns afterwards.
29-
pub struct InProcessExecutor<'a, H, I, OT>
30+
pub struct InProcessExecutor<'a, EM, H, I, OT, S>
3031
where
3132
H: FnMut(&[u8]) -> ExitKind,
3233
I: Input + HasTargetBytes,
3334
OT: ObserversTuple,
3435
{
35-
/// The name of this executor instance, to address it from other components
36-
name: &'static str,
3736
/// The harness function, being executed for each fuzzing loop execution
3837
harness_fn: &'a mut H,
3938
/// The observers, observing each run
4039
observers: OT,
41-
phantom: PhantomData<I>,
40+
phantom: PhantomData<(EM, I, S)>,
4241
}
4342

44-
impl<'a, H, I, OT> Executor<I> for InProcessExecutor<'a, H, I, OT>
43+
impl<'a, EM, H, I, OT, S> Executor<I> for InProcessExecutor<'a, EM, H, I, OT, S>
4544
where
4645
H: FnMut(&[u8]) -> ExitKind,
4746
I: Input + HasTargetBytes,
4847
OT: ObserversTuple,
4948
{
5049
#[inline]
51-
fn pre_exec<EM, S>(
52-
&mut self,
53-
_state: &mut S,
54-
_event_mgr: &mut EM,
55-
_input: &I,
56-
) -> Result<(), Error> {
50+
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
51+
let bytes = input.target_bytes();
52+
let ret = (self.harness_fn)(bytes.as_slice());
53+
Ok(ret)
54+
}
55+
}
56+
57+
impl<'a, EM, H, I, OT, S> HasExecHooks<EM, I, S> for InProcessExecutor<'a, EM, H, I, OT, S>
58+
where
59+
H: FnMut(&[u8]) -> ExitKind,
60+
I: Input + HasTargetBytes,
61+
OT: ObserversTuple,
62+
{
63+
#[inline]
64+
fn pre_exec(&mut self, _state: &mut S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error> {
5765
#[cfg(unix)]
5866
unsafe {
5967
let data = &mut unix_signal_handler::GLOBAL_STATE;
@@ -92,19 +100,7 @@ where
92100
}
93101

94102
#[inline]
95-
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
96-
let bytes = input.target_bytes();
97-
let ret = (self.harness_fn)(bytes.as_slice());
98-
Ok(ret)
99-
}
100-
101-
#[inline]
102-
fn post_exec<EM, S>(
103-
&mut self,
104-
_state: &mut S,
105-
_event_mgr: &mut EM,
106-
_input: &I,
107-
) -> Result<(), Error> {
103+
fn post_exec(&mut self, _state: &mut S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error> {
108104
#[cfg(unix)]
109105
unsafe {
110106
write_volatile(
@@ -125,18 +121,7 @@ where
125121
}
126122
}
127123

128-
impl<'a, H, I, OT> Named for InProcessExecutor<'a, H, I, OT>
129-
where
130-
H: FnMut(&[u8]) -> ExitKind,
131-
I: Input + HasTargetBytes,
132-
OT: ObserversTuple,
133-
{
134-
fn name(&self) -> &str {
135-
self.name
136-
}
137-
}
138-
139-
impl<'a, H, I, OT> HasObservers<OT> for InProcessExecutor<'a, H, I, OT>
124+
impl<'a, EM, H, I, OT, S> HasObservers<OT> for InProcessExecutor<'a, EM, H, I, OT, S>
140125
where
141126
H: FnMut(&[u8]) -> ExitKind,
142127
I: Input + HasTargetBytes,
@@ -153,7 +138,15 @@ where
153138
}
154139
}
155140

156-
impl<'a, H, I, OT> InProcessExecutor<'a, H, I, OT>
141+
impl<'a, EM, H, I, OT, S> HasObserversHooks<EM, I, OT, S> for InProcessExecutor<'a, EM, H, I, OT, S>
142+
where
143+
H: FnMut(&[u8]) -> ExitKind,
144+
I: Input + HasTargetBytes,
145+
OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
146+
{
147+
}
148+
149+
impl<'a, EM, H, I, OT, S> InProcessExecutor<'a, EM, H, I, OT, S>
157150
where
158151
H: FnMut(&[u8]) -> ExitKind,
159152
I: Input + HasTargetBytes,
@@ -162,12 +155,10 @@ where
162155
/// Create a new in mem executor.
163156
/// Caution: crash and restart in one of them will lead to odd behavior if multiple are used,
164157
/// depending on different corpus or state.
165-
/// * `name` - the name of this executor (to address it along the way)
166158
/// * `harness_fn` - the harness, executiong the function
167159
/// * `observers` - the observers observing the target during execution
168160
/// This may return an error on unix, if signal handler setup fails
169-
pub fn new<EM, OC, OFT, S>(
170-
name: &'static str,
161+
pub fn new<OC, OFT>(
171162
harness_fn: &'a mut H,
172163
observers: OT,
173164
_state: &mut S,
@@ -213,7 +204,6 @@ where
213204
Ok(Self {
214205
harness_fn,
215206
observers,
216-
name,
217207
phantom: PhantomData,
218208
})
219209
}
@@ -696,10 +686,9 @@ mod tests {
696686
fn test_inmem_exec() {
697687
let mut harness = |_buf: &[u8]| ExitKind::Ok;
698688

699-
let mut in_process_executor = InProcessExecutor::<_, NopInput, ()> {
689+
let mut in_process_executor = InProcessExecutor::<(), _, NopInput, (), ()> {
700690
harness_fn: &mut harness,
701691
observers: tuple_list!(),
702-
name: "main",
703692
phantom: PhantomData,
704693
};
705694
let mut input = NopInput {};

0 commit comments

Comments
 (0)