Refactor InProcessExecutor, merge timeout executors (#1789)
* move windows, inprocess fork to a different file, try new hook mechanism for the executor * fix * even more * more * more * fix * fix * macosgit add -ugit add -u * windows! * windows! * aa * aa * macos * std * wtf unresolved? * Copy, Clone * why you just don't have the same API! * inproc * next; inprocess * windows? * ci * ci * ci * unused * ci * unused * no_std * windows no std * fix * inprocess * fix * windows * fuzzers * macos , book * fix * aa * allow * fix * stop suggesting wrong lint AAAAAAAAAAAAAAAAA!!! * stop suggesting wrong lint AAAAAAAAAAAAAAAAA!!! * win * fix * wip * wip2 * windows done? * remove TimeoutExecutor * ci * ci * miri * fixfi * compile on windows * a * clp * no_std stuff * windows no_std * mac stuff * m * a * ci * ci * deleting timeoutexecutor, gradually * fucking macos * ci * test * ci * ci * batch mode constructor * fix * ci * aa * miri * aaa * tmate again * fix windows stuff * final fix * another win fix * add * let's add the new fix later * more * fi * parse * win clippy * win no std * safety * fix * DEFAULT * final fix * libafl_libfuzzer * comments * fix * fix fuzzres * fixxxxx * fixxxxx * last fix * change name
This commit is contained in:
parent
058d2c0825
commit
2ac154d473
2
.gitignore
vendored
2
.gitignore
vendored
@ -66,3 +66,5 @@ libafl_nyx/packer
|
|||||||
.gdb_history
|
.gdb_history
|
||||||
# No llvm IR
|
# No llvm IR
|
||||||
*.ll
|
*.ll
|
||||||
|
|
||||||
|
.tar.gz
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
extern crate libafl;
|
extern crate libafl;
|
||||||
extern crate libafl_bolts;
|
extern crate libafl_bolts;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{InMemoryCorpus, OnDiskCorpus},
|
corpus::{InMemoryCorpus, OnDiskCorpus},
|
||||||
events::SimpleEventManager,
|
events::SimpleEventManager,
|
||||||
@ -13,8 +15,7 @@ use libafl::{
|
|||||||
schedulers::QueueScheduler,
|
schedulers::QueueScheduler,
|
||||||
state::StdState,
|
state::StdState,
|
||||||
};
|
};
|
||||||
use libafl_bolts::{current_nanos, rands::StdRand, AsSlice};
|
use libafl_bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice};
|
||||||
use std::path::PathBuf;
|
|
||||||
/* ANCHOR_END: use */
|
/* ANCHOR_END: use */
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -70,8 +71,14 @@ fn main() {
|
|||||||
|
|
||||||
/* ANCHOR: executor */
|
/* ANCHOR: executor */
|
||||||
// Create the executor for an in-process function
|
// Create the executor for an in-process function
|
||||||
let mut executor = InProcessExecutor::new(&mut harness, (), &mut fuzzer, &mut state, &mut mgr)
|
let mut executor = InProcessExecutor::new(
|
||||||
.expect("Failed to create the Executor");
|
&mut harness,
|
||||||
|
(),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut mgr,
|
||||||
|
)
|
||||||
|
.expect("Failed to create the Executor");
|
||||||
/* ANCHOR_END: executor */
|
/* ANCHOR_END: executor */
|
||||||
|
|
||||||
/* ANCHOR: generator */
|
/* ANCHOR: generator */
|
||||||
|
@ -13,8 +13,6 @@ In Rust, we bind this concept to the [`Executor`](https://docs.rs/libafl/latest/
|
|||||||
|
|
||||||
By default, we implement some commonly used Executors such as [`InProcessExecutor`](https://docs.rs/libafl/latest/libafl/executors/inprocess/type.InProcessExecutor.html) in which the target is a harness function providing in-process crash detection. Another Executor is the [`ForkserverExecutor`](https://docs.rs/libafl/latest/libafl/executors/forkserver/struct.ForkserverExecutor.html) that implements an AFL-like mechanism to spawn child processes to fuzz.
|
By default, we implement some commonly used Executors such as [`InProcessExecutor`](https://docs.rs/libafl/latest/libafl/executors/inprocess/type.InProcessExecutor.html) in which the target is a harness function providing in-process crash detection. Another Executor is the [`ForkserverExecutor`](https://docs.rs/libafl/latest/libafl/executors/forkserver/struct.ForkserverExecutor.html) that implements an AFL-like mechanism to spawn child processes to fuzz.
|
||||||
|
|
||||||
A common pattern when creating an Executor is wrapping an existing one, for instance [`TimeoutExecutor`](https://docs.rs/libafl/latest/libafl/executors/timeout/struct.TimeoutExecutor.html) wraps an executor and installs a timeout callback before calling the original `run` function of the wrapped executor.
|
|
||||||
|
|
||||||
## InProcessExecutor
|
## InProcessExecutor
|
||||||
Let's begin with the base case; `InProcessExecutor`.
|
Let's begin with the base case; `InProcessExecutor`.
|
||||||
This executor executes the harness program (function) inside the fuzzer process.
|
This executor executes the harness program (function) inside the fuzzer process.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::ptr::write_volatile;
|
use std::ptr::write_volatile;
|
||||||
use std::{path::PathBuf, ptr::write};
|
use std::{path::PathBuf, ptr::write, time::Duration};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{InMemoryCorpus, OnDiskCorpus},
|
corpus::{InMemoryCorpus, OnDiskCorpus},
|
||||||
@ -110,6 +110,7 @@ pub fn main() {
|
|||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
core::time::Duration::from_millis(5000),
|
||||||
shmem_provider,
|
shmem_provider,
|
||||||
)
|
)
|
||||||
.expect("Failed to create the Executor");
|
.expect("Failed to create the Executor");
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::path::PathBuf;
|
use std::{path::PathBuf, time::Duration};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{InMemoryCorpus, OnDiskCorpus},
|
corpus::{InMemoryCorpus, OnDiskCorpus},
|
||||||
@ -98,6 +98,7 @@ pub fn main() {
|
|||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
Duration::from_millis(5000),
|
||||||
shmem_provider,
|
shmem_provider,
|
||||||
)
|
)
|
||||||
.expect("Failed to create the Executor");
|
.expect("Failed to create the Executor");
|
||||||
|
@ -117,6 +117,7 @@ pub fn main() {
|
|||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
core::time::Duration::from_millis(5000),
|
||||||
shmem_provider,
|
shmem_provider,
|
||||||
)
|
)
|
||||||
.expect("Failed to create the Executor");
|
.expect("Failed to create the Executor");
|
||||||
|
@ -18,7 +18,7 @@ use clap::{Arg, Command};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
||||||
events::SimpleRestartingEventManager,
|
events::SimpleRestartingEventManager,
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or,
|
feedback_or,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -327,29 +327,27 @@ fn fuzz(
|
|||||||
let mut tracing_harness = harness;
|
let mut tracing_harness = harness;
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut mgr,
|
||||||
&mut mgr,
|
|
||||||
)?,
|
|
||||||
timeout,
|
timeout,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// Setup a tracing stage in which we log comparisons
|
// Setup a tracing stage in which we log comparisons
|
||||||
let tracing = TracingStage::new(TimeoutExecutor::new(
|
let tracing = TracingStage::new(
|
||||||
InProcessExecutor::new(
|
InProcessExecutor::with_timeout(
|
||||||
&mut tracing_harness,
|
&mut tracing_harness,
|
||||||
tuple_list!(cmplog_observer),
|
tuple_list!(cmplog_observer),
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
timeout * 10,
|
||||||
)?,
|
)?,
|
||||||
// Give it more time!
|
// Give it more time!
|
||||||
timeout * 10,
|
);
|
||||||
));
|
|
||||||
|
|
||||||
// The order of the stages matter!
|
// The order of the stages matter!
|
||||||
let mut stages = tuple_list!(calibration, tracing, i2s, power);
|
let mut stages = tuple_list!(calibration, tracing, i2s, power);
|
||||||
|
@ -9,6 +9,7 @@ use std::{
|
|||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process,
|
process,
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::{Arg, Command};
|
use clap::{Arg, Command};
|
||||||
@ -342,6 +343,7 @@ fn fuzz(
|
|||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
shmem_provider,
|
shmem_provider,
|
||||||
|
Duration::from_millis(5000),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Show the cmplog observer
|
// Show the cmplog observer
|
||||||
|
@ -15,7 +15,7 @@ use clap::{Arg, Command};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
||||||
events::SimpleRestartingEventManager,
|
events::SimpleRestartingEventManager,
|
||||||
executors::{ExitKind, ShadowExecutor, TimeoutExecutor},
|
executors::{ExitKind, ShadowExecutor},
|
||||||
feedback_or,
|
feedback_or,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -351,6 +351,7 @@ fn fuzz(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let executor = QemuExecutor::new(
|
let executor = QemuExecutor::new(
|
||||||
&mut hooks,
|
&mut hooks,
|
||||||
&mut harness,
|
&mut harness,
|
||||||
@ -358,10 +359,9 @@ fn fuzz(
|
|||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
timeout,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
|
||||||
let executor = TimeoutExecutor::new(executor, timeout);
|
|
||||||
// Show the cmplog observer
|
// Show the cmplog observer
|
||||||
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
|
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ use content_inspector::inspect;
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
||||||
events::SimpleRestartingEventManager,
|
events::SimpleRestartingEventManager,
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or,
|
feedback_or,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -394,29 +394,24 @@ fn fuzz_binary(
|
|||||||
let mut tracing_harness = harness;
|
let mut tracing_harness = harness;
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut mgr,
|
||||||
&mut mgr,
|
|
||||||
)?,
|
|
||||||
timeout,
|
timeout,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// Setup a tracing stage in which we log comparisons
|
// Setup a tracing stage in which we log comparisons
|
||||||
let tracing = TracingStage::new(TimeoutExecutor::new(
|
let tracing = TracingStage::new(InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut tracing_harness,
|
||||||
&mut tracing_harness,
|
tuple_list!(cmplog_observer),
|
||||||
tuple_list!(cmplog_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut mgr,
|
||||||
&mut mgr,
|
|
||||||
)?,
|
|
||||||
// Give it more time!
|
|
||||||
timeout * 10,
|
timeout * 10,
|
||||||
));
|
)?);
|
||||||
|
|
||||||
// The order of the stages matter!
|
// The order of the stages matter!
|
||||||
let mut stages = tuple_list!(calibration, tracing, i2s, power);
|
let mut stages = tuple_list!(calibration, tracing, i2s, power);
|
||||||
@ -621,29 +616,24 @@ fn fuzz_text(
|
|||||||
let generalization = GeneralizationStage::new(&edges_observer);
|
let generalization = GeneralizationStage::new(&edges_observer);
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut mgr,
|
||||||
&mut mgr,
|
|
||||||
)?,
|
|
||||||
timeout,
|
timeout,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// Setup a tracing stage in which we log comparisons
|
// Setup a tracing stage in which we log comparisons
|
||||||
let tracing = TracingStage::new(TimeoutExecutor::new(
|
let tracing = TracingStage::new(InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut tracing_harness,
|
||||||
&mut tracing_harness,
|
tuple_list!(cmplog_observer),
|
||||||
tuple_list!(cmplog_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut mgr,
|
||||||
&mut mgr,
|
|
||||||
)?,
|
|
||||||
// Give it more time!
|
// Give it more time!
|
||||||
timeout * 10,
|
timeout * 10,
|
||||||
));
|
)?);
|
||||||
|
|
||||||
// The order of the stages matter!
|
// The order of the stages matter!
|
||||||
let mut stages = tuple_list!(generalization, calibration, tracing, i2s, power, grimoire);
|
let mut stages = tuple_list!(generalization, calibration, tracing, i2s, power, grimoire);
|
||||||
|
@ -14,7 +14,7 @@ use clap::{Arg, ArgAction, Command};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{launcher::Launcher, EventConfig},
|
events::{launcher::Launcher, EventConfig},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or,
|
feedback_or,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -197,16 +197,14 @@ pub extern "C" fn LLVMFuzzerRunDriver(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut mgr,
|
||||||
&mut mgr,
|
|
||||||
)?,
|
|
||||||
Duration::from_millis(timeout_ms),
|
Duration::from_millis(timeout_ms),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// Secondary harness due to mut ownership
|
// Secondary harness due to mut ownership
|
||||||
let mut harness = |input: &BytesInput| {
|
let mut harness = |input: &BytesInput| {
|
||||||
|
@ -12,7 +12,7 @@ use std::{env, path::PathBuf};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -173,17 +173,15 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
Duration::new(10, 0),
|
Duration::new(10, 0),
|
||||||
);
|
)?;
|
||||||
|
// 10 seconds timeout
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -13,7 +13,7 @@ use clap::Parser;
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{EventConfig, Launcher},
|
events::{EventConfig, Launcher},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -205,17 +205,14 @@ pub extern "C" fn libafl_main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
opt.timeout,
|
opt.timeout,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -12,7 +12,7 @@ use std::{env, path::PathBuf};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
||||||
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -189,17 +189,14 @@ fn fuzz(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
Duration::new(10, 0),
|
Duration::new(10, 0),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -13,7 +13,7 @@ use clap::{self, Parser};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{launcher::CentralizedLauncher, EventConfig},
|
events::{launcher::CentralizedLauncher, EventConfig},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -200,21 +200,25 @@ pub extern "C" fn libafl_main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let executor = InProcessExecutor::new(
|
#[cfg(target_os = "linux")]
|
||||||
|
let mut executor = InProcessExecutor::batched_timeouts(
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, time_observer),
|
tuple_list!(edges_observer, time_observer),
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
opt.timeout,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Wrap the executor with a timeout
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
let mut executor = TimeoutExecutor::batch_mode(executor, opt.timeout);
|
|
||||||
|
|
||||||
// Wrap the executor with a timeout
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
let mut executor = TimeoutExecutor::new(executor, opt.timeout);
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
|
&mut harness,
|
||||||
|
tuple_list!(edges_observer, time_observer),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut mgr,
|
||||||
|
opt.timeout,
|
||||||
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -15,7 +15,7 @@ use libafl::{
|
|||||||
Corpus, InMemoryCorpus, OnDiskCorpus,
|
Corpus, InMemoryCorpus, OnDiskCorpus,
|
||||||
},
|
},
|
||||||
events::{setup_restarting_mgr_std, EventConfig, EventFirer, EventRestarter, LogSeverity},
|
events::{setup_restarting_mgr_std, EventConfig, EventFirer, EventRestarter, LogSeverity},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -172,17 +172,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
Duration::new(10, 0),
|
Duration::new(10, 0),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -13,7 +13,7 @@ use clap::{self, Parser};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{launcher::Launcher, EventConfig},
|
events::{launcher::Launcher, EventConfig},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -196,17 +196,14 @@ pub extern "C" fn libafl_main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
opt.timeout,
|
opt.timeout,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -13,7 +13,7 @@ use clap::{self, Parser};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{launcher::Launcher, EventConfig},
|
events::{launcher::Launcher, EventConfig},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -201,21 +201,25 @@ pub extern "C" fn libafl_main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let executor = InProcessExecutor::new(
|
#[cfg(target_os = "linux")]
|
||||||
|
let mut executor = InProcessExecutor::batched_timeouts(
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, time_observer),
|
tuple_list!(edges_observer, time_observer),
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
|
opt.timeout,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Wrap the executor with a timeout
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
let mut executor = TimeoutExecutor::batch_mode(executor, opt.timeout);
|
|
||||||
|
|
||||||
// Wrap the executor with a timeout
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
let mut executor = TimeoutExecutor::new(executor, opt.timeout);
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
|
&mut harness,
|
||||||
|
tuple_list!(edges_observer, time_observer),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut restarting_mgr,
|
||||||
|
opt.timeout,
|
||||||
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -13,7 +13,7 @@ use clap::{self, Parser};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
||||||
events::{launcher::Launcher, EventConfig, EventRestarter, LlmpRestartingEventManager},
|
events::{launcher::Launcher, EventConfig, EventRestarter, LlmpRestartingEventManager},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -222,18 +222,14 @@ pub extern "C" fn libafl_main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
opt.timeout,
|
opt.timeout,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
@ -12,7 +12,7 @@ use std::{env, path::PathBuf};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{tcp::setup_restarting_mgr_tcp, EventConfig, EventRestarter},
|
events::{tcp::setup_restarting_mgr_tcp, EventConfig, EventRestarter},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -171,17 +171,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
Duration::new(10, 0),
|
Duration::new(10, 0),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -4,7 +4,7 @@ use std::{env, path::PathBuf};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -130,17 +130,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
Duration::new(10, 0),
|
Duration::new(10, 0),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// Initialize ASAN, call this before any ASAN crashes can occur (directly after initializing executor e.g.)
|
// Initialize ASAN, call this before any ASAN crashes can occur (directly after initializing executor e.g.)
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -70,7 +70,7 @@ pub fn main() {
|
|||||||
let mut scheduler = QueueScheduler::new();
|
let mut scheduler = QueueScheduler::new();
|
||||||
|
|
||||||
// Create the executor for an in-process function with just one observer
|
// Create the executor for an in-process function with just one observer
|
||||||
//let mut executor = InProcessExecutor::new(&mut harness, &mut fuzzer, &mut state, &mut mgr)
|
//let mut executor = InProcessExecutor::new(tuple_list!(), &mut harness, &mut fuzzer, &mut state, &mut mgr)
|
||||||
// .expect("Failed to create the Executor");
|
// .expect("Failed to create the Executor");
|
||||||
|
|
||||||
let testcase = Testcase::new(BytesInput::new(b"aaaa".to_vec()));
|
let testcase = Testcase::new(BytesInput::new(b"aaaa".to_vec()));
|
||||||
|
@ -228,6 +228,7 @@ pub fn fuzz() -> Result<(), Error> {
|
|||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
shmem_provider,
|
shmem_provider,
|
||||||
|
core::time::Duration::from_millis(5000),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
println!("Importing {} seeds...", files.len());
|
println!("Importing {} seeds...", files.len());
|
||||||
|
@ -9,7 +9,7 @@ use clap::{builder::Str, Parser};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, NopCorpus},
|
corpus::{Corpus, NopCorpus},
|
||||||
events::{launcher::Launcher, EventConfig, EventRestarter},
|
events::{launcher::Launcher, EventConfig, EventRestarter},
|
||||||
executors::{ExitKind, TimeoutExecutor},
|
executors::ExitKind,
|
||||||
fuzzer::StdFuzzer,
|
fuzzer::StdFuzzer,
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
monitors::MultiMonitor,
|
monitors::MultiMonitor,
|
||||||
@ -35,6 +35,11 @@ use rangemap::RangeMap;
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Version;
|
pub struct Version;
|
||||||
|
|
||||||
|
/// Parse a millis string to a [`Duration`]. Used for arg parsing.
|
||||||
|
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||||
|
Ok(Duration::from_millis(time.parse()?))
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Version> for Str {
|
impl From<Version> for Str {
|
||||||
fn from(_: Version) -> Str {
|
fn from(_: Version) -> Str {
|
||||||
let version = [
|
let version = [
|
||||||
@ -73,8 +78,8 @@ pub struct FuzzerOptions {
|
|||||||
#[arg(long, help = "Input directory")]
|
#[arg(long, help = "Input directory")]
|
||||||
input: String,
|
input: String,
|
||||||
|
|
||||||
#[arg(long, help = "Timeout in seconds", default_value_t = 1_u64)]
|
#[arg(long, help = "Timeout in seconds", default_value = "5000", value_parser = timeout_from_millis_str)]
|
||||||
timeout: u64,
|
timeout: Duration,
|
||||||
|
|
||||||
#[arg(long = "port", help = "Broker port", default_value_t = 1337_u16)]
|
#[arg(long = "port", help = "Broker port", default_value_t = 1337_u16)]
|
||||||
port: u16,
|
port: u16,
|
||||||
@ -245,18 +250,17 @@ pub fn fuzz() {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let executor = QemuExecutor::new(
|
let mut executor = QemuExecutor::new(
|
||||||
&mut hooks,
|
&mut hooks,
|
||||||
&mut harness,
|
&mut harness,
|
||||||
(),
|
(),
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
options.timeout,
|
||||||
)
|
)
|
||||||
.expect("Failed to create QemuExecutor");
|
.expect("Failed to create QemuExecutor");
|
||||||
|
|
||||||
let mut executor = TimeoutExecutor::new(executor, Duration::from_secs(options.timeout));
|
|
||||||
|
|
||||||
if state.must_load_initial_inputs() {
|
if state.must_load_initial_inputs() {
|
||||||
state
|
state
|
||||||
.load_initial_inputs_by_filenames(&mut fuzzer, &mut executor, &mut mgr, &files)
|
.load_initial_inputs_by_filenames(&mut fuzzer, &mut executor, &mut mgr, &files)
|
||||||
|
@ -18,7 +18,6 @@ int LLVMFuzzerTestOneInput(char *data, size_t len) {
|
|||||||
char *err_msg = 0, query[1024];
|
char *err_msg = 0, query[1024];
|
||||||
|
|
||||||
if (data[0] % 2) {
|
if (data[0] % 2) {
|
||||||
|
|
||||||
int rc = sqlite3_open_v2("example.db", &db, SQLITE_OPEN_READONLY, 0);
|
int rc = sqlite3_open_v2("example.db", &db, SQLITE_OPEN_READONLY, 0);
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) {
|
||||||
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
|
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
|
||||||
@ -33,9 +32,7 @@ int LLVMFuzzerTestOneInput(char *data, size_t len) {
|
|||||||
|
|
||||||
rc = sqlite3_exec(db, query, callback, 0, &err_msg);
|
rc = sqlite3_exec(db, query, callback, 0, &err_msg);
|
||||||
|
|
||||||
if (rc != SQLITE_OK) {
|
if (rc != SQLITE_OK) { sqlite3_free(err_msg); }
|
||||||
sqlite3_free(err_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ use libafl::{
|
|||||||
use libafl_bolts::{
|
use libafl_bolts::{
|
||||||
core_affinity::CoreId, rands::StdRand, shmem::StdShMemProvider, tuples::tuple_list,
|
core_affinity::CoreId, rands::StdRand, shmem::StdShMemProvider, tuples::tuple_list,
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "injections")]
|
||||||
|
use libafl_qemu::injections::QemuInjectionHelper;
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
asan::{init_with_asan, QemuAsanHelper},
|
asan::{init_with_asan, QemuAsanHelper},
|
||||||
cmplog::QemuCmpLogHelper,
|
cmplog::QemuCmpLogHelper,
|
||||||
@ -18,9 +20,6 @@ use libafl_qemu::{
|
|||||||
ArchExtras, Emulator, GuestAddr, QemuInstrumentationAddressRangeFilter,
|
ArchExtras, Emulator, GuestAddr, QemuInstrumentationAddressRangeFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "injections")]
|
|
||||||
use libafl_qemu::injections::QemuInjectionHelper;
|
|
||||||
|
|
||||||
use crate::{instance::Instance, options::FuzzerOptions};
|
use crate::{instance::Instance, options::FuzzerOptions};
|
||||||
|
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
|
@ -4,7 +4,7 @@ use std::process;
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
|
||||||
events::{EventRestarter, LlmpRestartingEventManager},
|
events::{EventRestarter, LlmpRestartingEventManager},
|
||||||
executors::{ShadowExecutor, TimeoutExecutor},
|
executors::ShadowExecutor,
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Evaluator, Fuzzer, StdFuzzer},
|
fuzzer::{Evaluator, Fuzzer, StdFuzzer},
|
||||||
@ -150,11 +150,9 @@ impl<'a> Instance<'a> {
|
|||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut self.mgr,
|
&mut self.mgr,
|
||||||
|
self.options.timeout,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Wrap the executor to keep track of the timeout
|
|
||||||
let executor = TimeoutExecutor::new(executor, self.options.timeout);
|
|
||||||
|
|
||||||
// Create an observation channel using cmplog map
|
// Create an observation channel using cmplog map
|
||||||
let cmplog_observer = CmpLogObserver::new("cmplog", true);
|
let cmplog_observer = CmpLogObserver::new("cmplog", true);
|
||||||
|
|
||||||
@ -183,18 +181,16 @@ impl<'a> Instance<'a> {
|
|||||||
self.fuzz(&mut state, &mut fuzzer, &mut executor, &mut stages)
|
self.fuzz(&mut state, &mut fuzzer, &mut executor, &mut stages)
|
||||||
} else {
|
} else {
|
||||||
// Create a QEMU in-process executor
|
// Create a QEMU in-process executor
|
||||||
let executor = QemuExecutor::new(
|
let mut executor = QemuExecutor::new(
|
||||||
&mut hooks,
|
&mut hooks,
|
||||||
&mut harness,
|
&mut harness,
|
||||||
observers,
|
observers,
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut self.mgr,
|
&mut self.mgr,
|
||||||
|
self.options.timeout,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Wrap the executor to keep track of the timeout
|
|
||||||
let mut executor = TimeoutExecutor::new(executor, self.options.timeout);
|
|
||||||
|
|
||||||
// Setup an havoc mutator with a mutational stage
|
// Setup an havoc mutator with a mutational stage
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
@ -6,7 +6,7 @@ use std::{env, path::PathBuf, process};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{launcher::Launcher, EventConfig},
|
events::{launcher::Launcher, EventConfig},
|
||||||
executors::{ExitKind, TimeoutExecutor},
|
executors::ExitKind,
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -202,15 +202,13 @@ pub fn fuzz() {
|
|||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
timeout,
|
||||||
)
|
)
|
||||||
.expect("Failed to create QemuExecutor");
|
.expect("Failed to create QemuExecutor");
|
||||||
|
|
||||||
// Instead of calling the timeout handler and restart the process, trigger a breakpoint ASAP
|
// Instead of calling the timeout handler and restart the process, trigger a breakpoint ASAP
|
||||||
executor.break_on_timeout();
|
executor.break_on_timeout();
|
||||||
|
|
||||||
// Wrap the executor to keep track of the timeout
|
|
||||||
let mut executor = TimeoutExecutor::new(executor, timeout);
|
|
||||||
|
|
||||||
if state.must_load_initial_inputs() {
|
if state.must_load_initial_inputs() {
|
||||||
state
|
state
|
||||||
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &corpus_dirs)
|
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &corpus_dirs)
|
||||||
|
@ -9,7 +9,7 @@ use std::{env, path::PathBuf};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::StdFuzzer,
|
fuzzer::StdFuzzer,
|
||||||
@ -142,17 +142,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
|||||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut restarting_mgr,
|
||||||
&mut restarting_mgr,
|
|
||||||
)?,
|
|
||||||
// 10 seconds timeout
|
|
||||||
Duration::new(10, 0),
|
Duration::new(10, 0),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
// Call LLVMFUzzerInitialize() if present.
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
@ -57,10 +57,7 @@ where
|
|||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
*state.executions_mut() += 1;
|
*state.executions_mut() += 1;
|
||||||
|
|
||||||
let ret = self.primary.run_target(fuzzer, state, mgr, input);
|
self.primary.run_target(fuzzer, state, mgr, input)
|
||||||
self.primary.post_run_reset();
|
|
||||||
self.secondary.post_run_reset();
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,6 @@ where
|
|||||||
.pre_observe_first_all(observers.primary.as_mut())?;
|
.pre_observe_first_all(observers.primary.as_mut())?;
|
||||||
observers.primary.as_mut().pre_exec_all(state, input)?;
|
observers.primary.as_mut().pre_exec_all(state, input)?;
|
||||||
let ret1 = self.primary.run_target(fuzzer, state, mgr, input)?;
|
let ret1 = self.primary.run_target(fuzzer, state, mgr, input)?;
|
||||||
self.primary.post_run_reset();
|
|
||||||
observers
|
observers
|
||||||
.primary
|
.primary
|
||||||
.as_mut()
|
.as_mut()
|
||||||
@ -90,7 +89,6 @@ where
|
|||||||
.pre_observe_second_all(observers.secondary.as_mut())?;
|
.pre_observe_second_all(observers.secondary.as_mut())?;
|
||||||
observers.secondary.as_mut().pre_exec_all(state, input)?;
|
observers.secondary.as_mut().pre_exec_all(state, input)?;
|
||||||
let ret2 = self.secondary.run_target(fuzzer, state, mgr, input)?;
|
let ret2 = self.secondary.run_target(fuzzer, state, mgr, input)?;
|
||||||
self.secondary.post_run_reset();
|
|
||||||
observers
|
observers
|
||||||
.secondary
|
.secondary
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
471
libafl/src/executors/hooks/inprocess.rs
Normal file
471
libafl/src/executors/hooks/inprocess.rs
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
//! The hook for `InProcessExecutor`
|
||||||
|
#[cfg(any(unix, all(windows, feature = "std")))]
|
||||||
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
use core::{
|
||||||
|
ffi::c_void,
|
||||||
|
ptr::{self, null_mut},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
#[cfg(all(target_os = "linux", feature = "std"))]
|
||||||
|
use core::{mem::zeroed, ptr::addr_of};
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", feature = "std"))]
|
||||||
|
use libafl_bolts::current_time;
|
||||||
|
#[cfg(all(unix, feature = "std", not(miri)))]
|
||||||
|
use libafl_bolts::os::unix_signals::setup_signal_handler;
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
use libafl_bolts::os::windows_exceptions::setup_exception_handler;
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
use windows::Win32::System::Threading::{CRITICAL_SECTION, PTP_TIMER};
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use crate::executors::hooks::timer::TimerStruct;
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use crate::executors::hooks::unix::unix_signal_handler;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use crate::state::State;
|
||||||
|
use crate::{
|
||||||
|
events::{EventFirer, EventRestarter},
|
||||||
|
executors::{hooks::ExecutorHook, inprocess::HasInProcessHooks, Executor, HasObservers},
|
||||||
|
feedbacks::Feedback,
|
||||||
|
state::{HasCorpus, HasExecutions, HasSolutions},
|
||||||
|
Error, HasObjective,
|
||||||
|
};
|
||||||
|
/// The inmem executor's handlers.
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct InProcessHooks {
|
||||||
|
/// On crash C function pointer
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub crash_handler: *const c_void,
|
||||||
|
/// On timeout C function pointer
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub timeout_handler: *const c_void,
|
||||||
|
/// TImer struct
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub timer: TimerStruct,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Any hooks that is about timeout
|
||||||
|
pub trait HasTimeout {
|
||||||
|
/// Return ref to timer
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
fn timer(&self) -> &TimerStruct;
|
||||||
|
/// Return mut ref to timer
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
fn timer_mut(&mut self) -> &mut TimerStruct;
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
/// The timer object
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
fn ptp_timer(&self) -> &PTP_TIMER;
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
/// The critical section
|
||||||
|
fn critical(&self) -> &CRITICAL_SECTION;
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
/// The critical section (mut)
|
||||||
|
fn critical_mut(&mut self) -> &mut CRITICAL_SECTION;
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
/// The timeout in milli sec
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
fn milli_sec(&self) -> i64;
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
/// The timeout in milli sec (mut ref)
|
||||||
|
fn millis_sec_mut(&mut self) -> &mut i64;
|
||||||
|
#[cfg(not(all(unix, feature = "std")))]
|
||||||
|
/// Handle timeout for batch mode timeout
|
||||||
|
fn handle_timeout(&mut self) -> bool;
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
/// Handle timeout for batch mode timeout
|
||||||
|
fn handle_timeout(&mut self, data: &mut InProcessExecutorHandlerData) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasTimeout for InProcessHooks {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
fn timer(&self) -> &TimerStruct {
|
||||||
|
&self.timer
|
||||||
|
}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
fn timer_mut(&mut self) -> &mut TimerStruct {
|
||||||
|
&mut self.timer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
fn ptp_timer(&self) -> &PTP_TIMER {
|
||||||
|
self.timer().ptp_timer()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
fn critical(&self) -> &CRITICAL_SECTION {
|
||||||
|
self.timer().critical()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
fn critical_mut(&mut self) -> &mut CRITICAL_SECTION {
|
||||||
|
self.timer_mut().critical_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
fn milli_sec(&self) -> i64 {
|
||||||
|
self.timer().milli_sec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
fn millis_sec_mut(&mut self) -> &mut i64 {
|
||||||
|
self.timer_mut().milli_sec_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(all(unix, feature = "std")))]
|
||||||
|
fn handle_timeout(&mut self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
#[allow(unused)]
|
||||||
|
fn handle_timeout(&mut self, data: &mut InProcessExecutorHandlerData) -> bool {
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
if !self.timer().batch_mode {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//eprintln!("handle_timeout {:?} {}", self.avg_exec_time, self.avg_mul_k);
|
||||||
|
let cur_time = current_time();
|
||||||
|
if !data.is_valid() {
|
||||||
|
// outside the target
|
||||||
|
unsafe {
|
||||||
|
let disarmed: libc::itimerspec = zeroed();
|
||||||
|
libc::timer_settime(
|
||||||
|
self.timer_mut().timerid,
|
||||||
|
0,
|
||||||
|
addr_of!(disarmed),
|
||||||
|
null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let elapsed = cur_time - self.timer().tmout_start_time;
|
||||||
|
// set timer the next exec
|
||||||
|
if self.timer().executions > 0 {
|
||||||
|
self.timer_mut().avg_exec_time = elapsed / self.timer().executions;
|
||||||
|
self.timer_mut().executions = 0;
|
||||||
|
}
|
||||||
|
self.timer_mut().avg_mul_k += 1;
|
||||||
|
self.timer_mut().last_signal_time = cur_time;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let elapsed_run = cur_time - self.timer_mut().start_time;
|
||||||
|
if elapsed_run < self.timer_mut().exec_tmout {
|
||||||
|
// fp, reset timeout
|
||||||
|
unsafe {
|
||||||
|
libc::timer_settime(
|
||||||
|
self.timer_mut().timerid,
|
||||||
|
0,
|
||||||
|
addr_of!(self.timer_mut().itimerspec),
|
||||||
|
null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if self.timer().executions > 0 {
|
||||||
|
let elapsed = cur_time - self.timer_mut().tmout_start_time;
|
||||||
|
self.timer_mut().avg_exec_time = elapsed / self.timer().executions;
|
||||||
|
self.timer_mut().executions = 0; // It will be 1 when the exec finish
|
||||||
|
}
|
||||||
|
self.timer_mut().tmout_start_time = current_time();
|
||||||
|
self.timer_mut().avg_mul_k += 1;
|
||||||
|
self.timer_mut().last_signal_time = cur_time;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecutorHook for InProcessHooks {
|
||||||
|
fn init<E: HasObservers, S>(&mut self, _state: &mut S) {}
|
||||||
|
|
||||||
|
/// Call before running a target.
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn pre_exec<EM, I, S, Z>(&mut self, fuzzer: &mut Z, state: &mut S, mgr: &mut EM, input: &I) {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
{
|
||||||
|
let data = unsafe { &mut GLOBAL_STATE };
|
||||||
|
data.crash_handler = self.crash_handler;
|
||||||
|
data.timeout_handler = self.timeout_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
self.timer_mut().set_timer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call after running a target.
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
fn post_exec<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) {
|
||||||
|
// let _data = unsafe { &mut GLOBAL_STATE };
|
||||||
|
// timeout stuff
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
self.timer_mut().unset_timer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InProcessHooks {
|
||||||
|
/// Create new [`InProcessHooks`].
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub fn new<E, EM, OF, Z>(exec_tmout: Duration) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
E: Executor<EM, Z> + HasObservers + HasInProcessHooks,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
#[cfg_attr(miri, allow(unused_variables))]
|
||||||
|
unsafe {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
unix_signal_handler::setup_panic_hook::<E, EM, OF, Z>();
|
||||||
|
#[cfg(all(not(miri), unix, feature = "std"))]
|
||||||
|
setup_signal_handler(data)?;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
Ok(Self {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
crash_handler: unix_signal_handler::inproc_crash_handler::<E, EM, OF, Z>
|
||||||
|
as *const c_void,
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
timeout_handler: unix_signal_handler::inproc_timeout_handler::<E, EM, OF, Z>
|
||||||
|
as *const _,
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
timer: TimerStruct::new(exec_tmout),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create new [`InProcessHooks`].
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn new<E, EM, OF, Z>(exec_tmout: Duration) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
E: Executor<EM, Z> + HasObservers + HasInProcessHooks,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: State + HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
let ret;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
unsafe {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
crate::executors::hooks::windows::windows_exception_handler::setup_panic_hook::<
|
||||||
|
E,
|
||||||
|
EM,
|
||||||
|
OF,
|
||||||
|
Z,
|
||||||
|
>();
|
||||||
|
setup_exception_handler(data)?;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
let crash_handler =
|
||||||
|
crate::executors::hooks::windows::windows_exception_handler::inproc_crash_handler::<
|
||||||
|
E,
|
||||||
|
EM,
|
||||||
|
OF,
|
||||||
|
Z,
|
||||||
|
> as *const _;
|
||||||
|
let timeout_handler =
|
||||||
|
crate::executors::hooks::windows::windows_exception_handler::inproc_timeout_handler::<
|
||||||
|
E,
|
||||||
|
EM,
|
||||||
|
OF,
|
||||||
|
Z,
|
||||||
|
> as *const c_void;
|
||||||
|
let timer = TimerStruct::new(exec_tmout, timeout_handler);
|
||||||
|
ret = Ok(Self {
|
||||||
|
crash_handler,
|
||||||
|
timeout_handler,
|
||||||
|
timer,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
{
|
||||||
|
ret = Ok(Self {});
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new [`InProcessHooks`]
|
||||||
|
#[cfg(all(not(unix), not(windows)))]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub fn new<E, EM, OF, Z>(exec_tmout: Duration) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
E: Executor<EM, Z> + HasObservers + HasInProcessHooks,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
#[cfg_attr(miri, allow(unused_variables))]
|
||||||
|
let ret = Self {};
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace the handlers with `nop` handlers, deactivating the handlers
|
||||||
|
#[must_use]
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub fn nop() -> Self {
|
||||||
|
Self {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
crash_handler: ptr::null(),
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
timeout_handler: ptr::null(),
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
timer: TimerStruct::new(Duration::from_millis(5000)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The global state of the in-process harness.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InProcessExecutorHandlerData {
|
||||||
|
/// the pointer to the state
|
||||||
|
pub state_ptr: *mut c_void,
|
||||||
|
/// the pointer to the event mgr
|
||||||
|
pub event_mgr_ptr: *mut c_void,
|
||||||
|
/// the pointer to the fuzzer
|
||||||
|
pub fuzzer_ptr: *mut c_void,
|
||||||
|
/// the pointer to the executor
|
||||||
|
pub executor_ptr: *const c_void,
|
||||||
|
pub(crate) current_input_ptr: *const c_void,
|
||||||
|
pub(crate) in_handler: bool,
|
||||||
|
|
||||||
|
/// The timeout handler
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub(crate) crash_handler: *const c_void,
|
||||||
|
/// The timeout handler
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub(crate) timeout_handler: *const c_void,
|
||||||
|
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
pub(crate) ptp_timer: Option<PTP_TIMER>,
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
pub(crate) in_target: u64,
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
pub(crate) critical: *mut c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for InProcessExecutorHandlerData {}
|
||||||
|
unsafe impl Sync for InProcessExecutorHandlerData {}
|
||||||
|
|
||||||
|
impl InProcessExecutorHandlerData {
|
||||||
|
#[cfg(any(unix, feature = "std"))]
|
||||||
|
pub(crate) fn executor_mut<'a, E>(&self) -> &'a mut E {
|
||||||
|
unsafe { (self.executor_ptr as *mut E).as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(unix, feature = "std"))]
|
||||||
|
pub(crate) fn state_mut<'a, S>(&self) -> &'a mut S {
|
||||||
|
unsafe { (self.state_ptr as *mut S).as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(unix, feature = "std"))]
|
||||||
|
pub(crate) fn event_mgr_mut<'a, EM>(&self) -> &'a mut EM {
|
||||||
|
unsafe { (self.event_mgr_ptr as *mut EM).as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(unix, feature = "std"))]
|
||||||
|
pub(crate) fn fuzzer_mut<'a, Z>(&self) -> &'a mut Z {
|
||||||
|
unsafe { (self.fuzzer_ptr as *mut Z).as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(unix, feature = "std"))]
|
||||||
|
pub(crate) fn take_current_input<'a, I>(&mut self) -> &'a I {
|
||||||
|
let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() };
|
||||||
|
self.current_input_ptr = ptr::null();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(unix, feature = "std"))]
|
||||||
|
pub(crate) fn is_valid(&self) -> bool {
|
||||||
|
!self.current_input_ptr.is_null()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(unix, feature = "std"))]
|
||||||
|
pub(crate) fn set_in_handler(&mut self, v: bool) -> bool {
|
||||||
|
let old = self.in_handler;
|
||||||
|
self.in_handler = v;
|
||||||
|
old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exception handling needs some nasty unsafe.
|
||||||
|
pub(crate) static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHandlerData {
|
||||||
|
// The state ptr for signal handling
|
||||||
|
state_ptr: null_mut(),
|
||||||
|
// The event manager ptr for signal handling
|
||||||
|
event_mgr_ptr: null_mut(),
|
||||||
|
// The fuzzer ptr for signal handling
|
||||||
|
fuzzer_ptr: null_mut(),
|
||||||
|
// The executor ptr for signal handling
|
||||||
|
executor_ptr: ptr::null(),
|
||||||
|
// The current input for signal handling
|
||||||
|
current_input_ptr: ptr::null(),
|
||||||
|
|
||||||
|
in_handler: false,
|
||||||
|
|
||||||
|
// The crash handler fn
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
crash_handler: ptr::null(),
|
||||||
|
// The timeout handler fn
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
timeout_handler: ptr::null(),
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
ptp_timer: None,
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
in_target: 0,
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
critical: null_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Get the inprocess [`crate::state::State`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn inprocess_get_state<'a, S>() -> Option<&'a mut S> {
|
||||||
|
unsafe { (GLOBAL_STATE.state_ptr as *mut S).as_mut() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the [`crate::events::EventManager`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn inprocess_get_event_manager<'a, EM>() -> Option<&'a mut EM> {
|
||||||
|
unsafe { (GLOBAL_STATE.event_mgr_ptr as *mut EM).as_mut() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the inprocess [`crate::fuzzer::Fuzzer`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn inprocess_get_fuzzer<'a, F>() -> Option<&'a mut F> {
|
||||||
|
unsafe { (GLOBAL_STATE.fuzzer_ptr as *mut F).as_mut() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the inprocess [`Executor`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn inprocess_get_executor<'a, E>() -> Option<&'a mut E> {
|
||||||
|
unsafe { (GLOBAL_STATE.executor_ptr as *mut E).as_mut() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the inprocess input
|
||||||
|
#[must_use]
|
||||||
|
pub fn inprocess_get_input<'a, I>() -> Option<&'a I> {
|
||||||
|
unsafe { (GLOBAL_STATE.current_input_ptr as *const I).as_ref() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Know if we ar eexecuting in a crash/timeout handler
|
||||||
|
#[must_use]
|
||||||
|
pub fn inprocess_in_handler() -> bool {
|
||||||
|
unsafe { GLOBAL_STATE.in_handler }
|
||||||
|
}
|
172
libafl/src/executors/hooks/inprocess_fork.rs
Normal file
172
libafl/src/executors/hooks/inprocess_fork.rs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
//! The hook for the `InProcessForkExecutor`
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::{
|
||||||
|
ffi::c_void,
|
||||||
|
ptr::null,
|
||||||
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
|
};
|
||||||
|
use std::intrinsics::transmute;
|
||||||
|
|
||||||
|
#[cfg(not(miri))]
|
||||||
|
use libafl_bolts::os::unix_signals::setup_signal_handler;
|
||||||
|
use libafl_bolts::os::unix_signals::{ucontext_t, Handler, Signal};
|
||||||
|
use libc::siginfo_t;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
executors::{
|
||||||
|
common_signals,
|
||||||
|
hooks::ExecutorHook,
|
||||||
|
inprocess_fork::{child_signal_handlers, ForkHandlerFuncPtr},
|
||||||
|
HasObservers,
|
||||||
|
},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The inmem fork executor's hooks.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InChildProcessHooks {
|
||||||
|
/// On crash C function pointer
|
||||||
|
pub crash_handler: *const c_void,
|
||||||
|
/// On timeout C function pointer
|
||||||
|
pub timeout_handler: *const c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecutorHook for InChildProcessHooks {
|
||||||
|
/// Init this hook
|
||||||
|
fn init<E: HasObservers, S>(&mut self, _state: &mut S) {}
|
||||||
|
|
||||||
|
/// Call before running a target.
|
||||||
|
fn pre_exec<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut FORK_EXECUTOR_GLOBAL_DATA;
|
||||||
|
data.crash_handler = self.crash_handler;
|
||||||
|
data.timeout_handler = self.timeout_handler;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_exec<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InChildProcessHooks {
|
||||||
|
/// Create new [`InChildProcessHooks`].
|
||||||
|
pub fn new<E>() -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
E: HasObservers,
|
||||||
|
{
|
||||||
|
#[cfg_attr(miri, allow(unused_variables))]
|
||||||
|
unsafe {
|
||||||
|
let data = &mut FORK_EXECUTOR_GLOBAL_DATA;
|
||||||
|
// child_signal_handlers::setup_child_panic_hook::<E, I, OT, S>();
|
||||||
|
#[cfg(not(miri))]
|
||||||
|
setup_signal_handler(data)?;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
Ok(Self {
|
||||||
|
crash_handler: child_signal_handlers::child_crash_handler::<E> as *const c_void,
|
||||||
|
timeout_handler: child_signal_handlers::child_timeout_handler::<E> as *const c_void,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace the hooks with `nop` hooks, deactivating the hooks
|
||||||
|
#[must_use]
|
||||||
|
pub fn nop() -> Self {
|
||||||
|
Self {
|
||||||
|
crash_handler: null(),
|
||||||
|
timeout_handler: null(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The global state of the in-process-fork harness.
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct InProcessForkExecutorGlobalData {
|
||||||
|
/// Stores a pointer to the fork executor struct
|
||||||
|
pub executor_ptr: *const c_void,
|
||||||
|
/// Stores a pointer to the state
|
||||||
|
pub state_ptr: *const c_void,
|
||||||
|
/// Stores a pointer to the current input
|
||||||
|
pub current_input_ptr: *const c_void,
|
||||||
|
/// Stores a pointer to the crash_handler function
|
||||||
|
pub crash_handler: *const c_void,
|
||||||
|
/// Stores a pointer to the timeout_handler function
|
||||||
|
pub timeout_handler: *const c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for InProcessForkExecutorGlobalData {}
|
||||||
|
|
||||||
|
unsafe impl Send for InProcessForkExecutorGlobalData {}
|
||||||
|
|
||||||
|
impl InProcessForkExecutorGlobalData {
|
||||||
|
pub(crate) fn executor_mut<'a, E>(&self) -> &'a mut E {
|
||||||
|
unsafe { (self.executor_ptr as *mut E).as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn state_mut<'a, S>(&self) -> &'a mut S {
|
||||||
|
unsafe { (self.state_ptr as *mut S).as_mut().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fn current_input<'a, I>(&self) -> &'a I {
|
||||||
|
unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() }
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub(crate) fn take_current_input<'a, I>(&mut self) -> &'a I {
|
||||||
|
let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() };
|
||||||
|
self.current_input_ptr = null();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_valid(&self) -> bool {
|
||||||
|
!self.current_input_ptr.is_null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// a static variable storing the global state
|
||||||
|
|
||||||
|
pub(crate) static mut FORK_EXECUTOR_GLOBAL_DATA: InProcessForkExecutorGlobalData =
|
||||||
|
InProcessForkExecutorGlobalData {
|
||||||
|
executor_ptr: null(),
|
||||||
|
state_ptr: null(),
|
||||||
|
current_input_ptr: null(),
|
||||||
|
crash_handler: null(),
|
||||||
|
timeout_handler: null(),
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Handler for InProcessForkExecutorGlobalData {
|
||||||
|
fn handle(&mut self, signal: Signal, info: &mut siginfo_t, context: Option<&mut ucontext_t>) {
|
||||||
|
match signal {
|
||||||
|
Signal::SigUser2 | Signal::SigAlarm => unsafe {
|
||||||
|
if !FORK_EXECUTOR_GLOBAL_DATA.timeout_handler.is_null() {
|
||||||
|
let func: ForkHandlerFuncPtr =
|
||||||
|
transmute(FORK_EXECUTOR_GLOBAL_DATA.timeout_handler);
|
||||||
|
(func)(signal, info, context, &mut FORK_EXECUTOR_GLOBAL_DATA);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => unsafe {
|
||||||
|
if !FORK_EXECUTOR_GLOBAL_DATA.crash_handler.is_null() {
|
||||||
|
let func: ForkHandlerFuncPtr =
|
||||||
|
transmute(FORK_EXECUTOR_GLOBAL_DATA.crash_handler);
|
||||||
|
(func)(signal, info, context, &mut FORK_EXECUTOR_GLOBAL_DATA);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signals(&self) -> Vec<Signal> {
|
||||||
|
common_signals()
|
||||||
|
}
|
||||||
|
}
|
102
libafl/src/executors/hooks/mod.rs
Normal file
102
libafl/src/executors/hooks/mod.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
//! Hooks for the executors.
|
||||||
|
//! These will be executed right before and after the executor's harness run.
|
||||||
|
|
||||||
|
use crate::executors::HasObservers;
|
||||||
|
|
||||||
|
/// windows crash/timeout handler and asan death callback
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub mod windows;
|
||||||
|
|
||||||
|
/// *nix crash handler
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
pub mod unix;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
/// The hook for inprocess fork executor
|
||||||
|
pub mod inprocess_fork;
|
||||||
|
|
||||||
|
/// The hook for inprocess executor
|
||||||
|
pub mod inprocess;
|
||||||
|
|
||||||
|
/// Timer-related stuff
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod timer;
|
||||||
|
|
||||||
|
/// The hook that runs before and after the executor runs the target
|
||||||
|
pub trait ExecutorHook {
|
||||||
|
/// Init this hook
|
||||||
|
fn init<E: HasObservers, S>(&mut self, state: &mut S);
|
||||||
|
/// The hook that runs before runs the target
|
||||||
|
fn pre_exec<EM, I, S, Z>(&mut self, fuzzer: &mut Z, state: &mut S, mgr: &mut EM, input: &I);
|
||||||
|
/// The hook that runs before runs the target
|
||||||
|
fn post_exec<EM, I, S, Z>(&mut self, fuzzer: &mut Z, state: &mut S, mgr: &mut EM, input: &I);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The hook that runs before and after the executor runs the target
|
||||||
|
pub trait ExecutorHooksTuple {
|
||||||
|
/// Init these hooks
|
||||||
|
fn init_all<E: HasObservers, S>(&mut self, state: &mut S);
|
||||||
|
/// The hooks that runs before runs the target
|
||||||
|
fn pre_exec_all<EM, I, S, Z>(&mut self, fuzzer: &mut Z, state: &mut S, mgr: &mut EM, input: &I);
|
||||||
|
/// The hooks that runs after runs the target
|
||||||
|
fn post_exec_all<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExecutorHooksTuple for () {
|
||||||
|
fn init_all<E, S>(&mut self, _state: &mut S) {}
|
||||||
|
fn pre_exec_all<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
fn post_exec_all<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut S,
|
||||||
|
_mgr: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Head, Tail> ExecutorHooksTuple for (Head, Tail)
|
||||||
|
where
|
||||||
|
Head: ExecutorHook,
|
||||||
|
Tail: ExecutorHooksTuple,
|
||||||
|
{
|
||||||
|
fn init_all<E: HasObservers, S>(&mut self, state: &mut S) {
|
||||||
|
self.0.init::<E, S>(state);
|
||||||
|
self.1.init_all::<E, S>(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pre_exec_all<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
) {
|
||||||
|
self.0.pre_exec(fuzzer, state, mgr, input);
|
||||||
|
self.1.pre_exec_all(fuzzer, state, mgr, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_exec_all<EM, I, S, Z>(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
mgr: &mut EM,
|
||||||
|
input: &I,
|
||||||
|
) {
|
||||||
|
self.0.post_exec(fuzzer, state, mgr, input);
|
||||||
|
self.1.post_exec_all(fuzzer, state, mgr, input);
|
||||||
|
}
|
||||||
|
}
|
378
libafl/src/executors/hooks/timer.rs
Normal file
378
libafl/src/executors/hooks/timer.rs
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
//! The struct `TimerStruct` will absorb all the difference in timeout implementation in various system.
|
||||||
|
use core::time::Duration;
|
||||||
|
#[cfg(any(windows, target_os = "linux"))]
|
||||||
|
use core::{
|
||||||
|
ffi::c_void,
|
||||||
|
ptr::{addr_of_mut, write_volatile},
|
||||||
|
};
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use core::{
|
||||||
|
mem::zeroed,
|
||||||
|
ptr::{addr_of, null_mut},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
pub const ITIMER_REAL: core::ffi::c_int = 0;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use libafl_bolts::current_time;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use windows::Win32::{
|
||||||
|
Foundation::FILETIME,
|
||||||
|
System::Threading::{
|
||||||
|
CreateThreadpoolTimer, EnterCriticalSection, InitializeCriticalSection,
|
||||||
|
LeaveCriticalSection, SetThreadpoolTimer, CRITICAL_SECTION, PTP_CALLBACK_INSTANCE,
|
||||||
|
PTP_TIMER, TP_CALLBACK_ENVIRON_V3,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(any(windows, target_os = "linux"))]
|
||||||
|
use crate::executors::hooks::inprocess::GLOBAL_STATE;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub(crate) struct Timeval {
|
||||||
|
pub tv_sec: i64,
|
||||||
|
pub tv_usec: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
impl core::fmt::Debug for Timeval {
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Timeval {{ tv_sec: {:?}, tv_usec: {:?} (tv: {:?}) }}",
|
||||||
|
self.tv_sec,
|
||||||
|
self.tv_usec,
|
||||||
|
Duration::new(self.tv_sec as _, (self.tv_usec * 1000) as _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub(crate) struct Itimerval {
|
||||||
|
pub it_interval: Timeval,
|
||||||
|
pub it_value: Timeval,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix, not(target_os = "linux")))]
|
||||||
|
extern "C" {
|
||||||
|
pub fn setitimer(
|
||||||
|
which: libc::c_int,
|
||||||
|
new_value: *mut Itimerval,
|
||||||
|
old_value: *mut Itimerval,
|
||||||
|
) -> libc::c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The strcut about all the internals of the timer.
|
||||||
|
/// This struct absorb all platform specific differences about timer.
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct TimerStruct {
|
||||||
|
// timeout time (windows)
|
||||||
|
#[cfg(windows)]
|
||||||
|
milli_sec: i64,
|
||||||
|
#[cfg(windows)]
|
||||||
|
ptp_timer: PTP_TIMER,
|
||||||
|
#[cfg(windows)]
|
||||||
|
critical: CRITICAL_SECTION,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) batch_mode: bool,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) exec_tmout: Duration,
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
itimerval: Itimerval,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) timerid: libc::timer_t,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) itimerspec: libc::itimerspec,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) executions: u32,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) avg_mul_k: u32,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) last_signal_time: Duration,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) avg_exec_time: Duration,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) start_time: Duration,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub(crate) tmout_start_time: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", windows))]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
type PTP_TIMER_CALLBACK = unsafe extern "system" fn(
|
||||||
|
param0: PTP_CALLBACK_INSTANCE,
|
||||||
|
param1: *mut c_void,
|
||||||
|
param2: PTP_TIMER,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl TimerStruct {
|
||||||
|
/// Timeout value in milli seconds
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn milli_sec(&self) -> i64 {
|
||||||
|
self.milli_sec
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
/// Timeout value in milli seconds (mut ref)
|
||||||
|
pub fn milli_sec_mut(&mut self) -> &mut i64 {
|
||||||
|
&mut self.milli_sec
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The timer object for windows
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn ptp_timer(&self) -> &PTP_TIMER {
|
||||||
|
&self.ptp_timer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
/// The timer object for windows
|
||||||
|
pub fn ptp_timer_mut(&mut self) -> &mut PTP_TIMER {
|
||||||
|
&mut self.ptp_timer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The critical section, we need to use critical section to access the globals
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn critical(&self) -> &CRITICAL_SECTION {
|
||||||
|
&self.critical
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
/// The critical section (mut ref), we need to use critical section to access the globals
|
||||||
|
pub fn critical_mut(&mut self) -> &mut CRITICAL_SECTION {
|
||||||
|
&mut self.critical
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `TimerStruct` with the specified timeout
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
pub fn new(exec_tmout: Duration) -> Self {
|
||||||
|
let milli_sec = exec_tmout.as_millis();
|
||||||
|
let it_value = Timeval {
|
||||||
|
tv_sec: (milli_sec / 1000) as i64,
|
||||||
|
tv_usec: (milli_sec % 1000) as i64,
|
||||||
|
};
|
||||||
|
let it_interval = Timeval {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_usec: 0,
|
||||||
|
};
|
||||||
|
let itimerval = Itimerval {
|
||||||
|
it_interval,
|
||||||
|
it_value,
|
||||||
|
};
|
||||||
|
Self { itimerval }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
/// # Safety
|
||||||
|
/// This function calls transmute to setup the timeout handler for windows
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[must_use]
|
||||||
|
pub unsafe fn new(exec_tmout: Duration, timeout_handler: *const c_void) -> Self {
|
||||||
|
let milli_sec = exec_tmout.as_millis() as i64;
|
||||||
|
|
||||||
|
let timeout_handler: PTP_TIMER_CALLBACK = unsafe { std::mem::transmute(timeout_handler) };
|
||||||
|
let ptp_timer = unsafe {
|
||||||
|
CreateThreadpoolTimer(
|
||||||
|
Some(timeout_handler),
|
||||||
|
Some(addr_of_mut!(GLOBAL_STATE) as *mut c_void),
|
||||||
|
Some(&TP_CALLBACK_ENVIRON_V3::default()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.expect("CreateThreadpoolTimer failed!");
|
||||||
|
|
||||||
|
let mut critical = CRITICAL_SECTION::default();
|
||||||
|
unsafe {
|
||||||
|
InitializeCriticalSection(&mut critical);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
milli_sec,
|
||||||
|
ptp_timer,
|
||||||
|
critical,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[must_use]
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
/// Create a `TimerStruct` with the specified timeout
|
||||||
|
pub fn new(exec_tmout: Duration) -> Self {
|
||||||
|
let milli_sec = exec_tmout.as_millis();
|
||||||
|
let it_value = libc::timespec {
|
||||||
|
tv_sec: (milli_sec / 1000) as _,
|
||||||
|
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
||||||
|
};
|
||||||
|
let it_interval = libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
};
|
||||||
|
let itimerspec = libc::itimerspec {
|
||||||
|
it_interval,
|
||||||
|
it_value,
|
||||||
|
};
|
||||||
|
let mut timerid: libc::timer_t = null_mut();
|
||||||
|
unsafe {
|
||||||
|
#[cfg(not(miri))]
|
||||||
|
// creates a new per-process interval timer
|
||||||
|
libc::timer_create(libc::CLOCK_MONOTONIC, null_mut(), addr_of_mut!(timerid));
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
batch_mode: false,
|
||||||
|
itimerspec,
|
||||||
|
timerid,
|
||||||
|
exec_tmout,
|
||||||
|
executions: 0,
|
||||||
|
avg_mul_k: 1,
|
||||||
|
last_signal_time: Duration::ZERO,
|
||||||
|
avg_exec_time: Duration::ZERO,
|
||||||
|
start_time: Duration::ZERO,
|
||||||
|
tmout_start_time: Duration::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[must_use]
|
||||||
|
/// Constructor but use batch mode
|
||||||
|
pub fn batch_mode(exec_tmout: Duration) -> Self {
|
||||||
|
let mut me = Self::new(exec_tmout);
|
||||||
|
me.batch_mode = true;
|
||||||
|
me
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
/// Set up timer
|
||||||
|
pub fn set_timer(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
setitimer(ITIMER_REAL, &mut self.itimerval, core::ptr::null_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[allow(clippy::cast_sign_loss)]
|
||||||
|
/// Set timer
|
||||||
|
pub fn set_timer(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
|
||||||
|
write_volatile(&mut data.ptp_timer, Some(*self.ptp_timer()));
|
||||||
|
write_volatile(
|
||||||
|
&mut data.critical,
|
||||||
|
addr_of_mut!(*self.critical_mut()) as *mut c_void,
|
||||||
|
);
|
||||||
|
let tm: i64 = -self.milli_sec() * 10 * 1000;
|
||||||
|
let ft = FILETIME {
|
||||||
|
dwLowDateTime: (tm & 0xffffffff) as u32,
|
||||||
|
dwHighDateTime: (tm >> 32) as u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
// enter critical section then set timer
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
EnterCriticalSection(self.critical_mut());
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
data.in_target = 1;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
LeaveCriticalSection(self.critical_mut());
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
SetThreadpoolTimer(*self.ptp_timer(), Some(&ft), 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set up timer
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn set_timer(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if self.batch_mode {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
write_volatile(&mut data.executor_ptr, self as *mut _ as *mut c_void);
|
||||||
|
|
||||||
|
if self.executions == 0 {
|
||||||
|
libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut());
|
||||||
|
self.tmout_start_time = current_time();
|
||||||
|
}
|
||||||
|
self.start_time = current_time();
|
||||||
|
} else {
|
||||||
|
#[cfg(not(miri))]
|
||||||
|
libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
/// Disalarm timer
|
||||||
|
pub fn unset_timer(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let mut itimerval_zero: Itimerval = core::mem::zeroed();
|
||||||
|
setitimer(ITIMER_REAL, &mut itimerval_zero, core::ptr::null_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disalarm timer
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub fn unset_timer(&mut self) {
|
||||||
|
if self.batch_mode {
|
||||||
|
unsafe {
|
||||||
|
let elapsed = current_time() - self.tmout_start_time;
|
||||||
|
// elapsed may be > than tmout in case of received but ingored signal
|
||||||
|
if elapsed > self.exec_tmout
|
||||||
|
|| self.exec_tmout - elapsed < self.avg_exec_time * self.avg_mul_k
|
||||||
|
{
|
||||||
|
let disarmed: libc::itimerspec = zeroed();
|
||||||
|
libc::timer_settime(self.timerid, 0, addr_of!(disarmed), null_mut());
|
||||||
|
// set timer the next exec
|
||||||
|
if self.executions > 0 {
|
||||||
|
self.avg_exec_time = elapsed / self.executions;
|
||||||
|
self.executions = 0;
|
||||||
|
}
|
||||||
|
// readjust K
|
||||||
|
if self.last_signal_time > self.exec_tmout * self.avg_mul_k
|
||||||
|
&& self.avg_mul_k > 1
|
||||||
|
{
|
||||||
|
self.avg_mul_k -= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.executions += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let disarmed: libc::itimerspec = zeroed();
|
||||||
|
#[cfg(not(miri))]
|
||||||
|
libc::timer_settime(self.timerid, 0, addr_of!(disarmed), null_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
/// Disalarm
|
||||||
|
pub fn unset_timer(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
EnterCriticalSection(self.critical_mut());
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
// Timeout handler will do nothing after we increment in_target value.
|
||||||
|
data.in_target = 0;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
LeaveCriticalSection(self.critical_mut());
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
// previously this wa post_run_reset
|
||||||
|
SetThreadpoolTimer(*self.ptp_timer(), None, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
272
libafl/src/executors/hooks/unix.rs
Normal file
272
libafl/src/executors/hooks/unix.rs
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
/// The inprocess executor singal handling code for unix
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub mod unix_signal_handler {
|
||||||
|
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||||
|
use core::mem::transmute;
|
||||||
|
use std::{io::Write, panic};
|
||||||
|
|
||||||
|
use libafl_bolts::os::unix_signals::{ucontext_t, Handler, Signal};
|
||||||
|
use libc::siginfo_t;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
events::{EventFirer, EventRestarter},
|
||||||
|
executors::{
|
||||||
|
common_signals,
|
||||||
|
hooks::inprocess::{HasTimeout, InProcessExecutorHandlerData, GLOBAL_STATE},
|
||||||
|
inprocess::{run_observers_and_save_state, HasInProcessHooks},
|
||||||
|
Executor, ExitKind, HasObservers,
|
||||||
|
},
|
||||||
|
feedbacks::Feedback,
|
||||||
|
fuzzer::HasObjective,
|
||||||
|
inputs::{Input, UsesInput},
|
||||||
|
state::{HasCorpus, HasExecutions, HasSolutions},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) type HandlerFuncPtr = unsafe fn(
|
||||||
|
Signal,
|
||||||
|
&mut siginfo_t,
|
||||||
|
Option<&mut ucontext_t>,
|
||||||
|
data: &mut InProcessExecutorHandlerData,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// A handler that does nothing.
|
||||||
|
/*pub fn nop_handler(
|
||||||
|
_signal: Signal,
|
||||||
|
_info: &mut siginfo_t,
|
||||||
|
_context: Option<&mut ucontext_t>,
|
||||||
|
_data: &mut InProcessExecutorHandlerData,
|
||||||
|
) {
|
||||||
|
}*/
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
impl Handler for InProcessExecutorHandlerData {
|
||||||
|
fn handle(
|
||||||
|
&mut self,
|
||||||
|
signal: Signal,
|
||||||
|
info: &mut siginfo_t,
|
||||||
|
context: Option<&mut ucontext_t>,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
let in_handler = data.set_in_handler(true);
|
||||||
|
match signal {
|
||||||
|
Signal::SigUser2 | Signal::SigAlarm => {
|
||||||
|
if !data.timeout_handler.is_null() {
|
||||||
|
let func: HandlerFuncPtr = transmute(data.timeout_handler);
|
||||||
|
(func)(signal, info, context, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if !data.crash_handler.is_null() {
|
||||||
|
let func: HandlerFuncPtr = transmute(data.crash_handler);
|
||||||
|
(func)(signal, info, context, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.set_in_handler(in_handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signals(&self) -> Vec<Signal> {
|
||||||
|
common_signals()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// invokes the `post_exec` hook on all observer in case of panic
|
||||||
|
pub fn setup_panic_hook<E, EM, OF, Z>()
|
||||||
|
where
|
||||||
|
E: HasObservers,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
let old_hook = panic::take_hook();
|
||||||
|
panic::set_hook(Box::new(move |panic_info| {
|
||||||
|
old_hook(panic_info);
|
||||||
|
let data = unsafe { &mut GLOBAL_STATE };
|
||||||
|
let in_handler = data.set_in_handler(true);
|
||||||
|
if data.is_valid() {
|
||||||
|
// We are fuzzing!
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
let fuzzer = data.fuzzer_mut::<Z>();
|
||||||
|
let event_mgr = data.event_mgr_mut::<EM>();
|
||||||
|
|
||||||
|
run_observers_and_save_state::<E, EM, OF, Z>(
|
||||||
|
executor,
|
||||||
|
state,
|
||||||
|
input,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
ExitKind::Crash,
|
||||||
|
);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
libc::_exit(128 + 6);
|
||||||
|
} // SIGABRT exit code
|
||||||
|
}
|
||||||
|
data.set_in_handler(in_handler);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Timeout-Handler for in-process fuzzing.
|
||||||
|
/// It will store the current State to shmem, then exit.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Well, signal handling is not safe
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
pub unsafe fn inproc_timeout_handler<E, EM, OF, Z>(
|
||||||
|
_signal: Signal,
|
||||||
|
_info: &mut siginfo_t,
|
||||||
|
_context: Option<&mut ucontext_t>,
|
||||||
|
data: &mut InProcessExecutorHandlerData,
|
||||||
|
) where
|
||||||
|
E: HasObservers + HasInProcessHooks,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
// this stuff is for batch timeout
|
||||||
|
if !data.executor_ptr.is_null()
|
||||||
|
&& data
|
||||||
|
.executor_mut::<E>()
|
||||||
|
.inprocess_hooks_mut()
|
||||||
|
.handle_timeout(data)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !data.is_valid() {
|
||||||
|
log::warn!("TIMEOUT or SIGUSR2 happened, but currently not fuzzing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let event_mgr = data.event_mgr_mut::<EM>();
|
||||||
|
let fuzzer = data.fuzzer_mut::<Z>();
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
|
||||||
|
log::error!("Timeout in fuzz run.");
|
||||||
|
|
||||||
|
run_observers_and_save_state::<E, EM, OF, Z>(
|
||||||
|
executor,
|
||||||
|
state,
|
||||||
|
input,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
ExitKind::Timeout,
|
||||||
|
);
|
||||||
|
log::info!("Exiting");
|
||||||
|
libc::_exit(55);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crash-Handler for in-process fuzzing.
|
||||||
|
/// Will be used for signal handling.
|
||||||
|
/// It will store the current State to shmem, then exit.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Well, signal handling is not safe
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
pub unsafe fn inproc_crash_handler<E, EM, OF, Z>(
|
||||||
|
signal: Signal,
|
||||||
|
_info: &mut siginfo_t,
|
||||||
|
_context: Option<&mut ucontext_t>,
|
||||||
|
data: &mut InProcessExecutorHandlerData,
|
||||||
|
) where
|
||||||
|
E: Executor<EM, Z> + HasObservers,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
|
||||||
|
let _context = _context.map(|p| {
|
||||||
|
&mut *(((p as *mut _ as *mut libc::c_void as usize) + 128) as *mut libc::c_void
|
||||||
|
as *mut ucontext_t)
|
||||||
|
});
|
||||||
|
|
||||||
|
log::error!("Crashed with {signal}");
|
||||||
|
if data.is_valid() {
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
// disarms timeout in case of timeout
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let event_mgr = data.event_mgr_mut::<EM>();
|
||||||
|
let fuzzer = data.fuzzer_mut::<Z>();
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
|
||||||
|
log::error!("Child crashed!");
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut bsod = Vec::new();
|
||||||
|
{
|
||||||
|
let mut writer = std::io::BufWriter::new(&mut bsod);
|
||||||
|
writeln!(writer, "input: {:?}", input.generate_name(0)).unwrap();
|
||||||
|
libafl_bolts::minibsod::generate_minibsod(
|
||||||
|
&mut writer,
|
||||||
|
signal,
|
||||||
|
_info,
|
||||||
|
_context.as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writer.flush().unwrap();
|
||||||
|
}
|
||||||
|
log::error!("{}", std::str::from_utf8(&bsod).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
run_observers_and_save_state::<E, EM, OF, Z>(
|
||||||
|
executor,
|
||||||
|
state,
|
||||||
|
input,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
ExitKind::Crash,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
{
|
||||||
|
log::error!("Double crash\n");
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
let si_addr = (_info._pad[0] as i64) | ((_info._pad[1] as i64) << 32);
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
let si_addr = { _info.si_addr() as usize };
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
"We crashed at addr 0x{si_addr:x}, but are not in the target... Bug in the fuzzer? Exiting."
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut bsod = Vec::new();
|
||||||
|
{
|
||||||
|
let mut writer = std::io::BufWriter::new(&mut bsod);
|
||||||
|
libafl_bolts::minibsod::generate_minibsod(
|
||||||
|
&mut writer,
|
||||||
|
signal,
|
||||||
|
_info,
|
||||||
|
_context.as_deref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writer.flush().unwrap();
|
||||||
|
}
|
||||||
|
log::error!("{}", std::str::from_utf8(&bsod).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
log::error!("Type QUIT to restart the child");
|
||||||
|
let mut line = String::new();
|
||||||
|
while line.trim() != "QUIT" {
|
||||||
|
std::io::stdin().read_line(&mut line).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO tell the parent to not restart
|
||||||
|
}
|
||||||
|
|
||||||
|
libc::_exit(128 + (signal as i32));
|
||||||
|
}
|
||||||
|
}
|
418
libafl/src/executors/hooks/windows.rs
Normal file
418
libafl/src/executors/hooks/windows.rs
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
/// Same as `inproc_crash_handler`, but this is called when address sanitizer exits, not from the exception handler
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
pub mod windows_asan_handler {
|
||||||
|
use alloc::string::String;
|
||||||
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
|
||||||
|
use windows::Win32::System::Threading::{
|
||||||
|
EnterCriticalSection, LeaveCriticalSection, CRITICAL_SECTION,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
events::{EventFirer, EventRestarter},
|
||||||
|
executors::{
|
||||||
|
hooks::inprocess::GLOBAL_STATE, inprocess::run_observers_and_save_state, Executor,
|
||||||
|
ExitKind, HasObservers,
|
||||||
|
},
|
||||||
|
feedbacks::Feedback,
|
||||||
|
fuzzer::HasObjective,
|
||||||
|
inputs::UsesInput,
|
||||||
|
state::{HasCorpus, HasExecutions, HasSolutions},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// ASAN deatch handler
|
||||||
|
pub unsafe extern "C" fn asan_death_handler<E, EM, OF, Z>()
|
||||||
|
where
|
||||||
|
E: Executor<EM, Z> + HasObservers,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
data.set_in_handler(true);
|
||||||
|
// Have we set a timer_before?
|
||||||
|
if data.ptp_timer.is_some() {
|
||||||
|
/*
|
||||||
|
We want to prevent the timeout handler being run while the main thread is executing the crash handler
|
||||||
|
Timeout handler runs if it has access to the critical section or data.in_target == 0
|
||||||
|
Writing 0 to the data.in_target makes the timeout handler makes the timeout handler invalid.
|
||||||
|
*/
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
EnterCriticalSection(data.critical as *mut CRITICAL_SECTION);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
data.in_target = 0;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
LeaveCriticalSection(data.critical as *mut CRITICAL_SECTION);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
log::error!("ASAN detected crash!");
|
||||||
|
if data.current_input_ptr.is_null() {
|
||||||
|
{
|
||||||
|
log::error!("Double crash\n");
|
||||||
|
log::error!(
|
||||||
|
"ASAN detected crash but we're not in the target... Bug in the fuzzer? Exiting.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
{
|
||||||
|
log::error!("Type QUIT to restart the child");
|
||||||
|
let mut line = String::new();
|
||||||
|
while line.trim() != "QUIT" {
|
||||||
|
std::io::stdin().read_line(&mut line).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO tell the parent to not restart
|
||||||
|
} else {
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
// reset timer
|
||||||
|
if data.ptp_timer.is_some() {
|
||||||
|
data.ptp_timer = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let fuzzer = data.fuzzer_mut::<Z>();
|
||||||
|
let event_mgr = data.event_mgr_mut::<EM>();
|
||||||
|
|
||||||
|
log::error!("Child crashed!");
|
||||||
|
|
||||||
|
// Make sure we don't crash in the crash handler forever.
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
|
||||||
|
run_observers_and_save_state::<E, EM, OF, Z>(
|
||||||
|
executor,
|
||||||
|
state,
|
||||||
|
input,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
ExitKind::Crash,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Don't need to exit, Asan will exit for us
|
||||||
|
// ExitProcess(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(windows, feature = "std"))]
|
||||||
|
/// The module to take care of windows crash or timeouts
|
||||||
|
pub mod windows_exception_handler {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::{string::String, vec::Vec};
|
||||||
|
use core::{
|
||||||
|
ffi::c_void,
|
||||||
|
mem::transmute,
|
||||||
|
ptr,
|
||||||
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
|
};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use std::panic;
|
||||||
|
|
||||||
|
use libafl_bolts::os::windows_exceptions::{
|
||||||
|
ExceptionCode, Handler, CRASH_EXCEPTIONS, EXCEPTION_HANDLERS_SIZE, EXCEPTION_POINTERS,
|
||||||
|
};
|
||||||
|
use windows::Win32::System::Threading::{
|
||||||
|
EnterCriticalSection, ExitProcess, LeaveCriticalSection, CRITICAL_SECTION,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
events::{EventFirer, EventRestarter},
|
||||||
|
executors::{
|
||||||
|
hooks::inprocess::{HasTimeout, InProcessExecutorHandlerData, GLOBAL_STATE},
|
||||||
|
inprocess::{run_observers_and_save_state, HasInProcessHooks},
|
||||||
|
Executor, ExitKind, HasObservers,
|
||||||
|
},
|
||||||
|
feedbacks::Feedback,
|
||||||
|
fuzzer::HasObjective,
|
||||||
|
inputs::UsesInput,
|
||||||
|
state::{HasCorpus, HasExecutions, HasSolutions, State},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) type HandlerFuncPtr =
|
||||||
|
unsafe fn(*mut EXCEPTION_POINTERS, &mut InProcessExecutorHandlerData);
|
||||||
|
|
||||||
|
/*pub unsafe fn nop_handler(
|
||||||
|
_code: ExceptionCode,
|
||||||
|
_exception_pointers: *mut EXCEPTION_POINTERS,
|
||||||
|
_data: &mut InProcessExecutorHandlerData,
|
||||||
|
) {
|
||||||
|
}*/
|
||||||
|
|
||||||
|
impl Handler for InProcessExecutorHandlerData {
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
fn handle(&mut self, _code: ExceptionCode, exception_pointers: *mut EXCEPTION_POINTERS) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut GLOBAL_STATE;
|
||||||
|
let in_handler = data.set_in_handler(true);
|
||||||
|
if !data.crash_handler.is_null() {
|
||||||
|
let func: HandlerFuncPtr = transmute(data.crash_handler);
|
||||||
|
(func)(exception_pointers, data);
|
||||||
|
}
|
||||||
|
data.set_in_handler(in_handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exceptions(&self) -> Vec<ExceptionCode> {
|
||||||
|
let crash_list = CRASH_EXCEPTIONS.to_vec();
|
||||||
|
assert!(crash_list.len() < EXCEPTION_HANDLERS_SIZE - 1);
|
||||||
|
crash_list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// invokes the `post_exec` hook on all observer in case of panic
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Well, exception handling is not safe
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub fn setup_panic_hook<E, EM, OF, Z>()
|
||||||
|
where
|
||||||
|
E: HasObservers,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
let old_hook = panic::take_hook();
|
||||||
|
panic::set_hook(Box::new(move |panic_info| {
|
||||||
|
let data = unsafe { &mut GLOBAL_STATE };
|
||||||
|
let in_handler = data.set_in_handler(true);
|
||||||
|
// Have we set a timer_before?
|
||||||
|
unsafe {
|
||||||
|
if data.ptp_timer.is_some() {
|
||||||
|
/*
|
||||||
|
We want to prevent the timeout handler being run while the main thread is executing the crash handler
|
||||||
|
Timeout handler runs if it has access to the critical section or data.in_target == 0
|
||||||
|
Writing 0 to the data.in_target makes the timeout handler makes the timeout handler invalid.
|
||||||
|
*/
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
EnterCriticalSection(data.critical as *mut CRITICAL_SECTION);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
data.in_target = 0;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
LeaveCriticalSection(data.critical as *mut CRITICAL_SECTION);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.is_valid() {
|
||||||
|
// We are fuzzing!
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let fuzzer = data.fuzzer_mut::<Z>();
|
||||||
|
let event_mgr = data.event_mgr_mut::<EM>();
|
||||||
|
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
|
||||||
|
run_observers_and_save_state::<E, EM, OF, Z>(
|
||||||
|
executor,
|
||||||
|
state,
|
||||||
|
input,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
ExitKind::Crash,
|
||||||
|
);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_hook(panic_info);
|
||||||
|
data.set_in_handler(in_handler);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Timeout handler for windows
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Well, exception handling is not safe
|
||||||
|
pub unsafe extern "system" fn inproc_timeout_handler<E, EM, OF, Z>(
|
||||||
|
_p0: *mut u8,
|
||||||
|
global_state: *mut c_void,
|
||||||
|
_p1: *mut u8,
|
||||||
|
) where
|
||||||
|
E: HasObservers + HasInProcessHooks,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: State + HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
let data: &mut InProcessExecutorHandlerData =
|
||||||
|
&mut *(global_state as *mut InProcessExecutorHandlerData);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
EnterCriticalSection((data.critical as *mut CRITICAL_SECTION).as_mut().unwrap());
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
if !data.executor_ptr.is_null()
|
||||||
|
&& data
|
||||||
|
.executor_mut::<E>()
|
||||||
|
.inprocess_hooks_mut()
|
||||||
|
.handle_timeout()
|
||||||
|
{
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
LeaveCriticalSection((data.critical as *mut CRITICAL_SECTION).as_mut().unwrap());
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.in_target == 1 {
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let fuzzer = data.fuzzer_mut::<Z>();
|
||||||
|
let event_mgr = data.event_mgr_mut::<EM>();
|
||||||
|
|
||||||
|
if data.current_input_ptr.is_null() {
|
||||||
|
log::error!("TIMEOUT or SIGUSR2 happened, but currently not fuzzing. Exiting");
|
||||||
|
} else {
|
||||||
|
log::error!("Timeout in fuzz run.");
|
||||||
|
|
||||||
|
let input = (data.current_input_ptr as *const <E::State as UsesInput>::Input)
|
||||||
|
.as_ref()
|
||||||
|
.unwrap();
|
||||||
|
data.current_input_ptr = ptr::null_mut();
|
||||||
|
|
||||||
|
run_observers_and_save_state::<E, EM, OF, Z>(
|
||||||
|
executor,
|
||||||
|
state,
|
||||||
|
input,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
ExitKind::Timeout,
|
||||||
|
);
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
LeaveCriticalSection((data.critical as *mut CRITICAL_SECTION).as_mut().unwrap());
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
// log::info!("TIMER INVOKED!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crash handler for windows
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Well, exception handling is not safe
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
pub unsafe fn inproc_crash_handler<E, EM, OF, Z>(
|
||||||
|
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||||
|
data: &mut InProcessExecutorHandlerData,
|
||||||
|
) where
|
||||||
|
E: Executor<EM, Z> + HasObservers,
|
||||||
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
|
OF: Feedback<E::State>,
|
||||||
|
E::State: HasExecutions + HasSolutions + HasCorpus,
|
||||||
|
Z: HasObjective<Objective = OF, State = E::State>,
|
||||||
|
{
|
||||||
|
// Have we set a timer_before?
|
||||||
|
if data.ptp_timer.is_some() {
|
||||||
|
/*
|
||||||
|
We want to prevent the timeout handler being run while the main thread is executing the crash handler
|
||||||
|
Timeout handler runs if it has access to the critical section or data.in_target == 0
|
||||||
|
Writing 0 to the data.in_target makes the timeout handler makes the timeout handler invalid.
|
||||||
|
*/
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
EnterCriticalSection(data.critical as *mut CRITICAL_SECTION);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
data.in_target = 0;
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
LeaveCriticalSection(data.critical as *mut CRITICAL_SECTION);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this really crash?
|
||||||
|
let mut is_crash = true;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
if let Some(exception_pointers) = exception_pointers.as_mut() {
|
||||||
|
let code = ExceptionCode::try_from(
|
||||||
|
exception_pointers
|
||||||
|
.ExceptionRecord
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.ExceptionCode
|
||||||
|
.0,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let exception_list = data.exceptions();
|
||||||
|
if exception_list.contains(&code) {
|
||||||
|
log::error!("Crashed with {code}");
|
||||||
|
} else {
|
||||||
|
// log::trace!("Exception code received, but {code} is not in CRASH_EXCEPTIONS");
|
||||||
|
is_crash = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::error!("Crashed without exception (probably due to SIGABRT)");
|
||||||
|
};
|
||||||
|
|
||||||
|
if data.current_input_ptr.is_null() {
|
||||||
|
{
|
||||||
|
log::error!("Double crash\n");
|
||||||
|
let crash_addr = exception_pointers
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.ExceptionRecord
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.ExceptionAddress as usize;
|
||||||
|
|
||||||
|
log::error!(
|
||||||
|
"We crashed at addr 0x{crash_addr:x}, but are not in the target... Bug in the fuzzer? Exiting."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
{
|
||||||
|
log::error!("Type QUIT to restart the child");
|
||||||
|
let mut line = String::new();
|
||||||
|
while line.trim() != "QUIT" {
|
||||||
|
std::io::stdin().read_line(&mut line).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO tell the parent to not restart
|
||||||
|
} else {
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
// reset timer
|
||||||
|
if data.ptp_timer.is_some() {
|
||||||
|
data.ptp_timer = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let fuzzer = data.fuzzer_mut::<Z>();
|
||||||
|
let event_mgr = data.event_mgr_mut::<EM>();
|
||||||
|
|
||||||
|
if is_crash {
|
||||||
|
log::error!("Child crashed!");
|
||||||
|
} else {
|
||||||
|
// log::info!("Exception received!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't crash in the crash handler forever.
|
||||||
|
if is_crash {
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
|
||||||
|
run_observers_and_save_state::<E, EM, OF, Z>(
|
||||||
|
executor,
|
||||||
|
state,
|
||||||
|
input,
|
||||||
|
fuzzer,
|
||||||
|
event_mgr,
|
||||||
|
ExitKind::Crash,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// This is not worth saving
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_crash {
|
||||||
|
log::info!("Exiting!");
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
// log::info!("Not Exiting!");
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
613
libafl/src/executors/inprocess_fork.rs
Normal file
613
libafl/src/executors/inprocess_fork.rs
Normal file
@ -0,0 +1,613 @@
|
|||||||
|
//! The `GenericInProcessForkExecutor` to do forking before executing the harness in-processly
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
|
use core::{
|
||||||
|
ffi::c_void,
|
||||||
|
fmt::{self, Debug, Formatter},
|
||||||
|
marker::PhantomData,
|
||||||
|
ptr::{null_mut, write_volatile},
|
||||||
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use libafl_bolts::{
|
||||||
|
os::unix_signals::{ucontext_t, Signal},
|
||||||
|
shmem::ShMemProvider,
|
||||||
|
tuples::{tuple_list, Merge},
|
||||||
|
};
|
||||||
|
use libc::siginfo_t;
|
||||||
|
use nix::{
|
||||||
|
sys::wait::{waitpid, WaitStatus},
|
||||||
|
unistd::{fork, ForkResult},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::hooks::ExecutorHooksTuple;
|
||||||
|
use crate::{
|
||||||
|
events::{EventFirer, EventRestarter},
|
||||||
|
executors::{
|
||||||
|
hooks::inprocess_fork::{
|
||||||
|
InChildProcessHooks, InProcessForkExecutorGlobalData, FORK_EXECUTOR_GLOBAL_DATA,
|
||||||
|
},
|
||||||
|
Executor, ExitKind, HasObservers,
|
||||||
|
},
|
||||||
|
feedbacks::Feedback,
|
||||||
|
fuzzer::HasObjective,
|
||||||
|
inputs::UsesInput,
|
||||||
|
observers::{ObserversTuple, UsesObservers},
|
||||||
|
state::{HasExecutions, HasSolutions, State, UsesState},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
/// The signature of the crash handler function
|
||||||
|
pub(crate) type ForkHandlerFuncPtr = unsafe fn(
|
||||||
|
Signal,
|
||||||
|
&mut siginfo_t,
|
||||||
|
Option<&mut ucontext_t>,
|
||||||
|
data: &mut InProcessForkExecutorGlobalData,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
use crate::executors::hooks::timer::{setitimer, Itimerval, Timeval, ITIMER_REAL};
|
||||||
|
|
||||||
|
/// The `InProcessForkExecutor` with no user hooks
|
||||||
|
pub type InProcessForkExecutor<'a, H, OT, S, SP> =
|
||||||
|
GenericInProcessForkExecutor<'a, H, (), OT, S, SP>;
|
||||||
|
|
||||||
|
impl<'a, H, OT, S, SP> InProcessForkExecutor<'a, H, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||||
|
S: State,
|
||||||
|
OT: ObserversTuple<S>,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
/// The constructor for `InProcessForkExecutor`
|
||||||
|
pub fn new<EM, OF, Z>(
|
||||||
|
harness_fn: &'a mut H,
|
||||||
|
observers: OT,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
event_mgr: &mut EM,
|
||||||
|
timeout: Duration,
|
||||||
|
shmem_provider: SP,
|
||||||
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||||
|
OF: Feedback<S>,
|
||||||
|
S: HasSolutions,
|
||||||
|
Z: HasObjective<Objective = OF, State = S>,
|
||||||
|
{
|
||||||
|
Self::with_hooks(
|
||||||
|
tuple_list!(),
|
||||||
|
harness_fn,
|
||||||
|
observers,
|
||||||
|
fuzzer,
|
||||||
|
state,
|
||||||
|
event_mgr,
|
||||||
|
timeout,
|
||||||
|
shmem_provider,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [`GenericInProcessForkExecutor`] is an executor that forks the current process before each execution.
|
||||||
|
pub struct GenericInProcessForkExecutor<'a, H, HT, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||||
|
OT: ObserversTuple<S>,
|
||||||
|
S: UsesInput,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
HT: ExecutorHooksTuple,
|
||||||
|
{
|
||||||
|
hooks: (InChildProcessHooks, HT),
|
||||||
|
harness_fn: &'a mut H,
|
||||||
|
shmem_provider: SP,
|
||||||
|
observers: OT,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
itimerspec: libc::itimerspec,
|
||||||
|
#[cfg(all(unix, not(target_os = "linux")))]
|
||||||
|
itimerval: Itimerval,
|
||||||
|
phantom: PhantomData<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H, HT, OT, S, SP> Debug for GenericInProcessForkExecutor<'a, H, HT, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||||
|
OT: ObserversTuple<S> + Debug,
|
||||||
|
S: UsesInput,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
HT: ExecutorHooksTuple,
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("GenericInProcessForkExecutor")
|
||||||
|
.field("observers", &self.observers)
|
||||||
|
.field("shmem_provider", &self.shmem_provider)
|
||||||
|
.field("itimerspec", &self.itimerspec)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
return f
|
||||||
|
.debug_struct("GenericInProcessForkExecutor")
|
||||||
|
.field("observers", &self.observers)
|
||||||
|
.field("shmem_provider", &self.shmem_provider)
|
||||||
|
.field("itimerval", &self.itimerval)
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H, HT, OT, S, SP> UsesState for GenericInProcessForkExecutor<'a, H, HT, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: ?Sized + FnMut(&S::Input) -> ExitKind,
|
||||||
|
OT: ObserversTuple<S>,
|
||||||
|
S: State,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
HT: ExecutorHooksTuple,
|
||||||
|
{
|
||||||
|
type State = S;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, EM, H, HT, OT, S, SP, Z> Executor<EM, Z>
|
||||||
|
for GenericInProcessForkExecutor<'a, H, HT, OT, S, SP>
|
||||||
|
where
|
||||||
|
EM: UsesState<State = S>,
|
||||||
|
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||||
|
OT: ObserversTuple<S>,
|
||||||
|
S: State + HasExecutions,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
HT: ExecutorHooksTuple,
|
||||||
|
Z: UsesState<State = S>,
|
||||||
|
{
|
||||||
|
#[allow(unreachable_code)]
|
||||||
|
#[inline]
|
||||||
|
fn run_target(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
state: &mut Self::State,
|
||||||
|
mgr: &mut EM,
|
||||||
|
input: &Self::Input,
|
||||||
|
) -> Result<ExitKind, Error> {
|
||||||
|
*state.executions_mut() += 1;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.shmem_provider.pre_fork()?;
|
||||||
|
match fork() {
|
||||||
|
Ok(ForkResult::Child) => {
|
||||||
|
// Child
|
||||||
|
self.shmem_provider.post_fork(true)?;
|
||||||
|
|
||||||
|
self.enter_target(fuzzer, state, mgr, input);
|
||||||
|
self.hooks.pre_exec_all(fuzzer, state, mgr, input);
|
||||||
|
|
||||||
|
self.observers
|
||||||
|
.pre_exec_child_all(state, input)
|
||||||
|
.expect("Failed to run post_exec on observers");
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
let mut timerid: libc::timer_t = null_mut();
|
||||||
|
// creates a new per-process interval timer
|
||||||
|
// we can't do this from the parent, timerid is unique to each process.
|
||||||
|
libc::timer_create(
|
||||||
|
libc::CLOCK_MONOTONIC,
|
||||||
|
null_mut(),
|
||||||
|
addr_of_mut!(timerid),
|
||||||
|
);
|
||||||
|
|
||||||
|
// log::info!("Set timer! {:#?} {timerid:#?}", self.itimerspec);
|
||||||
|
let _: i32 = libc::timer_settime(
|
||||||
|
timerid,
|
||||||
|
0,
|
||||||
|
addr_of_mut!(self.itimerspec),
|
||||||
|
null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
{
|
||||||
|
setitimer(ITIMER_REAL, &mut self.itimerval, null_mut());
|
||||||
|
}
|
||||||
|
// log::trace!("{v:#?} {}", nix::errno::errno());
|
||||||
|
(self.harness_fn)(input);
|
||||||
|
|
||||||
|
self.observers
|
||||||
|
.post_exec_child_all(state, input, &ExitKind::Ok)
|
||||||
|
.expect("Failed to run post_exec on observers");
|
||||||
|
|
||||||
|
self.hooks.post_exec_all(fuzzer, state, mgr, input);
|
||||||
|
self.leave_target(fuzzer, state, mgr, input);
|
||||||
|
|
||||||
|
libc::_exit(0);
|
||||||
|
|
||||||
|
Ok(ExitKind::Ok)
|
||||||
|
}
|
||||||
|
Ok(ForkResult::Parent { child }) => {
|
||||||
|
// Parent
|
||||||
|
// log::trace!("from parent {} child is {}", std::process::id(), child);
|
||||||
|
self.shmem_provider.post_fork(false)?;
|
||||||
|
|
||||||
|
let res = waitpid(child, None)?;
|
||||||
|
log::trace!("{res:#?}");
|
||||||
|
match res {
|
||||||
|
WaitStatus::Signaled(_, signal, _) => match signal {
|
||||||
|
nix::sys::signal::Signal::SIGALRM
|
||||||
|
| nix::sys::signal::Signal::SIGUSR2 => Ok(ExitKind::Timeout),
|
||||||
|
_ => Ok(ExitKind::Crash),
|
||||||
|
},
|
||||||
|
WaitStatus::Exited(_, code) => {
|
||||||
|
if code > 128 && code < 160 {
|
||||||
|
// Signal exit codes
|
||||||
|
let signal = code - 128;
|
||||||
|
if signal == Signal::SigAlarm as libc::c_int
|
||||||
|
|| signal == Signal::SigUser2 as libc::c_int
|
||||||
|
{
|
||||||
|
Ok(ExitKind::Timeout)
|
||||||
|
} else {
|
||||||
|
Ok(ExitKind::Crash)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(ExitKind::Ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ok(ExitKind::Ok),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Err(Error::from(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H, HT, OT, S, SP> GenericInProcessForkExecutor<'a, H, HT, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||||
|
HT: ExecutorHooksTuple,
|
||||||
|
S: State,
|
||||||
|
OT: ObserversTuple<S>,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
/// This function marks the boundary between the fuzzer and the target.
|
||||||
|
pub fn enter_target<EM, Z>(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
state: &mut <Self as UsesState>::State,
|
||||||
|
_event_mgr: &mut EM,
|
||||||
|
input: &<Self as UsesInput>::Input,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
let data = &mut FORK_EXECUTOR_GLOBAL_DATA;
|
||||||
|
write_volatile(&mut data.executor_ptr, self as *const _ as *const c_void);
|
||||||
|
write_volatile(
|
||||||
|
&mut data.current_input_ptr,
|
||||||
|
input as *const _ as *const c_void,
|
||||||
|
);
|
||||||
|
write_volatile(&mut data.state_ptr, state as *mut _ as *mut c_void);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// This function marks the boundary between the fuzzer and the target.
|
||||||
|
pub fn leave_target<EM, Z>(
|
||||||
|
&mut self,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
_state: &mut <Self as UsesState>::State,
|
||||||
|
_event_mgr: &mut EM,
|
||||||
|
_input: &<Self as UsesInput>::Input,
|
||||||
|
) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`GenericInProcessForkExecutor`] with custom hooks
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn with_hooks<EM, OF, Z>(
|
||||||
|
userhooks: HT,
|
||||||
|
harness_fn: &'a mut H,
|
||||||
|
observers: OT,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
_event_mgr: &mut EM,
|
||||||
|
timeout: Duration,
|
||||||
|
shmem_provider: SP,
|
||||||
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||||
|
OF: Feedback<S>,
|
||||||
|
S: HasSolutions,
|
||||||
|
Z: HasObjective<Objective = OF, State = S>,
|
||||||
|
{
|
||||||
|
let default_hooks = InChildProcessHooks::new::<Self>()?;
|
||||||
|
let mut hooks = tuple_list!(default_hooks).merge(userhooks);
|
||||||
|
hooks.init_all::<Self, S>(state);
|
||||||
|
|
||||||
|
let milli_sec = timeout.as_millis();
|
||||||
|
let it_value = libc::timespec {
|
||||||
|
tv_sec: (milli_sec / 1000) as _,
|
||||||
|
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
||||||
|
};
|
||||||
|
let it_interval = libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
};
|
||||||
|
let itimerspec = libc::itimerspec {
|
||||||
|
it_interval,
|
||||||
|
it_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
harness_fn,
|
||||||
|
shmem_provider,
|
||||||
|
observers,
|
||||||
|
hooks,
|
||||||
|
itimerspec,
|
||||||
|
phantom: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`GenericInProcessForkExecutor`], non linux
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn with_hooks<EM, OF, Z>(
|
||||||
|
userhooks: HT,
|
||||||
|
harness_fn: &'a mut H,
|
||||||
|
observers: OT,
|
||||||
|
_fuzzer: &mut Z,
|
||||||
|
state: &mut S,
|
||||||
|
_event_mgr: &mut EM,
|
||||||
|
timeout: Duration,
|
||||||
|
shmem_provider: SP,
|
||||||
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||||
|
OF: Feedback<S>,
|
||||||
|
S: HasSolutions,
|
||||||
|
Z: HasObjective<Objective = OF, State = S>,
|
||||||
|
{
|
||||||
|
let default_hooks = InChildProcessHooks::new::<Self>()?;
|
||||||
|
let mut hooks = tuple_list!(default_hooks).merge(userhooks);
|
||||||
|
hooks.init_all::<Self, S>(state);
|
||||||
|
|
||||||
|
let milli_sec = timeout.as_millis();
|
||||||
|
let it_value = Timeval {
|
||||||
|
tv_sec: (milli_sec / 1000) as i64,
|
||||||
|
tv_usec: (milli_sec % 1000) as i64,
|
||||||
|
};
|
||||||
|
let it_interval = Timeval {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_usec: 0,
|
||||||
|
};
|
||||||
|
let itimerval = Itimerval {
|
||||||
|
it_interval,
|
||||||
|
it_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
harness_fn,
|
||||||
|
shmem_provider,
|
||||||
|
observers,
|
||||||
|
hooks,
|
||||||
|
itimerval,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H, HT, OT, S, SP> UsesObservers for GenericInProcessForkExecutor<'a, H, HT, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: ?Sized + FnMut(&S::Input) -> ExitKind,
|
||||||
|
HT: ExecutorHooksTuple,
|
||||||
|
OT: ObserversTuple<S>,
|
||||||
|
S: State,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
type Observers = OT;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H, HT, OT, S, SP> HasObservers for GenericInProcessForkExecutor<'a, H, HT, OT, S, SP>
|
||||||
|
where
|
||||||
|
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||||
|
HT: ExecutorHooksTuple,
|
||||||
|
S: State,
|
||||||
|
OT: ObserversTuple<S>,
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn observers(&self) -> &OT {
|
||||||
|
&self.observers
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn observers_mut(&mut self) -> &mut OT {
|
||||||
|
&mut self.observers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// signal hooks and `panic_hooks` for the child process
|
||||||
|
|
||||||
|
pub mod child_signal_handlers {
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use std::panic;
|
||||||
|
|
||||||
|
use libafl_bolts::os::unix_signals::{ucontext_t, Signal};
|
||||||
|
use libc::siginfo_t;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
executors::{
|
||||||
|
hooks::inprocess_fork::{InProcessForkExecutorGlobalData, FORK_EXECUTOR_GLOBAL_DATA},
|
||||||
|
ExitKind, HasObservers,
|
||||||
|
},
|
||||||
|
inputs::UsesInput,
|
||||||
|
observers::ObserversTuple,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// invokes the `post_exec_child` hook on all observer in case the child process panics
|
||||||
|
pub fn setup_child_panic_hook<E>()
|
||||||
|
where
|
||||||
|
E: HasObservers,
|
||||||
|
{
|
||||||
|
let old_hook = panic::take_hook();
|
||||||
|
panic::set_hook(Box::new(move |panic_info| {
|
||||||
|
old_hook(panic_info);
|
||||||
|
let data = unsafe { &mut FORK_EXECUTOR_GLOBAL_DATA };
|
||||||
|
if data.is_valid() {
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
let observers = executor.observers_mut();
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
// Invalidate data to not execute again the observer hooks in the crash handler
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
observers
|
||||||
|
.post_exec_child_all(state, input, &ExitKind::Crash)
|
||||||
|
.expect("Failed to run post_exec on observers");
|
||||||
|
|
||||||
|
// std::process::abort();
|
||||||
|
unsafe { libc::_exit(128 + 6) }; // ABORT exit code
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// invokes the `post_exec` hook on all observer in case the child process crashes
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The function should only be called from a child crash handler.
|
||||||
|
/// It will dereference the `data` pointer and assume it's valid.
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
pub(crate) unsafe fn child_crash_handler<E>(
|
||||||
|
_signal: Signal,
|
||||||
|
_info: &mut siginfo_t,
|
||||||
|
_context: Option<&mut ucontext_t>,
|
||||||
|
data: &mut InProcessForkExecutorGlobalData,
|
||||||
|
) where
|
||||||
|
E: HasObservers,
|
||||||
|
{
|
||||||
|
if data.is_valid() {
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
let observers = executor.observers_mut();
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
observers
|
||||||
|
.post_exec_child_all(state, input, &ExitKind::Crash)
|
||||||
|
.expect("Failed to run post_exec on observers");
|
||||||
|
}
|
||||||
|
|
||||||
|
libc::_exit(128 + (_signal as i32));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
|
pub(crate) unsafe fn child_timeout_handler<E>(
|
||||||
|
_signal: Signal,
|
||||||
|
_info: &mut siginfo_t,
|
||||||
|
_context: Option<&mut ucontext_t>,
|
||||||
|
data: &mut InProcessForkExecutorGlobalData,
|
||||||
|
) where
|
||||||
|
E: HasObservers,
|
||||||
|
{
|
||||||
|
if data.is_valid() {
|
||||||
|
let executor = data.executor_mut::<E>();
|
||||||
|
let observers = executor.observers_mut();
|
||||||
|
let state = data.state_mut::<E::State>();
|
||||||
|
let input = data.take_current_input::<<E::State as UsesInput>::Input>();
|
||||||
|
observers
|
||||||
|
.post_exec_child_all(state, input, &ExitKind::Timeout)
|
||||||
|
.expect("Failed to run post_exec on observers");
|
||||||
|
}
|
||||||
|
libc::_exit(128 + (_signal as i32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use libafl_bolts::tuples::tuple_list;
|
||||||
|
|
||||||
|
use crate::{executors::ExitKind, inputs::NopInput};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
|
#[cfg(all(feature = "std", feature = "fork", unix))]
|
||||||
|
fn test_inprocessfork_exec() {
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use libafl_bolts::shmem::{ShMemProvider, StdShMemProvider};
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use libc::{itimerspec, timespec};
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
use crate::executors::hooks::timer::{Itimerval, Timeval};
|
||||||
|
use crate::{
|
||||||
|
events::SimpleEventManager,
|
||||||
|
executors::{
|
||||||
|
hooks::inprocess_fork::InChildProcessHooks,
|
||||||
|
inprocess_fork::GenericInProcessForkExecutor, Executor,
|
||||||
|
},
|
||||||
|
fuzzer::test::NopFuzzer,
|
||||||
|
state::test::NopState,
|
||||||
|
};
|
||||||
|
|
||||||
|
let provider = StdShMemProvider::new().unwrap();
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let timespec = timespec {
|
||||||
|
tv_sec: 5,
|
||||||
|
tv_nsec: 0,
|
||||||
|
};
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let itimerspec = itimerspec {
|
||||||
|
it_interval: timespec,
|
||||||
|
it_value: timespec,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
let timespec = Timeval {
|
||||||
|
tv_sec: 5,
|
||||||
|
tv_usec: 0,
|
||||||
|
};
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
let itimerspec = Itimerval {
|
||||||
|
it_interval: timespec,
|
||||||
|
it_value: timespec,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut harness = |_buf: &NopInput| ExitKind::Ok;
|
||||||
|
let default = InChildProcessHooks::nop();
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let mut in_process_fork_executor = GenericInProcessForkExecutor::<_, (), (), _, _> {
|
||||||
|
hooks: tuple_list!(default),
|
||||||
|
harness_fn: &mut harness,
|
||||||
|
shmem_provider: provider,
|
||||||
|
observers: tuple_list!(),
|
||||||
|
itimerspec,
|
||||||
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
let mut in_process_fork_executor = GenericInProcessForkExecutor::<_, (), (), _, _> {
|
||||||
|
harness_fn: &mut harness,
|
||||||
|
shmem_provider: provider,
|
||||||
|
observers: tuple_list!(),
|
||||||
|
hooks: tuple_list!(default),
|
||||||
|
itimerval: itimerspec,
|
||||||
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
let input = NopInput {};
|
||||||
|
let mut fuzzer = NopFuzzer::new();
|
||||||
|
let mut state = NopState::new();
|
||||||
|
let mut mgr = SimpleEventManager::printing();
|
||||||
|
in_process_fork_executor
|
||||||
|
.run_target(&mut fuzzer, &mut state, &mut mgr, &input)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
//! Executors take input, and run it in the target.
|
//! Executors take input, and run it in the target.
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
pub use combined::CombinedExecutor;
|
pub use combined::CombinedExecutor;
|
||||||
@ -10,11 +12,11 @@ pub use differential::DiffExecutor;
|
|||||||
pub use forkserver::{Forkserver, ForkserverExecutor, TimeoutForkserverExecutor};
|
pub use forkserver::{Forkserver, ForkserverExecutor, TimeoutForkserverExecutor};
|
||||||
pub use inprocess::InProcessExecutor;
|
pub use inprocess::InProcessExecutor;
|
||||||
#[cfg(all(feature = "std", feature = "fork", unix))]
|
#[cfg(all(feature = "std", feature = "fork", unix))]
|
||||||
pub use inprocess::InProcessForkExecutor;
|
pub use inprocess_fork::InProcessForkExecutor;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use libafl_bolts::os::unix_signals::Signal;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
pub use shadow::ShadowExecutor;
|
pub use shadow::ShadowExecutor;
|
||||||
#[cfg(any(unix, feature = "std"))]
|
|
||||||
pub use timeout::TimeoutExecutor;
|
|
||||||
pub use with_observers::WithObservers;
|
pub use with_observers::WithObservers;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -30,13 +32,18 @@ pub mod differential;
|
|||||||
#[cfg(all(feature = "std", feature = "fork", unix))]
|
#[cfg(all(feature = "std", feature = "fork", unix))]
|
||||||
pub mod forkserver;
|
pub mod forkserver;
|
||||||
pub mod inprocess;
|
pub mod inprocess;
|
||||||
|
|
||||||
|
/// The module for inproc fork executor
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
pub mod inprocess_fork;
|
||||||
|
|
||||||
pub mod shadow;
|
pub mod shadow;
|
||||||
/// Timeout executor.
|
|
||||||
/// Not possible on `no-std` Windows or `no-std`, but works for unix
|
|
||||||
#[cfg(any(unix, feature = "std"))]
|
|
||||||
pub mod timeout;
|
|
||||||
pub mod with_observers;
|
pub mod with_observers;
|
||||||
|
|
||||||
|
/// The module for all the hooks
|
||||||
|
pub mod hooks;
|
||||||
|
|
||||||
/// How an execution finished.
|
/// How an execution finished.
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
@ -135,10 +142,25 @@ where
|
|||||||
{
|
{
|
||||||
WithObservers::new(self, observers)
|
WithObservers::new(self, observers)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Custom Reset Handler, e.g., to reset timers
|
/// The common signals we want to handle
|
||||||
#[inline]
|
#[cfg(unix)]
|
||||||
fn post_run_reset(&mut self) {}
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn common_signals() -> Vec<Signal> {
|
||||||
|
vec![
|
||||||
|
Signal::SigAlarm,
|
||||||
|
Signal::SigUser2,
|
||||||
|
Signal::SigAbort,
|
||||||
|
Signal::SigBus,
|
||||||
|
#[cfg(feature = "handle_sigpipe")]
|
||||||
|
Signal::SigPipe,
|
||||||
|
Signal::SigFloatingPointException,
|
||||||
|
Signal::SigIllegalInstruction,
|
||||||
|
Signal::SigSegmentationFault,
|
||||||
|
Signal::SigTrap,
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -70,9 +70,7 @@ where
|
|||||||
mgr: &mut EM,
|
mgr: &mut EM,
|
||||||
input: &Self::Input,
|
input: &Self::Input,
|
||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
self.executor.run_target(fuzzer, state, mgr, input)
|
||||||
self.executor.post_run_reset();
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,583 +0,0 @@
|
|||||||
//! A `TimeoutExecutor` sets a timeout before each target run
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use core::ptr::{addr_of, addr_of_mut};
|
|
||||||
#[cfg(any(windows, target_os = "linux"))]
|
|
||||||
use core::{ffi::c_void, ptr::write_volatile};
|
|
||||||
#[cfg(any(windows, unix))]
|
|
||||||
use core::{
|
|
||||||
fmt::{self, Debug, Formatter},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
#[cfg(unix)]
|
|
||||||
use core::{mem::zeroed, ptr::null_mut};
|
|
||||||
#[cfg(windows)]
|
|
||||||
use core::{
|
|
||||||
ptr::addr_of_mut,
|
|
||||||
sync::atomic::{compiler_fence, Ordering},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use libafl_bolts::current_time;
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
use libc::c_int;
|
|
||||||
#[cfg(all(windows, feature = "std"))]
|
|
||||||
use windows::Win32::{
|
|
||||||
Foundation::FILETIME,
|
|
||||||
System::Threading::{
|
|
||||||
CreateThreadpoolTimer, EnterCriticalSection, InitializeCriticalSection,
|
|
||||||
LeaveCriticalSection, SetThreadpoolTimer, CRITICAL_SECTION, PTP_CALLBACK_INSTANCE,
|
|
||||||
PTP_TIMER, TP_CALLBACK_ENVIRON_V3,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(all(windows, feature = "std"))]
|
|
||||||
use crate::executors::inprocess::HasInProcessHandlers;
|
|
||||||
#[cfg(any(windows, target_os = "linux"))]
|
|
||||||
use crate::executors::inprocess::GLOBAL_STATE;
|
|
||||||
use crate::{
|
|
||||||
executors::{inprocess::InProcessExecutorHandlerData, Executor, ExitKind, HasObservers},
|
|
||||||
observers::UsesObservers,
|
|
||||||
state::UsesState,
|
|
||||||
Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
pub(crate) struct Timeval {
|
|
||||||
pub tv_sec: i64,
|
|
||||||
pub tv_usec: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
impl Debug for Timeval {
|
|
||||||
#[allow(clippy::cast_sign_loss)]
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Timeval {{ tv_sec: {:?}, tv_usec: {:?} (tv: {:?}) }}",
|
|
||||||
self.tv_sec,
|
|
||||||
self.tv_usec,
|
|
||||||
Duration::new(self.tv_sec as _, (self.tv_usec * 1000) as _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct Itimerval {
|
|
||||||
pub it_interval: Timeval,
|
|
||||||
pub it_value: Timeval,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
extern "C" {
|
|
||||||
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
const ITIMER_REAL: c_int = 0;
|
|
||||||
|
|
||||||
/// The timeout executor is a wrapper that sets a timeout before each run
|
|
||||||
pub struct TimeoutExecutor<E> {
|
|
||||||
/// The wrapped [`Executor`]
|
|
||||||
executor: E,
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
itimerspec: libc::itimerspec,
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
timerid: libc::timer_t,
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
itimerval: Itimerval,
|
|
||||||
#[cfg(windows)]
|
|
||||||
milli_sec: i64,
|
|
||||||
#[cfg(windows)]
|
|
||||||
ptp_timer: PTP_TIMER,
|
|
||||||
#[cfg(windows)]
|
|
||||||
critical: CRITICAL_SECTION,
|
|
||||||
|
|
||||||
exec_tmout: Duration,
|
|
||||||
|
|
||||||
// for batch mode (linux only atm)
|
|
||||||
#[allow(unused)]
|
|
||||||
batch_mode: bool,
|
|
||||||
#[allow(unused)]
|
|
||||||
executions: u32,
|
|
||||||
#[allow(unused)]
|
|
||||||
avg_mul_k: u32,
|
|
||||||
#[allow(unused)]
|
|
||||||
last_signal_time: Duration,
|
|
||||||
#[allow(unused)]
|
|
||||||
avg_exec_time: Duration,
|
|
||||||
#[allow(unused)]
|
|
||||||
start_time: Duration,
|
|
||||||
#[allow(unused)]
|
|
||||||
tmout_start_time: Duration,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Debug> Debug for TimeoutExecutor<E> {
|
|
||||||
#[cfg(windows)]
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("TimeoutExecutor")
|
|
||||||
.field("executor", &self.executor)
|
|
||||||
.field("milli_sec", &self.milli_sec)
|
|
||||||
.finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("TimeoutExecutor")
|
|
||||||
.field("executor", &self.executor)
|
|
||||||
.field(
|
|
||||||
"milli_sec",
|
|
||||||
&(&self.itimerspec.it_value.tv_sec * 1000
|
|
||||||
+ &self.itimerspec.it_value.tv_nsec / 1000 / 1000),
|
|
||||||
)
|
|
||||||
.finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("TimeoutExecutor")
|
|
||||||
.field("executor", &self.executor)
|
|
||||||
.field("itimerval", &self.itimerval)
|
|
||||||
.finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
type PTP_TIMER_CALLBACK = unsafe extern "system" fn(
|
|
||||||
param0: PTP_CALLBACK_INSTANCE,
|
|
||||||
param1: *mut c_void,
|
|
||||||
param2: PTP_TIMER,
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
impl<E> TimeoutExecutor<E> {
|
|
||||||
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
|
||||||
/// This should usually be used for `InProcess` fuzzing.
|
|
||||||
pub fn new(executor: E, exec_tmout: Duration) -> Self {
|
|
||||||
let milli_sec = exec_tmout.as_millis();
|
|
||||||
let it_value = libc::timespec {
|
|
||||||
tv_sec: (milli_sec / 1000) as _,
|
|
||||||
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
|
||||||
};
|
|
||||||
let it_interval = libc::timespec {
|
|
||||||
tv_sec: 0,
|
|
||||||
tv_nsec: 0,
|
|
||||||
};
|
|
||||||
let itimerspec = libc::itimerspec {
|
|
||||||
it_interval,
|
|
||||||
it_value,
|
|
||||||
};
|
|
||||||
let mut timerid: libc::timer_t = null_mut();
|
|
||||||
unsafe {
|
|
||||||
// creates a new per-process interval timer
|
|
||||||
libc::timer_create(libc::CLOCK_MONOTONIC, null_mut(), addr_of_mut!(timerid));
|
|
||||||
}
|
|
||||||
Self {
|
|
||||||
executor,
|
|
||||||
itimerspec,
|
|
||||||
timerid,
|
|
||||||
exec_tmout,
|
|
||||||
batch_mode: false,
|
|
||||||
executions: 0,
|
|
||||||
avg_mul_k: 1,
|
|
||||||
last_signal_time: Duration::ZERO,
|
|
||||||
avg_exec_time: Duration::ZERO,
|
|
||||||
start_time: Duration::ZERO,
|
|
||||||
tmout_start_time: Duration::ZERO,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
|
||||||
/// With this method batch mode is enabled.
|
|
||||||
pub fn batch_mode(executor: E, exec_tmout: Duration) -> Self {
|
|
||||||
let mut me = Self::new(executor, exec_tmout);
|
|
||||||
me.batch_mode = true;
|
|
||||||
me
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the timeout for this executor
|
|
||||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
|
||||||
let milli_sec = exec_tmout.as_millis();
|
|
||||||
let it_value = libc::timespec {
|
|
||||||
tv_sec: (milli_sec / 1000) as _,
|
|
||||||
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
|
||||||
};
|
|
||||||
let it_interval = libc::timespec {
|
|
||||||
tv_sec: 0,
|
|
||||||
tv_nsec: 0,
|
|
||||||
};
|
|
||||||
let itimerspec = libc::itimerspec {
|
|
||||||
it_interval,
|
|
||||||
it_value,
|
|
||||||
};
|
|
||||||
self.itimerspec = itimerspec;
|
|
||||||
self.exec_tmout = exec_tmout;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn handle_timeout(&mut self, data: &InProcessExecutorHandlerData) -> bool {
|
|
||||||
if !self.batch_mode {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//eprintln!("handle_timeout {:?} {}", self.avg_exec_time, self.avg_mul_k);
|
|
||||||
let cur_time = current_time();
|
|
||||||
if !data.is_valid() {
|
|
||||||
// outside the target
|
|
||||||
unsafe {
|
|
||||||
let disarmed: libc::itimerspec = zeroed();
|
|
||||||
libc::timer_settime(self.timerid, 0, addr_of!(disarmed), null_mut());
|
|
||||||
}
|
|
||||||
let elapsed = cur_time - self.tmout_start_time;
|
|
||||||
// set timer the next exec
|
|
||||||
if self.executions > 0 {
|
|
||||||
self.avg_exec_time = elapsed / self.executions;
|
|
||||||
self.executions = 0;
|
|
||||||
}
|
|
||||||
self.avg_mul_k += 1;
|
|
||||||
self.last_signal_time = cur_time;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let elapsed_run = cur_time - self.start_time;
|
|
||||||
if elapsed_run < self.exec_tmout {
|
|
||||||
// fp, reset timeout
|
|
||||||
unsafe {
|
|
||||||
libc::timer_settime(self.timerid, 0, addr_of!(self.itimerspec), null_mut());
|
|
||||||
}
|
|
||||||
if self.executions > 0 {
|
|
||||||
let elapsed = cur_time - self.tmout_start_time;
|
|
||||||
self.avg_exec_time = elapsed / self.executions;
|
|
||||||
self.executions = 0; // It will be 1 when the exec finish
|
|
||||||
}
|
|
||||||
self.tmout_start_time = current_time();
|
|
||||||
self.avg_mul_k += 1;
|
|
||||||
self.last_signal_time = cur_time;
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
impl<E> TimeoutExecutor<E> {
|
|
||||||
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
|
||||||
/// This should usually be used for `InProcess` fuzzing.
|
|
||||||
pub fn new(executor: E, exec_tmout: Duration) -> Self {
|
|
||||||
let milli_sec = exec_tmout.as_millis();
|
|
||||||
let it_value = Timeval {
|
|
||||||
tv_sec: (milli_sec / 1000) as i64,
|
|
||||||
tv_usec: (milli_sec % 1000) as i64,
|
|
||||||
};
|
|
||||||
let it_interval = Timeval {
|
|
||||||
tv_sec: 0,
|
|
||||||
tv_usec: 0,
|
|
||||||
};
|
|
||||||
let itimerval = Itimerval {
|
|
||||||
it_interval,
|
|
||||||
it_value,
|
|
||||||
};
|
|
||||||
Self {
|
|
||||||
executor,
|
|
||||||
itimerval,
|
|
||||||
exec_tmout,
|
|
||||||
batch_mode: false,
|
|
||||||
executions: 0,
|
|
||||||
avg_mul_k: 1,
|
|
||||||
last_signal_time: Duration::ZERO,
|
|
||||||
avg_exec_time: Duration::ZERO,
|
|
||||||
start_time: Duration::ZERO,
|
|
||||||
tmout_start_time: Duration::ZERO,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the timeout for this executor
|
|
||||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
|
||||||
let milli_sec = exec_tmout.as_millis();
|
|
||||||
let it_value = Timeval {
|
|
||||||
tv_sec: (milli_sec / 1000) as i64,
|
|
||||||
tv_usec: (milli_sec % 1000) as i64,
|
|
||||||
};
|
|
||||||
let it_interval = Timeval {
|
|
||||||
tv_sec: 0,
|
|
||||||
tv_usec: 0,
|
|
||||||
};
|
|
||||||
let itimerval = Itimerval {
|
|
||||||
it_interval,
|
|
||||||
it_value,
|
|
||||||
};
|
|
||||||
self.itimerval = itimerval;
|
|
||||||
self.exec_tmout = exec_tmout;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::unused_self)]
|
|
||||||
pub(crate) fn handle_timeout(&mut self, _data: &mut InProcessExecutorHandlerData) -> bool {
|
|
||||||
false // TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
impl<E: HasInProcessHandlers> TimeoutExecutor<E> {
|
|
||||||
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
|
||||||
pub fn new(executor: E, exec_tmout: Duration) -> Self {
|
|
||||||
let milli_sec = exec_tmout.as_millis() as i64;
|
|
||||||
let timeout_handler: PTP_TIMER_CALLBACK =
|
|
||||||
unsafe { std::mem::transmute(executor.inprocess_handlers().timeout_handler) };
|
|
||||||
let ptp_timer = unsafe {
|
|
||||||
CreateThreadpoolTimer(
|
|
||||||
Some(timeout_handler),
|
|
||||||
Some(addr_of_mut!(GLOBAL_STATE) as *mut c_void),
|
|
||||||
Some(&TP_CALLBACK_ENVIRON_V3::default()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.expect("CreateThreadpoolTimer failed!");
|
|
||||||
let mut critical = CRITICAL_SECTION::default();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
InitializeCriticalSection(&mut critical);
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
|
||||||
executor,
|
|
||||||
milli_sec,
|
|
||||||
ptp_timer,
|
|
||||||
critical,
|
|
||||||
exec_tmout,
|
|
||||||
batch_mode: false,
|
|
||||||
executions: 0,
|
|
||||||
avg_mul_k: 1,
|
|
||||||
last_signal_time: Duration::ZERO,
|
|
||||||
avg_exec_time: Duration::ZERO,
|
|
||||||
start_time: Duration::ZERO,
|
|
||||||
tmout_start_time: Duration::ZERO,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the timeout for this executor
|
|
||||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
|
||||||
self.milli_sec = exec_tmout.as_millis() as i64;
|
|
||||||
self.exec_tmout = exec_tmout;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::unused_self)]
|
|
||||||
pub(crate) fn handle_timeout(&mut self, _data: &mut InProcessExecutorHandlerData) -> bool {
|
|
||||||
false // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the inner `Executor` that is wrapped by this `TimeoutExecutor`.
|
|
||||||
pub fn inner(&mut self) -> &mut E {
|
|
||||||
&mut self.executor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
impl<E, EM, Z> Executor<EM, Z> for TimeoutExecutor<E>
|
|
||||||
where
|
|
||||||
E: Executor<EM, Z> + HasInProcessHandlers,
|
|
||||||
EM: UsesState<State = E::State>,
|
|
||||||
Z: UsesState<State = E::State>,
|
|
||||||
{
|
|
||||||
#[allow(clippy::cast_sign_loss)]
|
|
||||||
fn run_target(
|
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
state: &mut Self::State,
|
|
||||||
mgr: &mut EM,
|
|
||||||
input: &Self::Input,
|
|
||||||
) -> Result<ExitKind, Error> {
|
|
||||||
unsafe {
|
|
||||||
let data = &mut GLOBAL_STATE;
|
|
||||||
write_volatile(
|
|
||||||
&mut data.timeout_executor_ptr,
|
|
||||||
self as *mut _ as *mut c_void,
|
|
||||||
);
|
|
||||||
|
|
||||||
write_volatile(&mut data.ptp_timer, Some(self.ptp_timer));
|
|
||||||
write_volatile(
|
|
||||||
&mut data.critical,
|
|
||||||
addr_of_mut!(self.critical) as *mut c_void,
|
|
||||||
);
|
|
||||||
write_volatile(
|
|
||||||
&mut data.timeout_input_ptr,
|
|
||||||
addr_of_mut!(data.current_input_ptr) as *mut c_void,
|
|
||||||
);
|
|
||||||
let tm: i64 = -self.milli_sec * 10 * 1000;
|
|
||||||
let ft = FILETIME {
|
|
||||||
dwLowDateTime: (tm & 0xffffffff) as u32,
|
|
||||||
dwHighDateTime: (tm >> 32) as u32,
|
|
||||||
};
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
EnterCriticalSection(&mut self.critical);
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
data.in_target = 1;
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
LeaveCriticalSection(&mut self.critical);
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
|
|
||||||
SetThreadpoolTimer(self.ptp_timer, Some(&ft), 0, 0);
|
|
||||||
|
|
||||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
EnterCriticalSection(&mut self.critical);
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
// Timeout handler will do nothing after we increment in_target value.
|
|
||||||
data.in_target = 0;
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
LeaveCriticalSection(&mut self.critical);
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
|
|
||||||
write_volatile(&mut data.timeout_input_ptr, core::ptr::null_mut());
|
|
||||||
|
|
||||||
self.post_run_reset();
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes this timer queue
|
|
||||||
/// # Safety
|
|
||||||
/// Will dereference the given `tp_timer` pointer, unchecked.
|
|
||||||
fn post_run_reset(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
SetThreadpoolTimer(self.ptp_timer, None, 0, 0);
|
|
||||||
}
|
|
||||||
self.executor.post_run_reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
impl<E, EM, Z> Executor<EM, Z> for TimeoutExecutor<E>
|
|
||||||
where
|
|
||||||
E: Executor<EM, Z>,
|
|
||||||
EM: UsesState<State = E::State>,
|
|
||||||
Z: UsesState<State = E::State>,
|
|
||||||
{
|
|
||||||
fn run_target(
|
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
state: &mut Self::State,
|
|
||||||
mgr: &mut EM,
|
|
||||||
input: &Self::Input,
|
|
||||||
) -> Result<ExitKind, Error> {
|
|
||||||
unsafe {
|
|
||||||
if self.batch_mode {
|
|
||||||
let data = &mut GLOBAL_STATE;
|
|
||||||
write_volatile(
|
|
||||||
&mut data.timeout_executor_ptr,
|
|
||||||
self as *mut _ as *mut c_void,
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.executions == 0 {
|
|
||||||
libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut());
|
|
||||||
self.tmout_start_time = current_time();
|
|
||||||
}
|
|
||||||
self.start_time = current_time();
|
|
||||||
} else {
|
|
||||||
libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut());
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
|
||||||
// reset timer
|
|
||||||
self.post_run_reset();
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn post_run_reset(&mut self) {
|
|
||||||
if self.batch_mode {
|
|
||||||
unsafe {
|
|
||||||
let elapsed = current_time() - self.tmout_start_time;
|
|
||||||
// elapsed may be > than tmout in case of received but ingored signal
|
|
||||||
if elapsed > self.exec_tmout
|
|
||||||
|| self.exec_tmout - elapsed < self.avg_exec_time * self.avg_mul_k
|
|
||||||
{
|
|
||||||
let disarmed: libc::itimerspec = zeroed();
|
|
||||||
libc::timer_settime(self.timerid, 0, addr_of!(disarmed), null_mut());
|
|
||||||
// set timer the next exec
|
|
||||||
if self.executions > 0 {
|
|
||||||
self.avg_exec_time = elapsed / self.executions;
|
|
||||||
self.executions = 0;
|
|
||||||
}
|
|
||||||
// readjust K
|
|
||||||
if self.last_signal_time > self.exec_tmout * self.avg_mul_k
|
|
||||||
&& self.avg_mul_k > 1
|
|
||||||
{
|
|
||||||
self.avg_mul_k -= 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.executions += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
let disarmed: libc::itimerspec = zeroed();
|
|
||||||
libc::timer_settime(self.timerid, 0, addr_of!(disarmed), null_mut());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.executor.post_run_reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "linux")))]
|
|
||||||
impl<E, EM, Z> Executor<EM, Z> for TimeoutExecutor<E>
|
|
||||||
where
|
|
||||||
E: Executor<EM, Z>,
|
|
||||||
EM: UsesState<State = E::State>,
|
|
||||||
Z: UsesState<State = E::State>,
|
|
||||||
{
|
|
||||||
fn run_target(
|
|
||||||
&mut self,
|
|
||||||
fuzzer: &mut Z,
|
|
||||||
state: &mut Self::State,
|
|
||||||
mgr: &mut EM,
|
|
||||||
input: &Self::Input,
|
|
||||||
) -> Result<ExitKind, Error> {
|
|
||||||
unsafe {
|
|
||||||
setitimer(ITIMER_REAL, &mut self.itimerval, null_mut());
|
|
||||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
|
||||||
self.post_run_reset();
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn post_run_reset(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
let mut itimerval_zero: Itimerval = zeroed();
|
|
||||||
setitimer(ITIMER_REAL, &mut itimerval_zero, null_mut());
|
|
||||||
}
|
|
||||||
self.executor.post_run_reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E> UsesState for TimeoutExecutor<E>
|
|
||||||
where
|
|
||||||
E: UsesState,
|
|
||||||
{
|
|
||||||
type State = E::State;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E> UsesObservers for TimeoutExecutor<E>
|
|
||||||
where
|
|
||||||
E: UsesObservers,
|
|
||||||
{
|
|
||||||
type Observers = E::Observers;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E> HasObservers for TimeoutExecutor<E>
|
|
||||||
where
|
|
||||||
E: HasObservers,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn observers(&self) -> &Self::Observers {
|
|
||||||
self.executor.observers()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn observers_mut(&mut self) -> &mut Self::Observers {
|
|
||||||
self.executor.observers_mut()
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,9 +29,7 @@ where
|
|||||||
mgr: &mut EM,
|
mgr: &mut EM,
|
||||||
input: &Self::Input,
|
input: &Self::Input,
|
||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
self.executor.run_target(fuzzer, state, mgr, input)
|
||||||
self.executor.post_run_reset();
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use frida_gum::{
|
|||||||
};
|
};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use libafl::{
|
use libafl::{
|
||||||
executors::inprocess::{HasInProcessHandlers, InProcessHandlers},
|
executors::{hooks::inprocess::InProcessHooks, inprocess::HasInProcessHooks},
|
||||||
state::{HasCorpus, HasSolutions},
|
state::{HasCorpus, HasSolutions},
|
||||||
};
|
};
|
||||||
use libafl::{
|
use libafl::{
|
||||||
@ -230,7 +230,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHandlers
|
impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHooks
|
||||||
for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
|
for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input) -> ExitKind,
|
H: FnMut(&S::Input) -> ExitKind,
|
||||||
@ -241,7 +241,13 @@ where
|
|||||||
{
|
{
|
||||||
/// the timeout handler
|
/// the timeout handler
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inprocess_handlers(&self) -> &InProcessHandlers {
|
fn inprocess_hooks(&self) -> &InProcessHooks {
|
||||||
&self.base.handlers()
|
&self.base.hooks().0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the timeout handler
|
||||||
|
#[inline]
|
||||||
|
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks {
|
||||||
|
&mut self.base.hooks_mut().0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ macro_rules! fuzz_with {
|
|||||||
};
|
};
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
executors::{ExitKind, InProcessExecutor, TimeoutExecutor},
|
executors::{ExitKind, InProcessExecutor},
|
||||||
feedback_and_fast, feedback_not, feedback_or, feedback_or_fast,
|
feedback_and_fast, feedback_not, feedback_or, feedback_or_fast,
|
||||||
feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, NewHashFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, NewHashFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
generators::RandBytesGenerator,
|
generators::RandBytesGenerator,
|
||||||
@ -434,16 +434,14 @@ macro_rules! fuzz_with {
|
|||||||
let mut tracing_harness = harness;
|
let mut tracing_harness = harness;
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, size_edges_observer, time_observer, backtrace_observer, oom_observer),
|
tuple_list!(edges_observer, size_edges_observer, time_observer, backtrace_observer, oom_observer),
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
)?,
|
$options.timeout(),
|
||||||
$options.timeout(),
|
)?;
|
||||||
);
|
|
||||||
|
|
||||||
// In case the corpus is empty (on first run) or crashed while loading, reset
|
// In case the corpus is empty (on first run) or crashed while loading, reset
|
||||||
if state.must_load_initial_inputs() {
|
if state.must_load_initial_inputs() {
|
||||||
|
@ -10,7 +10,7 @@ use std::{
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
events::{EventRestarter, SimpleRestartingEventManager},
|
events::{EventRestarter, SimpleRestartingEventManager},
|
||||||
executors::{ExitKind, InProcessExecutor, TimeoutExecutor},
|
executors::{ExitKind, InProcessExecutor},
|
||||||
feedback_and_fast, feedback_or_fast,
|
feedback_and_fast, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MinMapFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MinMapFeedback, TimeoutFeedback},
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
@ -176,10 +176,14 @@ pub fn merge(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = TimeoutExecutor::new(
|
let mut executor = InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(&mut harness, observers, &mut fuzzer, &mut state, &mut mgr)?,
|
&mut harness,
|
||||||
|
observers,
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut mgr,
|
||||||
options.timeout(),
|
options.timeout(),
|
||||||
);
|
)?;
|
||||||
|
|
||||||
// In case the corpus is empty (on first run) or crashed while loading, reset
|
// In case the corpus is empty (on first run) or crashed while loading, reset
|
||||||
if state.must_load_initial_inputs() && !options.dirs().is_empty() {
|
if state.must_load_initial_inputs() && !options.dirs().is_empty() {
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, HasTestcase, InMemoryCorpus, Testcase},
|
corpus::{Corpus, HasTestcase, InMemoryCorpus, Testcase},
|
||||||
events::SimpleEventManager,
|
events::SimpleEventManager,
|
||||||
executors::{inprocess::TimeoutInProcessForkExecutor, ExitKind},
|
executors::{inprocess_fork::InProcessForkExecutor, ExitKind},
|
||||||
feedbacks::{CrashFeedbackFactory, TimeoutFeedbackFactory},
|
feedbacks::{CrashFeedbackFactory, TimeoutFeedbackFactory},
|
||||||
inputs::{BytesInput, HasBytesVec, HasTargetBytes},
|
inputs::{BytesInput, HasBytesVec, HasTargetBytes},
|
||||||
mutators::{havoc_mutations_no_crossover, Mutator, StdScheduledMutator},
|
mutators::{havoc_mutations_no_crossover, Mutator, StdScheduledMutator},
|
||||||
@ -62,7 +62,7 @@ fn minimize_crash_with_mutator<M: Mutator<BytesInput, TMinState>>(
|
|||||||
let mut fuzzer = StdFuzzer::new(QueueScheduler::new(), (), ());
|
let mut fuzzer = StdFuzzer::new(QueueScheduler::new(), (), ());
|
||||||
|
|
||||||
let shmem_provider = StdShMemProvider::new()?;
|
let shmem_provider = StdShMemProvider::new()?;
|
||||||
let mut executor = TimeoutInProcessForkExecutor::new(
|
let mut executor = InProcessForkExecutor::new(
|
||||||
&mut harness,
|
&mut harness,
|
||||||
(),
|
(),
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
use core::{
|
use core::{
|
||||||
ffi::c_void,
|
ffi::c_void,
|
||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "fork")]
|
#[cfg(feature = "fork")]
|
||||||
@ -13,7 +14,8 @@ use libafl::{
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
events::{EventFirer, EventRestarter},
|
events::{EventFirer, EventRestarter},
|
||||||
executors::{
|
executors::{
|
||||||
inprocess::{InProcessExecutor, InProcessExecutorHandlerData},
|
hooks::{inprocess::InProcessExecutorHandlerData, ExecutorHooksTuple},
|
||||||
|
inprocess::{HasInProcessHooks, InProcessExecutor},
|
||||||
Executor, ExitKind, HasObservers,
|
Executor, ExitKind, HasObservers,
|
||||||
},
|
},
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
@ -97,7 +99,7 @@ pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
|
|||||||
context: Option<&mut ucontext_t>,
|
context: Option<&mut ucontext_t>,
|
||||||
data: &mut InProcessExecutorHandlerData,
|
data: &mut InProcessExecutorHandlerData,
|
||||||
) where
|
) where
|
||||||
E: Executor<EM, Z> + HasObservers,
|
E: Executor<EM, Z> + HasObservers + HasInProcessHooks,
|
||||||
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
|
||||||
OF: Feedback<E::State>,
|
OF: Feedback<E::State>,
|
||||||
E::State: HasSolutions + HasCorpus + HasExecutions,
|
E::State: HasSolutions + HasCorpus + HasExecutions,
|
||||||
@ -106,7 +108,7 @@ pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
|
|||||||
if BREAK_ON_TMOUT {
|
if BREAK_ON_TMOUT {
|
||||||
qemu_system_debug_request();
|
qemu_system_debug_request();
|
||||||
} else {
|
} else {
|
||||||
libafl::executors::inprocess::unix_signal_handler::inproc_timeout_handler::<E, EM, OF, Z>(
|
libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::<E, EM, OF, Z>(
|
||||||
signal, info, context, data,
|
signal, info, context, data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -126,6 +128,7 @@ where
|
|||||||
fuzzer: &mut Z,
|
fuzzer: &mut Z,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
event_mgr: &mut EM,
|
event_mgr: &mut EM,
|
||||||
|
timeout: Duration,
|
||||||
) -> Result<Self, Error>
|
) -> Result<Self, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||||
@ -133,10 +136,12 @@ where
|
|||||||
S: State + HasExecutions + HasCorpus + HasSolutions,
|
S: State + HasExecutions + HasCorpus + HasSolutions,
|
||||||
Z: HasObjective<Objective = OF, State = S>,
|
Z: HasObjective<Objective = OF, State = S>,
|
||||||
{
|
{
|
||||||
let mut inner = InProcessExecutor::new(harness_fn, observers, fuzzer, state, event_mgr)?;
|
let mut inner = InProcessExecutor::with_timeout(
|
||||||
|
harness_fn, observers, fuzzer, state, event_mgr, timeout,
|
||||||
|
)?;
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
{
|
{
|
||||||
inner.handlers_mut().crash_handler =
|
inner.inprocess_hooks_mut().crash_handler =
|
||||||
inproc_qemu_crash_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
|
inproc_qemu_crash_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
|
||||||
as *const c_void;
|
as *const c_void;
|
||||||
|
|
||||||
@ -157,7 +162,7 @@ where
|
|||||||
}
|
}
|
||||||
#[cfg(emulation_mode = "systemmode")]
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
{
|
{
|
||||||
inner.handlers_mut().timeout_handler =
|
inner.inprocess_hooks_mut().timeout_handler =
|
||||||
inproc_qemu_timeout_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
|
inproc_qemu_timeout_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
|
||||||
as *const c_void;
|
as *const c_void;
|
||||||
}
|
}
|
||||||
@ -315,6 +320,7 @@ where
|
|||||||
state: &mut S,
|
state: &mut S,
|
||||||
event_mgr: &mut EM,
|
event_mgr: &mut EM,
|
||||||
shmem_provider: SP,
|
shmem_provider: SP,
|
||||||
|
timeout: core::time::Duration,
|
||||||
) -> Result<Self, Error>
|
) -> Result<Self, Error>
|
||||||
where
|
where
|
||||||
EM: EventFirer<State = S> + EventRestarter,
|
EM: EventFirer<State = S> + EventRestarter,
|
||||||
@ -333,6 +339,7 @@ where
|
|||||||
fuzzer,
|
fuzzer,
|
||||||
state,
|
state,
|
||||||
event_mgr,
|
event_mgr,
|
||||||
|
timeout,
|
||||||
shmem_provider,
|
shmem_provider,
|
||||||
)?,
|
)?,
|
||||||
})
|
})
|
||||||
|
@ -9,10 +9,7 @@ use core::{
|
|||||||
ptr::{self, addr_of},
|
ptr::{self, addr_of},
|
||||||
};
|
};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{executors::hooks::inprocess::inprocess_get_state, inputs::UsesInput};
|
||||||
executors::{inprocess::inprocess_get_state, ExitKind},
|
|
||||||
inputs::UsesInput,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use crate::emu::SyscallHookResult;
|
pub use crate::emu::SyscallHookResult;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -7,7 +7,7 @@ use std::{fs, net::SocketAddr, path::PathBuf, time::Duration};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
|
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
|
||||||
events::{launcher::Launcher, EventConfig, EventRestarter, LlmpRestartingEventManager},
|
events::{launcher::Launcher, EventConfig, EventRestarter, LlmpRestartingEventManager},
|
||||||
executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor, TimeoutExecutor},
|
executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -201,16 +201,14 @@ where
|
|||||||
|
|
||||||
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
let mut executor = ShadowExecutor::new(
|
let mut executor = ShadowExecutor::new(
|
||||||
TimeoutExecutor::new(
|
InProcessExecutor::with_timeout(
|
||||||
InProcessExecutor::new(
|
&mut harness,
|
||||||
&mut harness,
|
tuple_list!(edges_observer, time_observer),
|
||||||
tuple_list!(edges_observer, time_observer),
|
&mut fuzzer,
|
||||||
&mut fuzzer,
|
&mut state,
|
||||||
&mut state,
|
&mut mgr,
|
||||||
&mut mgr,
|
|
||||||
)?,
|
|
||||||
timeout,
|
timeout,
|
||||||
),
|
)?,
|
||||||
tuple_list!(cmplog_observer),
|
tuple_list!(cmplog_observer),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use std::{fs, net::SocketAddr, path::PathBuf, time::Duration};
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
|
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
|
||||||
events::{launcher::Launcher, EventConfig, EventRestarter, LlmpRestartingEventManager},
|
events::{launcher::Launcher, EventConfig, EventRestarter, LlmpRestartingEventManager},
|
||||||
executors::{ExitKind, ShadowExecutor, TimeoutExecutor},
|
executors::{ExitKind, ShadowExecutor},
|
||||||
feedback_or, feedback_or_fast,
|
feedback_or, feedback_or_fast,
|
||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
@ -231,8 +231,8 @@ where
|
|||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
timeout,
|
||||||
)?;
|
)?;
|
||||||
let executor = TimeoutExecutor::new(executor, timeout);
|
|
||||||
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
|
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
|
||||||
|
|
||||||
// In case the corpus is empty (on first run), reset
|
// In case the corpus is empty (on first run), reset
|
||||||
@ -330,15 +330,15 @@ where
|
|||||||
tuple_list!(QemuEdgeCoverageHelper::default()),
|
tuple_list!(QemuEdgeCoverageHelper::default()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let executor = QemuExecutor::new(
|
let mut executor = QemuExecutor::new(
|
||||||
&mut hooks,
|
&mut hooks,
|
||||||
&mut harness,
|
&mut harness,
|
||||||
tuple_list!(edges_observer, time_observer),
|
tuple_list!(edges_observer, time_observer),
|
||||||
&mut fuzzer,
|
&mut fuzzer,
|
||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
|
timeout,
|
||||||
)?;
|
)?;
|
||||||
let mut executor = TimeoutExecutor::new(executor, timeout);
|
|
||||||
|
|
||||||
// In case the corpus is empty (on first run), reset
|
// In case the corpus is empty (on first run), reset
|
||||||
if state.must_load_initial_inputs() {
|
if state.must_load_initial_inputs() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
events::{EventFirer, EventRestarter},
|
events::{EventFirer, EventRestarter},
|
||||||
executors::{inprocess::windows_asan_handler::asan_death_handler, Executor, HasObservers},
|
executors::{hooks::windows::windows_asan_handler::asan_death_handler, Executor, HasObservers},
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
state::{HasCorpus, HasExecutions, HasSolutions},
|
state::{HasCorpus, HasExecutions, HasSolutions},
|
||||||
HasObjective,
|
HasObjective,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user