Skip to content

Commit

Permalink
add event publish/subscribe system
Browse files Browse the repository at this point in the history
Add event publish/subscribe system
  • Loading branch information
epi052 authored Nov 23, 2022
2 parents 905cf74 + 987c23a commit d55a269
Show file tree
Hide file tree
Showing 33 changed files with 1,165 additions and 385 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "feroxfuzz"
version = "1.0.0-rc.2"
version = "1.0.0-rc.3"
edition = "2021"
authors = ["Ben 'epi' Risher (@epi052)"]
license = "Apache-2.0"
Expand Down Expand Up @@ -47,7 +47,7 @@ tokio = { version = "1.20", optional = true, features = [
num = { version = "0.4" }
cfg-if = { version = "1.0" }
dyn-clone = { version = "1.0.9" }
libafl = { version = "0.8.1", default-features = false, features = ["std"] }
libafl = { version = "0.8.2", default-features = false, features = ["std"] }
url = { version = "2.2", features = ["serde"] }
## optional
serde = { version = "1.0", optional = true, features = ["derive", "rc"] }
Expand Down
27 changes: 15 additions & 12 deletions src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,23 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use cfg_if::cfg_if;

cfg_if! {
if #[cfg(docsrs)] {
// just bringing in types for easier intra-doc linking during doc build
use crate::requests::Request;
use crate::responses::Response;
use crate::corpora::Corpus;
use crate::processors::Processor;
}
}

/// all possible actions
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub enum Action {
/// when used in a pre-send context, retain the current [`Request`], if
/// used in a post-send context, retain the current [`Response`]
///
/// [`Request`]: crate::requests::Request
/// [`Response`]: crate::responses::Response
Keep,

/// when used in a pre-send context, ignore the current [`Request`], if
/// used in a post-send context, ignore the current [`Response`]
///
/// [`Request`]: crate::requests::Request
/// [`Response`]: crate::responses::Response
Discard,

/// add the current mutated field(s) to the [`Corpus`] associated
Expand All @@ -44,6 +38,9 @@ pub enum Action {
/// won't progress beyond being added to the corpus. In either case, the
/// resulting `Action` will still be passed to any configured
/// [`Processor`]s.
///
/// [`Corpus`]: crate::corpora::Corpus
/// [`Processor`]: crate::processors::Processor
AddToCorpus(&'static str, FlowControl),

/// break out of the current fuzz loop; no more iterations other than
Expand All @@ -60,10 +57,16 @@ pub enum Action {
pub enum FlowControl {
/// when used in a pre-send context, retain the current [`Request`], if
/// used in a post-send context, retain the current [`Response`]
///
/// [`Request`]: crate::requests::Request
/// [`Response`]: crate::responses::Response
Keep,

/// when used in a pre-send context, ignore the current [`Request`], if
/// used in a post-send context, ignore the current [`Response`]
///
/// [`Request`]: crate::requests::Request
/// [`Response`]: crate::responses::Response
Discard,

/// break out of the current fuzz loop; no more iterations other than
Expand Down
15 changes: 4 additions & 11 deletions src/deciders/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,6 @@ use crate::std_ext::tuple::Named;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use cfg_if::cfg_if;

cfg_if! {
if #[cfg(docsrs)] {
// just bringing in types for easier intra-doc linking during doc build
use crate::fuzzers::Fuzzer;
use crate::build_deciders;
use crate::deciders::Deciders;
}
}

/// Decide upon an [`Action`] based on a [`ResponseObserver`]'s content-length
///
/// # Examples
Expand All @@ -28,6 +17,10 @@ cfg_if! {
/// it, and any other [`Deciders`] to the [`build_deciders`] macro, and pass
/// the result of that call to your chosen [`Fuzzer`] implementation.
///
/// [`build_deciders`]: crate::build_deciders
/// [`Fuzzer`]: crate::fuzzers::Fuzzer
/// [`Deciders`]: crate::deciders::Deciders
///
/// ```
/// # use http::response;
/// # use feroxfuzz::responses::{Response, AsyncResponse};
Expand Down
41 changes: 32 additions & 9 deletions src/deciders/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! Use data from an [`Observer`] to make a decision about the supplied data
//!
//! [`Observer`]: crate::observers::Observer
mod length;
mod regex;
mod status_code;
Expand All @@ -18,19 +20,13 @@ pub use self::status_code::StatusCodeDecider;
// re-export LogicOperation from here, for a more logical location from an external user's perspective
pub use crate::std_ext::ops::LogicOperation;

use cfg_if::cfg_if;
use dyn_clone::DynClone;

cfg_if! {
if #[cfg(docsrs)] {
// just bringing in types for easier intra-doc linking during doc build
use crate::client::HttpClient;
use crate::observers::Observer;
}
}

/// A `Decider` pulls information from some [`Observer`] in order to
/// reach a decision about what [`Action`] should be taken
///
/// [`Action`]: crate::actions::Action
/// [`Observer`]: crate::observers::Observer
pub trait Decider<O, R>: DynClone + AsAny + Named
where
O: Observers<R>,
Expand All @@ -40,6 +36,10 @@ where
/// make a decision that returns an [`Action`]
///
/// this is typically called via the `pre_send_hook`
///
/// [`SharedState`]: crate::state::SharedState
/// [`Request`]: crate::requests::Request
/// [`Action`]: crate::actions::Action
fn decide_with_request(&mut self, _state: &SharedState, _request: &Request) -> Option<Action> {
None
}
Expand All @@ -48,6 +48,10 @@ where
/// returns an [`Action`]
///
/// this is typically called via the `post_send_hook`
///
/// [`SharedState`]: crate::state::SharedState
/// [`Observers`]: crate::observers::Observers
/// [`Action`]: crate::actions::Action
fn decide_with_observers(&mut self, _state: &SharedState, _observers: &O) -> Option<Action> {
None
}
Expand Down Expand Up @@ -86,6 +90,9 @@ where
R: Response,
{
/// called before an [`HttpClient`] sends a [`Request`]
///
/// [`HttpClient`]: crate::client::HttpClient
/// [`Request`]: crate::requests::Request
fn pre_send_hook(
&mut self,
state: &SharedState,
Expand Down Expand Up @@ -120,6 +127,9 @@ where
}

/// called after an [`HttpClient`] receives a [`Response`]
///
/// [`HttpClient`]: crate::client::HttpClient
/// [`Request`]: crate::requests::Request
fn post_send_hook(
&mut self,
state: &SharedState,
Expand Down Expand Up @@ -165,6 +175,11 @@ where
///
/// In order to logically group different sets of hooks, with different logic, we need
/// to make a separate [`Deciders`] tuple for each logical grouping.
///
/// [`Deciders`]: crate::deciders::Deciders
/// [`DeciderHooks`]: crate::deciders::DeciderHooks
/// [`DecidersList`]: crate::DecidersList
/// [`LogicOperation`]: crate::deciders::LogicOperation
pub trait Deciders<O, R>
where
O: Observers<R>,
Expand All @@ -173,6 +188,10 @@ where
/// called before an [`HttpClient`] sends a [`Request`]
///
/// recursively calls [`DeciderHooks::pre_send_hook`]
///
/// [`HttpClient`]: crate::client::HttpClient
/// [`Request`]: crate::requests::Request
/// [`DeciderHooks::pre_send_hook`]: crate::deciders::DeciderHooks::pre_send_hook
fn call_pre_send_hooks(
&mut self,
_state: &SharedState,
Expand All @@ -186,6 +205,10 @@ where
/// called after an [`HttpClient`] receives a [`Response`]
///
/// recursively calls [`DeciderHooks::post_send_hook`]
///
/// [`HttpClient`]: crate::client::HttpClient
/// [`Request`]: crate::requests::Request
/// [`DeciderHooks::post_send_hook`]: crate::deciders::DeciderHooks::post_send_hook
fn call_post_send_hooks(
&mut self,
_state: &SharedState,
Expand Down
15 changes: 4 additions & 11 deletions src/deciders/status_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,6 @@ use crate::std_ext::tuple::Named;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use cfg_if::cfg_if;

cfg_if! {
if #[cfg(docsrs)] {
// just bringing in types for easier intra-doc linking during doc build
use crate::fuzzers::Fuzzer;
use crate::build_deciders;
use crate::deciders::Deciders;
}
}

/// Decide upon an [`Action`] based on a [`ResponseObserver`]'s status code
///
/// # Examples
Expand All @@ -28,6 +17,10 @@ cfg_if! {
/// it, and any other [`Deciders`] to the [`build_deciders`] macro, and pass
/// the result of that call to your chosen [`Fuzzer`] implementation.
///
/// [`build_deciders`]: crate::build_deciders
/// [`Fuzzer`]: crate::fuzzers::Fuzzer
/// [`Deciders`]: crate::deciders::Deciders
///
/// ```
/// # use http::response;
/// # use feroxfuzz::responses::{Response, AsyncResponse};
Expand Down
37 changes: 22 additions & 15 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,6 @@ use serde::{Deserialize, Serialize};

use crate::input::Data;

use cfg_if::cfg_if;

cfg_if! {
if #[cfg(docsrs)] {
// just bringing in types for easier intra-doc linking during doc build
use crate::requests::Request;
use crate::std_ext::tuple::MatchName;
use crate::corpora::{Corpus, CorpusMap, CorpusIndices};
use crate::state::SharedState;
use crate::deciders::Decider;
use crate::actions::Action;
use crate::statistics::Statistics;
}
}

/// primary error-type for the feroxfuzz library
#[derive(Error, Debug)]
#[non_exhaustive]
Expand Down Expand Up @@ -96,6 +81,8 @@ pub enum FeroxFuzzError {
},

/// Represents an invalid index passed to [`Corpus::get`]
///
/// [`Corpus::get`]: crate::corpora::Corpus::get
#[error("Requested entry at `{index}` could not be found in Corpus `{name}`")]
CorpusEntryNotFound {
/// the name of the corpus
Expand All @@ -106,13 +93,17 @@ pub enum FeroxFuzzError {
},

/// Represents an invalid name passed to [`SharedState::corpus_by_name`]
///
/// [`SharedState::corpus_by_name`]: crate::state::SharedState::corpus_by_name
#[error("Requested Corpus named `{name}` could not be found")]
CorpusNotFound {
/// name of the requested corpus that couldn't be found
name: String,
},

/// Represents an invalid name passed to [`SharedState::corpus_index_by_name`]
///
/// [`SharedState::corpus_index_by_name`]: crate::state::SharedState::corpus_index_by_name
#[error("Requested index associated with Corpus named `{name}` could not be found")]
CorpusIndexNotFound {
/// name of the requested corpus index that couldn't be found
Expand Down Expand Up @@ -141,17 +132,23 @@ pub enum FeroxFuzzError {
},

/// Represents an empty [`Corpus`], which isn't allowed
///
/// [`Corpus`]: crate::corpora::Corpus
#[error("No entries were found in the Corpus `{name}`")]
EmptyCorpus {
/// name of the empty corpus
name: String,
},

/// Represents an empty [`CorpusMap`], which isn't allowed
///
/// [`CorpusMap`]: crate::corpora::CorpusMap
#[error("No corpora were found in the CorpusMap")]
EmptyCorpusMap,

/// Represents an empty [`CorpusIndices`], which isn't allowed
///
/// [`CorpusIndices`]: crate::corpora::CorpusIndices
#[error("No indices were found in the CorpusIndices map")]
EmptyCorpusIndices,

Expand All @@ -163,6 +160,8 @@ pub enum FeroxFuzzError {
},

/// Represents an invalid request passed to [`MatchName`]
///
/// [`MatchName`]: crate::MatchName
#[error("Requested Named `{name}` object could not be found via MatchName")]
NamedObjectNotFound {
/// contains the name of what was requested
Expand All @@ -174,6 +173,8 @@ pub enum FeroxFuzzError {
IterationStopped,

/// Represents a [`Request`] field that could not be parsed into a valid utf-8 &str
///
/// [`Request`]: crate::requests::Request
#[error("Could not parse bytes into valid utf-8 (required by &str)")]
UnparsableData {
/// underlying source error-type
Expand All @@ -192,6 +193,8 @@ pub enum FeroxFuzzError {
},

/// Represents a failed mutation of a [`Request`] object
///
/// [`Request`]: crate::requests::Request
#[error("Mutation failed")]
FailedMutation {
/// underlying source error-type
Expand Down Expand Up @@ -221,13 +224,17 @@ pub enum FeroxFuzzError {
/// Note: this is only used because of how the async fuzz_once loop
/// is implemented. It is not intended to be used outside of the
/// async fuzz_once loop.
///
/// [`Action::StopFuzzing`]: crate::actions::Action::StopFuzzing
#[error("Stopped fuzzing based on user-provided criteria")]
FuzzingStopped,
}

/// Used to differentiate between different types of errors that occur when making requests.
///
/// That differentiation is then used internally to update the proper error counts in [`Statistics`]
///
/// [`Statistics`]: crate::statistics::Statistics
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
#[non_exhaustive]
Expand Down
Loading

0 comments on commit d55a269

Please sign in to comment.