pub mod map;
pub use map::*;
pub mod differential;
pub use differential::DiffFeedback;
#[cfg(feature = "std")]
pub mod concolic;
#[cfg(feature = "std")]
pub use concolic::ConcolicFeedback;
#[cfg(feature = "std")]
pub mod new_hash_feedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedback;
#[cfg(feature = "std")]
pub use new_hash_feedback::NewHashFeedbackMetadata;
#[cfg(feature = "nautilus")]
pub mod nautilus;
#[cfg(feature = "std")]
pub mod stdio;
pub mod transferred;
pub mod list;
use alloc::string::{String, ToString};
use core::{
fmt::{self, Debug, Formatter},
marker::PhantomData,
};
use libafl_bolts::Named;
pub use list::*;
#[cfg(feature = "nautilus")]
pub use nautilus::*;
use serde::{Deserialize, Serialize};
use crate::{
corpus::Testcase,
events::EventFirer,
executors::ExitKind,
observers::{ObserversTuple, TimeObserver},
state::State,
Error,
};
pub trait Feedback<S>: Named
where
S: State,
{
fn init_state(&mut self, _state: &mut S) -> Result<(), Error> {
Ok(())
}
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>;
#[cfg(feature = "introspection")]
#[allow(clippy::too_many_arguments)]
#[allow(clippy::wrong_self_convention)]
fn is_interesting_introspection<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let start_time = libafl_bolts::cpu::read_time_counter();
let ret = self.is_interesting(state, manager, input, observers, exit_kind);
let elapsed = libafl_bolts::cpu::read_time_counter() - start_time;
state
.introspection_monitor_mut()
.update_feedback(self.name(), elapsed);
ret
}
#[inline]
#[allow(unused_variables)]
fn append_metadata<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
observers: &OT,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error>
where
OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{
Ok(())
}
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
}
pub trait HasObserverName {
fn observer_name(&self) -> &str;
}
#[derive(Debug)]
pub struct CombinedFeedback<A, B, FL, S>
where
A: Feedback<S>,
B: Feedback<S>,
FL: FeedbackLogic<A, B, S>,
S: State,
{
pub first: A,
pub second: B,
name: String,
phantom: PhantomData<(S, FL)>,
}
impl<A, B, FL, S> Named for CombinedFeedback<A, B, FL, S>
where
A: Feedback<S>,
B: Feedback<S>,
FL: FeedbackLogic<A, B, S>,
S: State,
{
fn name(&self) -> &str {
self.name.as_ref()
}
}
impl<A, B, FL, S> CombinedFeedback<A, B, FL, S>
where
A: Feedback<S>,
B: Feedback<S>,
FL: FeedbackLogic<A, B, S>,
S: State,
{
pub fn new(first: A, second: B) -> Self {
let name = format!("{} ({},{})", FL::name(), first.name(), second.name());
Self {
first,
second,
name,
phantom: PhantomData,
}
}
}
impl<A, B, FL, S> Feedback<S> for CombinedFeedback<A, B, FL, S>
where
A: Feedback<S>,
B: Feedback<S>,
FL: FeedbackLogic<A, B, S>,
S: State,
{
fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
self.first.init_state(state)?;
self.second.init_state(state)?;
Ok(())
}
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
FL::is_pair_interesting(
&mut self.first,
&mut self.second,
state,
manager,
input,
observers,
exit_kind,
)
}
#[cfg(feature = "introspection")]
#[allow(clippy::wrong_self_convention)]
fn is_interesting_introspection<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
FL::is_pair_interesting_introspection(
&mut self.first,
&mut self.second,
state,
manager,
input,
observers,
exit_kind,
)
}
#[inline]
fn append_metadata<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
observers: &OT,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error>
where
OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{
self.first
.append_metadata(state, manager, observers, testcase)?;
self.second
.append_metadata(state, manager, observers, testcase)
}
#[inline]
fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.first.discard_metadata(state, input)?;
self.second.discard_metadata(state, input)
}
}
pub trait FeedbackLogic<A, B, S>: 'static
where
A: Feedback<S>,
B: Feedback<S>,
S: State,
{
fn name() -> &'static str;
fn is_pair_interesting<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>;
#[cfg(feature = "introspection")]
#[allow(clippy::too_many_arguments)]
fn is_pair_interesting_introspection<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>;
}
pub trait FeedbackFactory<F, S, T>
where
F: Feedback<S>,
S: State,
{
fn create_feedback(&self, ctx: &T) -> F;
}
impl<FE, FU, S, T> FeedbackFactory<FE, S, T> for FU
where
FU: Fn(&T) -> FE,
FE: Feedback<S>,
S: State,
{
fn create_feedback(&self, ctx: &T) -> FE {
self(ctx)
}
}
#[derive(Default, Debug, Copy, Clone)]
pub struct DefaultFeedbackFactory<F>
where
F: Default,
{
phantom: PhantomData<F>,
}
impl<F> DefaultFeedbackFactory<F>
where
F: Default,
{
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
impl<F, S, T> FeedbackFactory<F, S, T> for DefaultFeedbackFactory<F>
where
F: Feedback<S> + Default,
S: State,
{
fn create_feedback(&self, _ctx: &T) -> F {
F::default()
}
}
#[derive(Debug, Clone)]
pub struct LogicEagerOr {}
#[derive(Debug, Clone)]
pub struct LogicFastOr {}
#[derive(Debug, Clone)]
pub struct LogicEagerAnd {}
#[derive(Debug, Clone)]
pub struct LogicFastAnd {}
impl<A, B, S> FeedbackLogic<A, B, S> for LogicEagerOr
where
A: Feedback<S>,
B: Feedback<S>,
S: State,
{
fn name() -> &'static str {
"Eager OR"
}
fn is_pair_interesting<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
Ok(a || b)
}
#[cfg(feature = "introspection")]
fn is_pair_interesting_introspection<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
Ok(a || b)
}
}
impl<A, B, S> FeedbackLogic<A, B, S> for LogicFastOr
where
A: Feedback<S>,
B: Feedback<S>,
S: State,
{
fn name() -> &'static str {
"Fast OR"
}
fn is_pair_interesting<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
if a {
return Ok(true);
}
second.is_interesting(state, manager, input, observers, exit_kind)
}
#[cfg(feature = "introspection")]
fn is_pair_interesting_introspection<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
if a {
return Ok(true);
}
second.is_interesting_introspection(state, manager, input, observers, exit_kind)
}
}
impl<A, B, S> FeedbackLogic<A, B, S> for LogicEagerAnd
where
A: Feedback<S>,
B: Feedback<S>,
S: State,
{
fn name() -> &'static str {
"Eager AND"
}
fn is_pair_interesting<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
Ok(a && b)
}
#[cfg(feature = "introspection")]
fn is_pair_interesting_introspection<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
Ok(a && b)
}
}
impl<A, B, S> FeedbackLogic<A, B, S> for LogicFastAnd
where
A: Feedback<S>,
B: Feedback<S>,
S: State,
{
fn name() -> &'static str {
"Fast AND"
}
fn is_pair_interesting<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
if !a {
return Ok(false);
}
second.is_interesting(state, manager, input, observers, exit_kind)
}
#[cfg(feature = "introspection")]
fn is_pair_interesting_introspection<EM, OT>(
first: &mut A,
second: &mut B,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?;
if !a {
return Ok(false);
}
second.is_interesting_introspection(state, manager, input, observers, exit_kind)
}
}
pub type EagerAndFeedback<A, B, S> = CombinedFeedback<A, B, LogicEagerAnd, S>;
pub type FastAndFeedback<A, B, S> = CombinedFeedback<A, B, LogicFastAnd, S>;
pub type EagerOrFeedback<A, B, S> = CombinedFeedback<A, B, LogicEagerOr, S>;
pub type FastOrFeedback<A, B, S> = CombinedFeedback<A, B, LogicFastOr, S>;
#[derive(Clone)]
pub struct NotFeedback<A, S>
where
A: Feedback<S>,
S: State,
{
pub first: A,
name: String,
phantom: PhantomData<S>,
}
impl<A, S> Debug for NotFeedback<A, S>
where
A: Feedback<S> + Debug,
S: State,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("NotFeedback")
.field("name", &self.name)
.field("first", &self.first)
.finish()
}
}
impl<A, S> Feedback<S> for NotFeedback<A, S>
where
A: Feedback<S>,
S: State,
{
fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
self.first.init_state(state)
}
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &S::Input,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
Ok(!self
.first
.is_interesting(state, manager, input, observers, exit_kind)?)
}
#[inline]
fn append_metadata<EM, OT>(
&mut self,
state: &mut S,
manager: &mut EM,
observers: &OT,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error>
where
OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{
self.first
.append_metadata(state, manager, observers, testcase)
}
#[inline]
fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.first.discard_metadata(state, input)
}
}
impl<A, S> Named for NotFeedback<A, S>
where
A: Feedback<S>,
S: State,
{
#[inline]
fn name(&self) -> &str {
&self.name
}
}
impl<A, S> NotFeedback<A, S>
where
A: Feedback<S>,
S: State,
{
pub fn new(first: A) -> Self {
let name = format!("Not({})", first.name());
Self {
first,
name,
phantom: PhantomData,
}
}
}
#[macro_export]
macro_rules! feedback_and {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
$crate::feedbacks::EagerAndFeedback::new($head , feedback_and!($($tail),+))
};
}
#[macro_export]
macro_rules! feedback_and_fast {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
$crate::feedbacks::FastAndFeedback::new($head , feedback_and_fast!($($tail),+))
};
}
#[macro_export]
macro_rules! feedback_or {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
$crate::feedbacks::EagerOrFeedback::new($head , feedback_or!($($tail),+))
};
}
#[macro_export]
macro_rules! feedback_or_fast {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
$crate::feedbacks::FastOrFeedback::new($head , feedback_or_fast!($($tail),+))
};
}
#[macro_export]
macro_rules! feedback_not {
( $last:expr ) => {
$crate::feedbacks::NotFeedback::new($last)
};
}
impl<S> Feedback<S> for ()
where
S: State,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
Ok(false)
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CrashFeedback {}
impl<S> Feedback<S> for CrashFeedback
where
S: State,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
if let ExitKind::Crash = exit_kind {
Ok(true)
} else {
Ok(false)
}
}
}
impl Named for CrashFeedback {
#[inline]
fn name(&self) -> &str {
"CrashFeedback"
}
}
impl CrashFeedback {
#[must_use]
pub fn new() -> Self {
Self {}
}
}
impl Default for CrashFeedback {
fn default() -> Self {
Self::new()
}
}
pub type CrashFeedbackFactory = DefaultFeedbackFactory<CrashFeedback>;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeoutFeedback {}
impl<S> Feedback<S> for TimeoutFeedback
where
S: State,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
if let ExitKind::Timeout = exit_kind {
Ok(true)
} else {
Ok(false)
}
}
}
impl Named for TimeoutFeedback {
#[inline]
fn name(&self) -> &str {
"TimeoutFeedback"
}
}
impl TimeoutFeedback {
#[must_use]
pub fn new() -> Self {
Self {}
}
}
impl Default for TimeoutFeedback {
fn default() -> Self {
Self::new()
}
}
pub type TimeoutFeedbackFactory = DefaultFeedbackFactory<TimeoutFeedback>;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeFeedback {
name: String,
}
impl<S> Feedback<S> for TimeFeedback
where
S: State,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
Ok(false)
}
#[inline]
fn append_metadata<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
observers: &OT,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error>
where
OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap();
*testcase.exec_time_mut() = *observer.last_runtime();
Ok(())
}
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
}
impl Named for TimeFeedback {
#[inline]
fn name(&self) -> &str {
self.name.as_str()
}
}
impl TimeFeedback {
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: name.to_string(),
}
}
#[must_use]
pub fn with_observer(observer: &TimeObserver) -> Self {
Self {
name: observer.name().to_string(),
}
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConstFeedback {
True,
False,
}
impl<S> Feedback<S> for ConstFeedback
where
S: State,
{
#[inline]
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
Ok(match self {
ConstFeedback::True => true,
ConstFeedback::False => false,
})
}
}
impl Named for ConstFeedback {
#[inline]
fn name(&self) -> &str {
"ConstFeedback"
}
}
impl ConstFeedback {
#[must_use]
pub fn new(val: bool) -> Self {
Self::from(val)
}
}
impl From<bool> for ConstFeedback {
fn from(val: bool) -> Self {
if val {
Self::True
} else {
Self::False
}
}
}