WIP: input snippet mutation
This commit is contained in:
parent
3b6cd3bc45
commit
de9c0a6d1e
@ -5,10 +5,9 @@ use core::marker::PhantomData;
|
|||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use libafl_bolts::rands::{
|
use libafl_bolts::{rands::{
|
||||||
StdRand, random_seed,
|
random_seed, Rand, StdRand
|
||||||
Rand
|
}, Named};
|
||||||
};
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
common::{HasMetadata, HasNamedMetadata}, corpus::{self, Corpus}, events::{Event, EventFirer, LogSeverity}, fuzzer::Evaluator, inputs::{HasMutatorBytes, HasTargetBytes, Input, MultipartInput}, mark_feature_time, prelude::{new_hash_feedback, CorpusId, MutationResult, Mutator, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error
|
common::{HasMetadata, HasNamedMetadata}, corpus::{self, Corpus}, events::{Event, EventFirer, LogSeverity}, fuzzer::Evaluator, inputs::{HasMutatorBytes, HasTargetBytes, Input, MultipartInput}, mark_feature_time, prelude::{new_hash_feedback, CorpusId, MutationResult, Mutator, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error
|
||||||
};
|
};
|
||||||
@ -16,6 +15,7 @@ use libafl::prelude::State;
|
|||||||
use petgraph::{graph::NodeIndex, graph::{self, DiGraph}};
|
use petgraph::{graph::NodeIndex, graph::{self, DiGraph}};
|
||||||
use crate::{time::clock::{IcHist, QEMU_ISNS_PER_USEC}, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT, MAX_NUM_INTERRUPT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, CaptureEvent, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}};
|
use crate::{time::clock::{IcHist, QEMU_ISNS_PER_USEC}, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT, MAX_NUM_INTERRUPT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, CaptureEvent, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}};
|
||||||
use libafl::state::HasCurrentTestcase;
|
use libafl::state::HasCurrentTestcase;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use super::stg::{STGEdge, STGNode};
|
use super::stg::{STGEdge, STGNode};
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ where
|
|||||||
.named_metadata_map()
|
.named_metadata_map()
|
||||||
.get::<STGFeedbackState>("stgfeedbackstate") {
|
.get::<STGFeedbackState>("stgfeedbackstate") {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => {
|
Option::None => {
|
||||||
panic!("STGfeedbackstate not visible")
|
panic!("STGfeedbackstate not visible")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -408,3 +408,94 @@ where
|
|||||||
{
|
{
|
||||||
type State = Z::State;
|
type State = Z::State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn try_worst_snippets(bytes : &[u8], fbs: &STGFeedbackState, meta: &STGNodeMetadata) -> Option<Vec<u8>> {
|
||||||
|
let mut new = false;
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for (num,interval) in meta.intervals.iter().enumerate() {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
if new {Some(ret)} else {None}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// The default mutational stage
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct STGSnippetStage<E, EM, Z> {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
phantom: PhantomData<(E, EM, Z)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, Z> STGSnippetStage<E, EM, Z>
|
||||||
|
where
|
||||||
|
E: UsesState<State = Z::State>,
|
||||||
|
EM: UsesState<State = Z::State>,
|
||||||
|
Z: Evaluator<E, EM>,
|
||||||
|
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
|
||||||
|
{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { phantom: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, Z, I> Stage<E, EM, Z> for STGSnippetStage<E, EM, Z>
|
||||||
|
where
|
||||||
|
E: UsesState<State = Z::State>,
|
||||||
|
EM: UsesState<State = Z::State>,
|
||||||
|
EM: EventFirer,
|
||||||
|
Z: Evaluator<E, EM>,
|
||||||
|
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
|
||||||
|
<Z::State as UsesInput>::Input: Input,
|
||||||
|
Z::State: UsesInput<Input = MultipartInput<I>>,
|
||||||
|
I: HasMutatorBytes + Default
|
||||||
|
{
|
||||||
|
fn perform(
|
||||||
|
&mut self,
|
||||||
|
fuzzer: &mut Z,
|
||||||
|
executor: &mut E,
|
||||||
|
state: &mut Self::State,
|
||||||
|
manager: &mut EM
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut myrand = StdRand::new();
|
||||||
|
myrand.set_seed(state.rand_mut().next());
|
||||||
|
|
||||||
|
let current_case = state.current_testcase()?;
|
||||||
|
let old_input = current_case.input().as_ref().unwrap();
|
||||||
|
let mut new_input = old_input.clone();
|
||||||
|
if let Some(bytes) = old_input.parts_by_name("bytes").next() {
|
||||||
|
let new_bytes = new_input.parts_by_name("bytes").next();
|
||||||
|
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() {
|
||||||
|
let feedbackstate = match state
|
||||||
|
.named_metadata_map()
|
||||||
|
.get::<STGFeedbackState>("stgfeedbackstate") {
|
||||||
|
Some(s) => s,
|
||||||
|
Option::None => {
|
||||||
|
panic!("STGfeedbackstate not visible")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result<bool, Error> {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, EM, Z> UsesState for STGSnippetStage<E, EM, Z>
|
||||||
|
where
|
||||||
|
E: UsesState<State = Z::State>,
|
||||||
|
EM: UsesState<State = Z::State>,
|
||||||
|
Z: Evaluator<E, EM>,
|
||||||
|
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
|
||||||
|
{
|
||||||
|
type State = Z::State;
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
use hashbrown::HashSet;
|
||||||
|
use libafl::inputs::Input;
|
||||||
/// Feedbacks organizing SystemStates as a graph
|
/// Feedbacks organizing SystemStates as a graph
|
||||||
use libafl::SerdeAny;
|
use libafl::SerdeAny;
|
||||||
use libafl_bolts::ownedref::OwnedMutSlice;
|
use libafl_bolts::ownedref::OwnedMutSlice;
|
||||||
@ -41,6 +43,8 @@ use std::{fs::OpenOptions, io::Write};
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use petgraph::visit::EdgeRef;
|
||||||
|
|
||||||
//============================= Data Structures
|
//============================= Data Structures
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash)]
|
||||||
@ -83,12 +87,12 @@ impl PartialEq for STGNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct STGEdge
|
pub struct STGEdge
|
||||||
{
|
{
|
||||||
// is_interrupt: bool,
|
|
||||||
pub event: CaptureEvent,
|
pub event: CaptureEvent,
|
||||||
pub name: String
|
pub name: String,
|
||||||
|
pub worst: Option<(u64, HashSet<u32>)>, // TODO: extract bytes from input
|
||||||
}
|
}
|
||||||
|
|
||||||
impl STGEdge {
|
impl STGEdge {
|
||||||
@ -116,6 +120,19 @@ impl STGEdge {
|
|||||||
});
|
});
|
||||||
short
|
short
|
||||||
}
|
}
|
||||||
|
pub fn is_abb_end(&self) -> bool {
|
||||||
|
match self.event {
|
||||||
|
CaptureEvent::APIStart | CaptureEvent::APIEnd | CaptureEvent::ISREnd | CaptureEvent::End => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for STGEdge {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.event.hash(state);
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shared Metadata for a systemstateFeedback
|
/// Shared Metadata for a systemstateFeedback
|
||||||
@ -345,6 +362,26 @@ fn get_generic_hash<H>(input: &H) -> u64
|
|||||||
s.finish()
|
s.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execinterval_to_abb_instances(trace: &Vec<ExecInterval>, read_trace: &Vec<HashSet<u32>>) -> HashMap<usize, (u64, HashSet<u32>)>{
|
||||||
|
let mut instance_time: HashMap<usize, (u64, HashSet<u32>)> = HashMap::new();
|
||||||
|
for (_i,interval) in trace.iter().enumerate() { // Iterate intervals
|
||||||
|
// sum up execution time and accesses per ABB
|
||||||
|
let temp = interval.abb.as_ref().map(|abb| abb.instance_id).unwrap_or(usize::MAX);
|
||||||
|
match instance_time.get_mut(&temp) {
|
||||||
|
Some(x) => {
|
||||||
|
x.0 += interval.get_exec_time();
|
||||||
|
x.1.extend(read_trace[_i].clone());
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
if temp != usize::MAX {
|
||||||
|
instance_time.insert(temp, (interval.get_exec_time(), read_trace[_i].clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return instance_time;
|
||||||
|
}
|
||||||
|
|
||||||
impl StgFeedback {
|
impl StgFeedback {
|
||||||
pub fn new(dump_name: Option<PathBuf>) -> Self {
|
pub fn new(dump_name: Option<PathBuf>) -> Self {
|
||||||
// Self {name: String::from("STGFeedback"), last_node_trace: None, last_edge_trace: None, last_intervals: None }
|
// Self {name: String::from("STGFeedback"), last_node_trace: None, last_edge_trace: None, last_intervals: None }
|
||||||
@ -362,11 +399,12 @@ impl StgFeedback {
|
|||||||
/// newly discovered node?
|
/// newly discovered node?
|
||||||
/// side effect:
|
/// side effect:
|
||||||
/// the graph gets new nodes and edge
|
/// the graph gets new nodes and edge
|
||||||
fn update_stg_interval(trace: &Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool, bool) {
|
fn update_stg_interval(trace: &Vec<ExecInterval>, read_trace: &Vec<HashSet<u32>>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool, bool) {
|
||||||
let mut return_node_trace = vec![fbs.entrypoint];
|
let mut return_node_trace = vec![fbs.entrypoint];
|
||||||
let mut return_edge_trace = vec![];
|
let mut return_edge_trace = vec![];
|
||||||
let mut interesting = false;
|
let mut interesting = false;
|
||||||
let mut updated = false;
|
let mut updated = false;
|
||||||
|
let mut instance_time = execinterval_to_abb_instances(trace, read_trace);
|
||||||
// add all missing state+abb combinations to the graph
|
// add all missing state+abb combinations to the graph
|
||||||
for (_i,interval) in trace.iter().enumerate() { // Iterate intervals
|
for (_i,interval) in trace.iter().enumerate() { // Iterate intervals
|
||||||
let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()};
|
let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()};
|
||||||
@ -388,8 +426,23 @@ impl StgFeedback {
|
|||||||
let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx);
|
let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx);
|
||||||
if let Some(e_) = e {
|
if let Some(e_) = e {
|
||||||
return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_));
|
return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_));
|
||||||
|
if let Some((time,accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) {
|
||||||
|
let ref_ = &mut fbs.graph.edge_weight_mut(e_.id()).unwrap().worst;
|
||||||
|
if ref_.is_some() {
|
||||||
|
let w = ref_.as_mut().unwrap();
|
||||||
|
if w.0 < *time {*w = (*time, accesses.clone())};
|
||||||
} else {
|
} else {
|
||||||
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, STGEdge{event: interval.start_capture.0, name: interval.start_capture.1.clone()});
|
*ref_ = Some((*time, accesses.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut e__ = STGEdge{event: interval.start_capture.0, name: interval.start_capture.1.clone(), worst: None};
|
||||||
|
if e__.is_abb_end() {
|
||||||
|
if let Some((time,accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) {
|
||||||
|
e__.worst = Some((*time, accesses.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, e__);
|
||||||
return_edge_trace.push(e_);
|
return_edge_trace.push(e_);
|
||||||
interesting |= INTEREST_EDGE;
|
interesting |= INTEREST_EDGE;
|
||||||
updated = true;
|
updated = true;
|
||||||
@ -405,7 +458,13 @@ impl StgFeedback {
|
|||||||
}
|
}
|
||||||
// every path terminates at the end
|
// every path terminates at the end
|
||||||
if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exitpoint) {
|
if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exitpoint) {
|
||||||
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exitpoint, STGEdge { event: CaptureEvent::End, name: String::from("End") });
|
let mut e__ = STGEdge { event: CaptureEvent::End, name: String::from("End"), worst: None};
|
||||||
|
if e__.is_abb_end() {
|
||||||
|
if let Some((time,accesses)) = instance_time.get_mut(&trace[trace.len()-1].abb.as_ref().unwrap().instance_id) {
|
||||||
|
e__.worst = Some((*time, accesses.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exitpoint, e__);
|
||||||
return_edge_trace.push(e_);
|
return_edge_trace.push(e_);
|
||||||
interesting |= INTEREST_EDGE;
|
interesting |= INTEREST_EDGE;
|
||||||
updated = true;
|
updated = true;
|
||||||
@ -453,14 +512,14 @@ where
|
|||||||
.named_metadata_map_mut()
|
.named_metadata_map_mut()
|
||||||
.get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
.get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => {
|
Option::None => {
|
||||||
let n=STGFeedbackState::default();
|
let n=STGFeedbackState::default();
|
||||||
state.named_metadata_map_mut().insert("stgfeedbackstate",n);
|
state.named_metadata_map_mut().insert("stgfeedbackstate",n);
|
||||||
state.named_metadata_map_mut().get_mut::<STGFeedbackState>("stgfeedbackstate").unwrap()
|
state.named_metadata_map_mut().get_mut::<STGFeedbackState>("stgfeedbackstate").unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_states, feedbackstate);
|
let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_reads, &observer.last_states, feedbackstate);
|
||||||
|
|
||||||
{
|
{
|
||||||
let h = get_generic_hash(&edgetrace);
|
let h = get_generic_hash(&edgetrace);
|
||||||
@ -557,7 +616,7 @@ where
|
|||||||
let edges = self.last_edge_trace.take();
|
let edges = self.last_edge_trace.take();
|
||||||
match nodes {
|
match nodes {
|
||||||
Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap())),
|
Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap())),
|
||||||
None => (),
|
Option::None => (),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user