Skip to content

Commit

Permalink
Merge pull request #26 from epi052/make-libafl-optional
Browse files Browse the repository at this point in the history
Make libafl optional
  • Loading branch information
epi052 authored Oct 14, 2023
2 parents d2c04d0 + 9e01e4a commit cbb8141
Show file tree
Hide file tree
Showing 23 changed files with 306 additions and 84 deletions.
24 changes: 18 additions & 6 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
name: Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
Expand All @@ -21,7 +21,7 @@ jobs:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
Expand All @@ -33,19 +33,31 @@ jobs:
args: --all-features --doc
- name: Install latest nextest release
uses: taiki-e/install-action@nextest
- name: Test with latest nextest release
- name: Test with all features
uses: actions-rs/cargo@v1
with:
command: nextest
args: run --all-targets --all-features
args: run --retries 10 --lib --all-targets --all-features
- name: Test with default features
uses: actions-rs/cargo@v1
with:
command: nextest
args: run --retries 10 --lib

semver:
name: Semver Check
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cargo semver checks
uses: obi1kenobi/cargo-semver-checks-action@v2

fmt:
name: Rust fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
Expand All @@ -61,7 +73,7 @@ jobs:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
Expand Down
10 changes: 8 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.11"
version = "1.0.0-rc.12"
edition = "2021"
authors = ["Ben 'epi' Risher (@epi052)"]
license = "Apache-2.0"
Expand Down Expand Up @@ -29,6 +29,9 @@ blocking = ["reqwest/blocking"]
# wrapper around providing different encoders
encoders = ["base64", "hex"]

# wrapper around providing havoc mutations
havoc = ["libafl", "libafl_bolts"]

[dependencies]
# MIT Licenses
tuple_list = { version = "0.1" }
Expand All @@ -47,7 +50,6 @@ 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.10.1", default-features = false, features = ["std"] }
url = { version = "2.2", features = ["serde"] }
## optional
serde = { version = "1.0", optional = true, features = ["derive", "rc"] }
Expand All @@ -66,6 +68,10 @@ futures = { version = "0.3", optional = true }
base64 = { version = "0.21.2", optional = true }
hex = { version = "0.4.3", optional = true }
flume = { version = "0.11.0" }
libafl = { version = "0.11.1", default-features = false, features = [
"std",
], optional = true }
libafl_bolts = { version = "0.11.1", default-features = false, optional = true }

[dev-dependencies]
http = { version = "0.2" }
Expand Down
1 change: 1 addition & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ cargo test --all-features --doc "${@}"
[tasks.test-lib]
clear = true
script = """
cargo nextest run --retries 10 --lib "${@}"
cargo nextest run --all-features --retries 10 --lib "${@}"
"""

Expand Down
2 changes: 1 addition & 1 deletion examples/havoc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! first, update the variable named target with a valid url to scan
//!
//! then run the example with the following command
//! cargo run --example havoc
//! cargo run --features havoc --example havoc
use feroxfuzz::actions::{Action, FlowControl};
use feroxfuzz::client::{AsyncClient, HttpClient};
use feroxfuzz::corpora::{CorpusItemType, Wordlist};
Expand Down
2 changes: 1 addition & 1 deletion src/deciders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ where
}
}

