330 lines
8.6 KiB
Rust
330 lines
8.6 KiB
Rust
use core::fmt::Debug;
|
|
use core::cmp::Ordering::{Greater,Less,Equal};
|
|
use libafl::inputs::BytesInput;
|
|
use libafl::inputs::HasTargetBytes;
|
|
use libafl::feedbacks::MapIndexesMetadata;
|
|
use libafl::corpus::Testcase;
|
|
use libafl::prelude::{UsesInput, AsSlice};
|
|
use core::marker::PhantomData;
|
|
use libafl::schedulers::{MinimizerScheduler, TestcaseScore};
|
|
use std::path::PathBuf;
|
|
use std::fs;
|
|
use hashbrown::{HashMap};
|
|
use libafl::observers::ObserversTuple;
|
|
use libafl::executors::ExitKind;
|
|
use libafl::events::EventFirer;
|
|
use libafl::state::{HasClientPerfMonitor, HasCorpus, UsesState};
|
|
use libafl::inputs::Input;
|
|
use libafl::feedbacks::Feedback;
|
|
use libafl::state::HasMetadata;
|
|
use libafl_qemu::edges::QemuEdgesMapMetadata;
|
|
use libafl::observers::MapObserver;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::cmp;
|
|
|
|
use libafl::{
|
|
bolts::{
|
|
tuples::Named,
|
|
HasLen,
|
|
},
|
|
observers::Observer,
|
|
Error,
|
|
};
|
|
|
|
use crate::clock::QemuClockObserver;
|
|
use crate::systemstate::FreeRTOSSystemStateMetadata;
|
|
//=========================== Scheduler
|
|
|
|
pub type TimeMaximizerCorpusScheduler<CS> =
|
|
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>, MapIndexesMetadata>;
|
|
|
|
/// Multiply the testcase size with the execution time.
|
|
/// This favors small and quick testcases.
|
|
#[derive(Debug, Clone)]
|
|
pub struct MaxTimeFavFactor<S>
|
|
where
|
|
S: HasCorpus + HasMetadata,
|
|
S::Input: HasLen,
|
|
{
|
|
phantom: PhantomData<S>,
|
|
}
|
|
|
|
impl<S> TestcaseScore<S> for MaxTimeFavFactor<S>
|
|
where
|
|
S: HasCorpus + HasMetadata,
|
|
S::Input: HasLen,
|
|
{
|
|
fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
|
|
// TODO maybe enforce entry.exec_time().is_some()
|
|
let execs_per_hour = 3600.0/entry.exec_time().expect("testcase.exec_time is needed for scheduler").as_secs_f64();
|
|
Ok(execs_per_hour)
|
|
}
|
|
}
|
|
|
|
pub type LenTimeMaximizerCorpusScheduler<CS> =
|
|
MinimizerScheduler<CS, MaxExecsLenFavFactor<<CS as UsesState>::State>, MapIndexesMetadata>;
|
|
|
|
pub type TimeStateMaximizerCorpusScheduler<CS> =
|
|
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>, FreeRTOSSystemStateMetadata>;
|
|
|
|
/// Multiply the testcase size with the execution time.
|
|
/// This favors small and quick testcases.
|
|
#[derive(Debug, Clone)]
|
|
pub struct MaxExecsLenFavFactor<S>
|
|
where
|
|
S: HasCorpus + HasMetadata,
|
|
S::Input: HasLen,
|
|
{
|
|
phantom: PhantomData<S>,
|
|
}
|
|
|
|
impl<S> TestcaseScore<S> for MaxExecsLenFavFactor<S>
|
|
where
|
|
S: HasCorpus + HasMetadata,
|
|
S::Input: HasLen,
|
|
{
|
|
fn compute(entry: &mut Testcase<S::Input>, state: &S) -> Result<f64, Error> {
|
|
let execs_per_hour = (3600.0/entry.exec_time().expect("testcase.exec_time is needed for scheduler").as_secs_f64());
|
|
let execs_times_length_per_hour = execs_per_hour*entry.cached_len()? as f64;
|
|
Ok(execs_times_length_per_hour)
|
|
}
|
|
}
|
|
|
|
//===================================================================
|
|
|
|
/// A Feedback reporting if the Input consists of strictly decreasing bytes.
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct SortedFeedback {
|
|
}
|
|
|
|
impl<S> Feedback<S> for SortedFeedback
|
|
where
|
|
S: UsesInput + HasClientPerfMonitor,
|
|
S::Input: HasTargetBytes,
|
|
{
|
|
#[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>,
|
|
{
|
|
let t = _input.target_bytes();
|
|
let tmp = t.as_slice();
|
|
if tmp.len()<32 {return Ok(false);}
|
|
let tmp = Vec::<u8>::from(&tmp[0..32]);
|
|
// tmp.reverse();
|
|
if tmp.is_sorted_by(|a,b| match a.partial_cmp(b).unwrap_or(Less) {
|
|
Less => Some(Greater),
|
|
Equal => Some(Greater),
|
|
Greater => Some(Less),
|
|
}) {return Ok(true)};
|
|
return Ok(false);
|
|
}
|
|
}
|
|
|
|
impl Named for SortedFeedback {
|
|
#[inline]
|
|
fn name(&self) -> &str {
|
|
"Sorted"
|
|
}
|
|
}
|
|
|
|
impl SortedFeedback {
|
|
/// Creates a new [`HitFeedback`]
|
|
#[must_use]
|
|
pub fn new() -> Self {
|
|
Self {}
|
|
}
|
|
}
|
|
|
|
impl Default for SortedFeedback {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
//===================================================================
|
|
/// A Feedback which expects a certain minimum execution time
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct ExecTimeReachedFeedback
|
|
{
|
|
target_time: u64,
|
|
}
|
|
|
|
impl<S> Feedback<S> for ExecTimeReachedFeedback
|
|
where
|
|
S: UsesInput + HasClientPerfMonitor,
|
|
{
|
|
#[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>,
|
|
{
|
|
let observer = observers.match_name::<QemuClockObserver>("clock")
|
|
.expect("QemuClockObserver not found");
|
|
Ok(observer.last_runtime() >= self.target_time)
|
|
}
|
|
}
|
|
|
|
impl Named for ExecTimeReachedFeedback
|
|
{
|
|
#[inline]
|
|
fn name(&self) -> &str {
|
|
"ExecTimeReachedFeedback"
|
|
}
|
|
}
|
|
|
|
impl ExecTimeReachedFeedback
|
|
where
|
|
{
|
|
/// Creates a new [`ExecTimeReachedFeedback`]
|
|
#[must_use]
|
|
pub fn new(target_time : u64) -> Self {
|
|
Self {target_time: target_time}
|
|
}
|
|
}
|
|
|
|
pub static mut EXEC_TIME_COLLECTION : Vec<u32> = Vec::new();
|
|
|
|
/// A Noop Feedback which records a list of all execution times
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct ExecTimeCollectorFeedback
|
|
{
|
|
}
|
|
|
|
impl<S> Feedback<S> for ExecTimeCollectorFeedback
|
|
where
|
|
S: UsesInput + HasClientPerfMonitor,
|
|
{
|
|
#[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>,
|
|
{
|
|
let observer = observers.match_name::<QemuClockObserver>("clock")
|
|
.expect("QemuClockObserver not found");
|
|
unsafe { EXEC_TIME_COLLECTION.push(observer.last_runtime().try_into().unwrap()); }
|
|
Ok(false)
|
|
}
|
|
}
|
|
|
|
impl Named for ExecTimeCollectorFeedback
|
|
{
|
|
#[inline]
|
|
fn name(&self) -> &str {
|
|
"ExecTimeCollectorFeedback"
|
|
}
|
|
}
|
|
|
|
impl ExecTimeCollectorFeedback
|
|
where
|
|
{
|
|
/// Creates a new [`ExecTimeCollectorFeedback`]
|
|
#[must_use]
|
|
pub fn new() -> Self {
|
|
Self {}
|
|
}
|
|
}
|
|
|
|
/// Shared Metadata for a SysStateFeedback
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
pub struct ExecTimeCollectorFeedbackState
|
|
{
|
|
collection: Vec<u32>,
|
|
}
|
|
impl Named for ExecTimeCollectorFeedbackState
|
|
{
|
|
#[inline]
|
|
fn name(&self) -> &str {
|
|
"ExecTimeCollectorFeedbackState"
|
|
}
|
|
}
|
|
|
|
//===================================================================
|
|
/// A Feedback which expects a certain minimum execution time
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
pub struct ExecTimeIncFeedback
|
|
{
|
|
longest_time: u64,
|
|
last_is_longest: bool
|
|
}
|
|
|
|
impl<S> Feedback<S> for ExecTimeIncFeedback
|
|
where
|
|
S: UsesInput + HasClientPerfMonitor,
|
|
{
|
|
#[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>,
|
|
{
|
|
let observer = observers.match_name::<QemuClockObserver>("clocktime")
|
|
.expect("QemuClockObserver not found");
|
|
if observer.last_runtime() > self.longest_time {
|
|
self.longest_time = observer.last_runtime();
|
|
}
|
|
self.last_is_longest = observer.last_runtime() > self.longest_time;
|
|
Ok(observer.last_runtime() > self.longest_time)
|
|
}
|
|
fn append_metadata(
|
|
&mut self,
|
|
_state: &mut S,
|
|
testcase: &mut Testcase<<S as UsesInput>::Input>,
|
|
) -> Result<(), Error> {
|
|
if self.last_is_longest {
|
|
let mim : Option<&mut MapIndexesMetadata>= testcase.metadata_mut().get_mut();
|
|
// pretend that the longest input alone excercises some non-existing edge, to keep it relevant
|
|
mim.unwrap().list.push(usize::MAX);
|
|
};
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Named for ExecTimeIncFeedback
|
|
{
|
|
#[inline]
|
|
fn name(&self) -> &str {
|
|
"ExecTimeReachedFeedback"
|
|
}
|
|
}
|
|
|
|
impl ExecTimeIncFeedback
|
|
where
|
|
{
|
|
/// Creates a new [`ExecTimeReachedFeedback`]
|
|
#[must_use]
|
|
pub fn new() -> Self {
|
|
Self {longest_time: 0, last_is_longest: false}
|
|
}
|
|
} |