
* Associated types for Corpus, State * cleanup * fix no_std * drop unused clauses * Corpus * cleanup * adding things * fixed fuzzer * remove phantom data * python * progress? * more more * oof * wow it builds? * python fixes, tests * fix python fun * black fmt for python * clippy, added Nop things * fixes * fix merge * make it compile (#836) * doc-test fixes, prelude-b-gone for cargo-hack compat * fixes for windows, concolic * really fix windows, maybe * imagine using windows * ... * elide I generic when used with S: State * Elide many, many generics, but at what cost? * progress on push * Constraint HasCorpus, HasSolutions at trait definition * remove unused feature * remove unstable usage since we constrained HasCorpus at definition * compiled, but still no type inference for MaxMapFeedback * cleanup inprocess * resolve some std conflicts * simplify map * undo unnecessary cfg specification * fix breaking test case for CI on no-std * fix concolic build failures * fix macos build * fixes for windows build * timeout fixes for windows build * fix pybindings issues * fixup qemu * fix outstanding local build issues * maybe fix windows inprocess * doc fixes * unbridled fury * de-associate State from Feedback, replace with generic as AT inference is not sufficient to derive specialisation for MapFeedback * merge update * refactor + speed up fuzzer builds by sharing build work * cleanup lingering compiler errors * lol missed one * revert QEMU-Nyx change, not sure how I did that * move HasInput to inputs * HasInput => KnowsInput * update bounds to enforce via associated types * disentangle observers with fuzzer * revert --target; update some fuzzers to match new API * resolve outstanding fuzzer build blockers (that I can run on my system) * fixes for non-linux unixes * fix for windows * Knows => Uses, final fixes for windows * <guttural screaming> * fixes for concolic * loosen bound for frida executor so windows builds correctly * cleanup generics for eventmanager/eventprocessor to drop observers requirement * improve inference over fuzz_one and friends * update migration notes * fixes for python bindings * fixes for generic counts in event managers * finish migration notes * post-merge fix Co-authored-by: Addison Crump <addison.crump@cispa.de>
241 lines
7.2 KiB
Rust
241 lines
7.2 KiB
Rust
//! Executor for differential fuzzing.
|
|
//! It wraps two executors that will be run after each other with the same input.
|
|
//! In comparison to the [`crate::executors::CombinedExecutor`] it also runs the secondary executor in `run_target`.
|
|
//!
|
|
use core::{cell::UnsafeCell, fmt::Debug};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{
|
|
bolts::{ownedref::OwnedPtrMut, tuples::MatchName},
|
|
executors::{Executor, ExitKind, HasObservers},
|
|
inputs::UsesInput,
|
|
observers::{ObserversTuple, UsesObservers},
|
|
state::UsesState,
|
|
Error,
|
|
};
|
|
|
|
/// A [`DiffExecutor`] wraps a primary executor, forwarding its methods, and a secondary one
|
|
#[derive(Debug)]
|
|
pub struct DiffExecutor<A, B, OTA, OTB> {
|
|
primary: A,
|
|
secondary: B,
|
|
observers: UnsafeCell<ProxyObserversTuple<OTA, OTB>>,
|
|
}
|
|
|
|
impl<A, B, OTA, OTB> DiffExecutor<A, B, OTA, OTB> {
|
|
/// Create a new `DiffExecutor`, wrapping the given `executor`s.
|
|
pub fn new<EM, Z>(primary: A, secondary: B) -> Self
|
|
where
|
|
A: Executor<EM, Z>,
|
|
B: Executor<EM, Z, State = A::State>,
|
|
EM: UsesState<State = A::State>,
|
|
Z: UsesState<State = A::State>,
|
|
{
|
|
Self {
|
|
primary,
|
|
secondary,
|
|
observers: UnsafeCell::new(ProxyObserversTuple {
|
|
primary: OwnedPtrMut::Ptr(core::ptr::null_mut()),
|
|
secondary: OwnedPtrMut::Ptr(core::ptr::null_mut()),
|
|
}),
|
|
}
|
|
}
|
|
|
|
/// Retrieve the primary `Executor` that is wrapped by this `DiffExecutor`.
|
|
pub fn primary(&mut self) -> &mut A {
|
|
&mut self.primary
|
|
}
|
|
|
|
/// Retrieve the secondary `Executor` that is wrapped by this `DiffExecutor`.
|
|
pub fn secondary(&mut self) -> &mut B {
|
|
&mut self.secondary
|
|
}
|
|
}
|
|
|
|
impl<A, B, EM, OTA, OTB, Z> Executor<EM, Z> for DiffExecutor<A, B, OTA, OTB>
|
|
where
|
|
A: Executor<EM, Z>,
|
|
B: Executor<EM, Z, State = A::State>,
|
|
EM: UsesState<State = A::State>,
|
|
OTA: Debug,
|
|
OTB: Debug,
|
|
Z: UsesState<State = A::State>,
|
|
{
|
|
fn run_target(
|
|
&mut self,
|
|
fuzzer: &mut Z,
|
|
state: &mut Self::State,
|
|
mgr: &mut EM,
|
|
input: &Self::Input,
|
|
) -> Result<ExitKind, Error> {
|
|
let ret1 = self.primary.run_target(fuzzer, state, mgr, input)?;
|
|
self.primary.post_run_reset();
|
|
let ret2 = self.secondary.run_target(fuzzer, state, mgr, input)?;
|
|
self.secondary.post_run_reset();
|
|
if ret1 == ret2 {
|
|
Ok(ret1)
|
|
} else {
|
|
// We found a diff in the exit codes!
|
|
Ok(ExitKind::Diff {
|
|
primary: ret1.into(),
|
|
secondary: ret2.into(),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Proxy the observers of the inner executors
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
#[serde(
|
|
bound = "A: serde::Serialize + serde::de::DeserializeOwned, B: serde::Serialize + serde::de::DeserializeOwned"
|
|
)]
|
|
pub struct ProxyObserversTuple<A, B> {
|
|
primary: OwnedPtrMut<A>,
|
|
secondary: OwnedPtrMut<B>,
|
|
}
|
|
|
|
impl<A, B, S> ObserversTuple<S> for ProxyObserversTuple<A, B>
|
|
where
|
|
A: ObserversTuple<S>,
|
|
B: ObserversTuple<S>,
|
|
S: UsesInput,
|
|
{
|
|
fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
|
self.primary.as_mut().pre_exec_all(state, input)?;
|
|
self.secondary.as_mut().pre_exec_all(state, input)
|
|
}
|
|
|
|
fn post_exec_all(
|
|
&mut self,
|
|
state: &mut S,
|
|
input: &S::Input,
|
|
exit_kind: &ExitKind,
|
|
) -> Result<(), Error> {
|
|
self.primary
|
|
.as_mut()
|
|
.post_exec_all(state, input, exit_kind)?;
|
|
self.secondary
|
|
.as_mut()
|
|
.post_exec_all(state, input, exit_kind)
|
|
}
|
|
|
|
fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
|
|
self.primary.as_mut().pre_exec_child_all(state, input)?;
|
|
self.secondary.as_mut().pre_exec_child_all(state, input)
|
|
}
|
|
|
|
fn post_exec_child_all(
|
|
&mut self,
|
|
state: &mut S,
|
|
input: &S::Input,
|
|
exit_kind: &ExitKind,
|
|
) -> Result<(), Error> {
|
|
self.primary
|
|
.as_mut()
|
|
.post_exec_child_all(state, input, exit_kind)?;
|
|
self.secondary
|
|
.as_mut()
|
|
.post_exec_child_all(state, input, exit_kind)
|
|
}
|
|
|
|
/// Returns true if a `stdout` observer was added to the list
|
|
#[inline]
|
|
fn observes_stdout(&mut self) -> bool {
|
|
self.primary.as_mut().observes_stdout() || self.secondary.as_mut().observes_stdout()
|
|
}
|
|
/// Returns true if a `stderr` observer was added to the list
|
|
#[inline]
|
|
fn observes_stderr(&mut self) -> bool {
|
|
self.primary.as_mut().observes_stderr() || self.secondary.as_mut().observes_stderr()
|
|
}
|
|
|
|
/// Runs `observe_stdout` for all stdout observers in the list
|
|
fn observe_stdout(&mut self, stdout: &str) {
|
|
self.primary.as_mut().observe_stderr(stdout);
|
|
self.secondary.as_mut().observe_stderr(stdout);
|
|
}
|
|
|
|
/// Runs `observe_stderr` for all stderr observers in the list
|
|
fn observe_stderr(&mut self, stderr: &str) {
|
|
self.primary.as_mut().observe_stderr(stderr);
|
|
self.secondary.as_mut().observe_stderr(stderr);
|
|
}
|
|
}
|
|
|
|
impl<A, B> MatchName for ProxyObserversTuple<A, B>
|
|
where
|
|
A: MatchName,
|
|
B: MatchName,
|
|
{
|
|
fn match_name<T>(&self, name: &str) -> Option<&T> {
|
|
if let Some(t) = self.primary.as_ref().match_name::<T>(name) {
|
|
return Some(t);
|
|
}
|
|
self.secondary.as_ref().match_name::<T>(name)
|
|
}
|
|
fn match_name_mut<T>(&mut self, name: &str) -> Option<&mut T> {
|
|
if let Some(t) = self.primary.as_mut().match_name_mut::<T>(name) {
|
|
return Some(t);
|
|
}
|
|
self.secondary.as_mut().match_name_mut::<T>(name)
|
|
}
|
|
}
|
|
|
|
impl<A, B> ProxyObserversTuple<A, B> {
|
|
fn set(&mut self, primary: &A, secondary: &B) {
|
|
self.primary = OwnedPtrMut::Ptr(primary as *const A as *mut A);
|
|
self.secondary = OwnedPtrMut::Ptr(secondary as *const B as *mut B);
|
|
}
|
|
}
|
|
|
|
impl<A, B, OTA, OTB> UsesObservers for DiffExecutor<A, B, OTA, OTB>
|
|
where
|
|
A: HasObservers<Observers = OTA>,
|
|
B: HasObservers<Observers = OTB, State = A::State>,
|
|
OTA: ObserversTuple<A::State>,
|
|
OTB: ObserversTuple<A::State>,
|
|
{
|
|
type Observers = ProxyObserversTuple<OTA, OTB>;
|
|
}
|
|
|
|
impl<A, B, OTA, OTB> UsesState for DiffExecutor<A, B, OTA, OTB>
|
|
where
|
|
A: UsesState,
|
|
B: UsesState<State = A::State>,
|
|
{
|
|
type State = A::State;
|
|
}
|
|
|
|
impl<A, B, OTA, OTB> HasObservers for DiffExecutor<A, B, OTA, OTB>
|
|
where
|
|
A: HasObservers<Observers = OTA>,
|
|
B: HasObservers<Observers = OTB, State = A::State>,
|
|
OTA: ObserversTuple<A::State>,
|
|
OTB: ObserversTuple<A::State>,
|
|
{
|
|
#[inline]
|
|
fn observers(&self) -> &ProxyObserversTuple<OTA, OTB> {
|
|
unsafe {
|
|
self.observers
|
|
.get()
|
|
.as_mut()
|
|
.unwrap()
|
|
.set(self.primary.observers(), self.secondary.observers());
|
|
self.observers.get().as_ref().unwrap()
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn observers_mut(&mut self) -> &mut ProxyObserversTuple<OTA, OTB> {
|
|
unsafe {
|
|
self.observers
|
|
.get()
|
|
.as_mut()
|
|
.unwrap()
|
|
.set(self.primary.observers(), self.secondary.observers());
|
|
self.observers.get().as_mut().unwrap()
|
|
}
|
|
}
|
|
}
|