#[cfg(test)]
#[cfg(all(test, feature = "blocking"))]
mod tests {
#![allow(clippy::similar_names)]
use super::*;
Expand Down
14 changes: 14 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,26 @@ pub enum FeroxFuzzError {
/// Represents a failed mutation of a [`Request`] object
///
/// [`Request`]: crate::requests::Request
#[cfg(feature = "libafl")]
#[error("Mutation failed")]
MutationError {
/// underlying source error-type
source: libafl::Error,
},

/// Represents a failure to convert between two number types
#[error("Conversion from {value}_{from} to {to} failed")]
ConversionError {
/// value that couldn't be converted
value: String,

/// type to which conversion was attempted
to: String,

/// type from which conversion was attempted
from: String,
},

/// Represents a failure encountered during sending a request / receiving a response
#[error("An error occurred while sending the request: {kind:?} {message}")]
RequestError {
Expand Down
3 changes: 2 additions & 1 deletion src/fuzzers/async_fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,11 @@ where

// if any of the tasks failed, log the error and move along, nothing can really be
// done about it from here
#[allow(clippy::tuple_array_conversions)] // false positive
[first, second, third, fourth, fifth, sixth]
.into_iter()
.filter_map(|result| match result {
Ok(_) => None,
Ok(()) => None,
Err(err) => Some(err),
})
.for_each(|err| {
Expand Down
2 changes: 1 addition & 1 deletion src/fuzzers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl Debug for FuzzingLoopHook {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FuzzingLoopHook")
.field("called", &self.called)
.finish()
.finish_non_exhaustive() // purposely ignore callback
}
}

Expand Down
34 changes: 20 additions & 14 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ use crate::error::FeroxFuzzError;
use crate::std_ext::convert::{AsInner, IntoInner};
use crate::std_ext::fmt::DisplayExt;
use crate::AsBytes;
#[cfg(feature = "libafl")]
use libafl::inputs::{HasBytesVec, Input};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug, Display, Formatter};
use std::str::FromStr;
use std::string::ParseError;

use cfg_if::cfg_if;
use tracing::{error, instrument};

/// Base-level input type; can be marked `Fuzzable` or `Static`
Expand Down Expand Up @@ -339,22 +341,26 @@ impl PartialEq<Data> for Vec<u8> {
}
}

// implement the HasBytesVec and Input traits from libafl so our
// state plays nicely with libafl mutators
impl HasBytesVec for Data {
fn bytes(&self) -> &[u8] {
self.as_ref()
}
cfg_if! {
if #[cfg(feature = "libafl")] {
// implement the HasBytesVec and Input traits from libafl so our
// state plays nicely with libafl mutators
impl HasBytesVec for Data {
fn bytes(&self) -> &[u8] {
self.as_ref()
}

fn bytes_mut(&mut self) -> &mut Vec<u8> {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner,
fn bytes_mut(&mut self) -> &mut Vec<u8> {
match self {
Self::Fuzzable(inner) | Self::Static(inner) => inner,
}
}
}
}
}

impl Input for Data {
fn generate_name(&self, idx: usize) -> String {
format!("{}_{idx}", self.format())
impl Input for Data {
fn generate_name(&self, idx: usize) -> String {
format!("{}_{idx}", self.format())
}
}
}
}
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ pub use tuple_list::TupleList as MutatorsList;
pub use tuple_list::TupleList as ProcessorsList;

// re-exported 3rd party crate traits
pub use libafl::bolts::rands::Rand;
#[cfg(feature = "libafl")]
pub use libafl_bolts::rands::Rand;

/// Wrapper `Atomic*.fetch_add` to save me from writing `Ordering::SeqCst` a bajillion times
///
Expand Down
2 changes: 1 addition & 1 deletion src/mutators/afl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use crate::std_ext::ops::Len;
use crate::std_ext::tuple::Named;
use crate::{atomic_load, AsBytes};

use libafl::bolts::rands::Rand;
use libafl::inputs::HasBytesVec;
use libafl::state::{HasMaxSize, HasRand};
use libafl_bolts::rands::Rand;
#[cfg(feature = "serde")]
use serde::{
de::{self, Deserialize, Deserializer, MapAccess, Visitor},
Expand Down
2 changes: 1 addition & 1 deletion src/mutators/havoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
use std::any::Any;
use std::sync::atomic::Ordering;

use libafl::bolts::rands::Rand;
use libafl::state::HasRand;
use libafl_bolts::rands::Rand;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

Expand Down
28 changes: 17 additions & 11 deletions src/mutators/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
//! actions taken against [`Data`] that change the underlying bytes in some way
mod afl;
mod havoc;
mod wordlist_token;
pub use self::wordlist_token::ReplaceKeyword;

use cfg_if::cfg_if;

cfg_if! {
if #[cfg(any(feature = "havoc", feature = "libafl"))] {
mod afl;
mod havoc;
pub use self::afl::*;
pub use self::havoc::HavocMutator;
}
}

use std::sync::{Arc, Once, RwLock};

use dyn_clone::DynClone;
use tracing::instrument;

use crate::error::FeroxFuzzError;
use crate::events::{EventPublisher, Mutation, Publisher};
use crate::input::Data;
Expand All @@ -14,13 +27,6 @@ use crate::state::SharedState;
use crate::std_ext::tuple::Named;
use crate::MutatorsList;

pub use self::afl::*;
pub use self::havoc::HavocMutator;
pub use self::wordlist_token::ReplaceKeyword;

use dyn_clone::DynClone;
use tracing::instrument;

static mut HAS_LISTENERS: bool = false;
static INIT: Once = Once::new();

Expand Down Expand Up @@ -158,7 +164,7 @@ pub trait Mutator: DynClone + AsAny + Named + Send + Sync {
}

if let Some(headers) = request.headers.as_mut() {
for (key, value) in headers.iter_mut() {
for (key, value) in &mut *headers {
if key.is_fuzzable() {
self.mutate(key, state)?;
notify_listeners(
Expand All @@ -182,7 +188,7 @@ pub trait Mutator: DynClone + AsAny + Named + Send + Sync {
}

if let Some(params) = request.params.as_mut() {
for (key, value) in params.iter_mut() {
for (key, value) in &mut *params {
if key.is_fuzzable() {
self.mutate(key, state)?;
notify_listeners(
Expand Down
22 changes: 21 additions & 1 deletion src/mutators/wordlist_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,27 @@ impl Mutator for ReplaceKeyword {
// piece of data, the index gathered above will move by some amount.
// the `step` value here is one piece of info necessary to calculate
// how far the move is.
let step = entry.len() as i64 - self.keyword.len() as i64;
let entry_length = i64::try_from(entry.len()).map_err(|source| {
tracing::error!(%source, "could not convert from {} to an i64", entry.len());

FeroxFuzzError::ConversionError {
value: format!("{}", entry.len()),
to: String::from("i64"),
from: String::from("usize"),
}
})?;

let keyword_length = i64::try_from(self.keyword.len()).map_err(|source| {
tracing::error!(%source, "could not convert from {} to an i64", self.keyword.len());

FeroxFuzzError::ConversionError {
value: format!("{}", self.keyword.len()),
to: String::from("i64"),
from: String::from("usize"),
}
})?;

let step = entry_length - keyword_length;

indices.iter().enumerate().for_each(|(i, &idx)| {
// when the step is negative, we need to subtract the
Expand Down
3 changes: 1 addition & 2 deletions src/observers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
//! [`Deciders`]: crate::deciders::Deciders
use crate::requests::Request;
use crate::responses::Response;
use crate::std_ext::tuple::Named;
use crate::MatchName;
use crate::std_ext::tuple::{MatchName, Named};
use crate::ObserversList;

mod response;
Expand Down
8 changes: 3 additions & 5 deletions src/requests/encoders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ macro_rules! encode_optional_field {
}

// buffer of a size big enough to hold the encoded value
let mut buffer = Vec::new();
buffer.resize($field.len() * 4 / 3 + 4, 0);
let mut buffer = vec![0; $field.len() * 4 / 3 + 4];

// perform the write
let written = general_purpose::URL_SAFE.encode_slice(
Expand Down Expand Up @@ -63,8 +62,7 @@ macro_rules! encode_optional_field {
}

// buffer of a size big enough to hold the encoded value
let mut buffer = Vec::new();
buffer.resize($field.len() * 2, 0);
let mut buffer = vec![0; $field.len() * 2];

// perform the write
//
Expand Down Expand Up @@ -345,7 +343,7 @@ impl RequestExt for Request {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "encoders"))]
mod tests {
use super::*;
use crate::requests::ShouldFuzz;
Expand Down
2 changes: 1 addition & 1 deletion src/schedulers/ordered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl OrderedScheduler {

let mut indices = Vec::with_capacity(corpora.len());

for (name, corpus) in corpora.iter() {
for (name, corpus) in &*corpora {
let length = corpus.len();

if length == 0 {
Expand Down
Loading

0 comments on commit cbb8141

Please sign in to comment.