stg try_force_new_branches
This commit is contained in:
parent
810ec36115
commit
47724ad1c3
@ -13,9 +13,12 @@ use libafl::{
|
|||||||
common::{HasMetadata, HasNamedMetadata}, corpus::{self, Corpus}, 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}, 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
|
||||||
};
|
};
|
||||||
use libafl::prelude::State;
|
use libafl::prelude::State;
|
||||||
|
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 super::stg::{STGEdge, STGNode};
|
||||||
|
|
||||||
pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
|
pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
|
||||||
// one isn per 2**4 ns
|
// one isn per 2**4 ns
|
||||||
// virtual insn/sec 62500000 = 1/16 GHz
|
// virtual insn/sec 62500000 = 1/16 GHz
|
||||||
@ -53,6 +56,43 @@ pub fn input_bytes_to_interrupt_times(buf: &[u8]) -> Vec<u32> {
|
|||||||
|
|
||||||
//======================= Custom mutator
|
//======================= Custom mutator
|
||||||
|
|
||||||
|
fn is_interrupt_handler(graph: &DiGraph<STGNode, STGEdge>, node: NodeIndex) -> bool {
|
||||||
|
graph.edges_directed(node as NodeIndex, petgraph::Direction::Incoming).any(|x| x.weight().event == CaptureEvent::ISRStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_interrupt_handler_non_systick(graph: &DiGraph<STGNode, STGEdge>, node: NodeIndex) -> bool {
|
||||||
|
graph.edges_directed(node as NodeIndex, petgraph::Direction::Outgoing).any(|x| x.weight().event == CaptureEvent::ISRStart && x.weight().name!="xPortSysTickHandler")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_candidate_for_new_branches(graph: &DiGraph<STGNode, STGEdge>, node: NodeIndex) -> bool {
|
||||||
|
!has_interrupt_handler_non_systick(graph, node) && !is_interrupt_handler(graph, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: thic can be much more efficient, if the graph stored snapshots of the state and input progress was tracked
|
||||||
|
/// Determines if a given node in the state transition graph (STG) is a candidate for introducing new branches.
|
||||||
|
pub fn try_force_new_branches(interrupt_ticks : &[u32], fbs: &STGFeedbackState, meta: &STGNodeMetadata) -> Option<Vec<u32>> {
|
||||||
|
let mut new = false;
|
||||||
|
let mut new_interrupt_times = Vec::new();
|
||||||
|
for (num,&interrupt_time) in interrupt_ticks.iter().enumerate() {
|
||||||
|
let lower_bound = interrupt_time + unsafe{MINIMUM_INTER_ARRIVAL_TIME};
|
||||||
|
let next = if interrupt_ticks.len()>num {interrupt_ticks[num+1]} else {u32::MAX};
|
||||||
|
for exec_interval in meta.intervals.iter().filter(|x| x.start_tick >= lower_bound as u64 && x.start_tick < next as u64) {
|
||||||
|
if !(exec_interval.start_capture.0==CaptureEvent::ISRStart) { // shortcut to skip interrupt handers without node lookup
|
||||||
|
let node_index = fbs.state_abb_hash_index.get(&exec_interval.get_hash_index()).unwrap();
|
||||||
|
if !has_interrupt_handler_non_systick(&fbs.graph, node_index.clone()) {
|
||||||
|
new_interrupt_times.push(lower_bound);
|
||||||
|
new_interrupt_times.append(interrupt_ticks[num+2..].to_vec().as_mut());
|
||||||
|
new=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if new {break;}
|
||||||
|
new_interrupt_times.push(interrupt_time);
|
||||||
|
}
|
||||||
|
if new {Some(new_interrupt_times)} else {None}
|
||||||
|
}
|
||||||
|
|
||||||
/// The default mutational stage
|
/// The default mutational stage
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct InterruptShiftStage<E, EM, Z> {
|
pub struct InterruptShiftStage<E, EM, Z> {
|
||||||
@ -130,34 +170,45 @@ where
|
|||||||
prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick as usize, u32::MAX as usize)).try_into().expect("ticks > u32")));
|
prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick as usize, u32::MAX as usize)).try_into().expect("ticks > u32")));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// let choice = myrand.between(1,100);
|
let choice = myrand.between(1,100);
|
||||||
// if choice <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts
|
if choice <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts
|
||||||
// do_rerun = true;
|
do_rerun = true;
|
||||||
// // let metadata = state.metadata_map();
|
// let metadata = state.metadata_map();
|
||||||
// let hist = metadata.get::<IcHist>().unwrap();
|
let hist = metadata.get::<IcHist>().unwrap();
|
||||||
// let maxtick : u64 = hist.1.0;
|
let maxtick : u64 = hist.1.0;
|
||||||
// // let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
|
// let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
|
||||||
// let mut numbers : Vec<u32> = vec![];
|
let mut numbers : Vec<u32> = vec![];
|
||||||
// for i in 0..num_interrupts {
|
for i in 0..num_interrupts {
|
||||||
// prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32")));
|
prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64) as usize).try_into().expect("ticks > u32")));
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases
|
else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases
|
||||||
// let feedbackstate = match state
|
let feedbackstate = match state
|
||||||
// .named_metadata_map_mut()
|
.named_metadata_map()
|
||||||
// .get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
.get::<STGFeedbackState>("stgfeedbackstate") {
|
||||||
// Some(s) => s,
|
Some(s) => s,
|
||||||
// None => {
|
None => {
|
||||||
// panic!("STGfeedbackstate not visible")
|
panic!("STGfeedbackstate not visible")
|
||||||
// }
|
}
|
||||||
// };
|
};
|
||||||
// let tmp = _input.metadata_map().get::<STGNodeMetadata>();
|
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() {
|
||||||
|
if let Some(t) = try_force_new_branches(&interrupt_offsets, feedbackstate, meta) {
|
||||||
|
do_rerun = true;
|
||||||
|
for i in 0..t.len() {
|
||||||
|
if i<num_interrupts {
|
||||||
|
interrupt_offsets[i]=t[i];
|
||||||
|
} else {break;}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// let tmp = current_case.metadata_map().get::<STGNodeMetadata>();
|
||||||
// if tmp.is_some() {
|
// if tmp.is_some() {
|
||||||
// let trace = tmp.expect("STGNodeMetadata not found");
|
// let trace = tmp.expect("STGNodeMetadata not found");
|
||||||
// let mut node_indices = vec![];
|
// let mut node_indices = vec![];
|
||||||
// for i in (0..trace.intervals.len()).into_iter() {
|
// for i in (0..trace.intervals.len()).into_iter() {
|
||||||
// if let Some(abb) = &trace.intervals[i].abb {
|
// if let Some(abb) = &trace.intervals[i].abb {
|
||||||
// if let Some(idx) = feedbackstate.state_abb_hash_index.get(&(abb.get_hash(), trace.intervals[i].start_state)) {
|
// if let Some(idx) = feedbackstate.state_abb_hash_index.get(&(trace.intervals[i].start_state,abb.get_hash())) {
|
||||||
// node_indices.push(Some(idx));
|
// node_indices.push(Some(idx));
|
||||||
// continue;
|
// continue;
|
||||||
// }
|
// }
|
||||||
@ -190,18 +241,17 @@ where
|
|||||||
// let not_yet_hit : Vec<_> = alternatives.iter().filter(
|
// let not_yet_hit : Vec<_> = alternatives.iter().filter(
|
||||||
// |x| feedbackstate.graph.edges_directed(*node_indices[**x].unwrap(), petgraph::Direction::Outgoing).any(|y| y.weight().event != CaptureEvent::ISRStart)).collect();
|
// |x| feedbackstate.graph.edges_directed(*node_indices[**x].unwrap(), petgraph::Direction::Outgoing).any(|y| y.weight().event != CaptureEvent::ISRStart)).collect();
|
||||||
// if not_yet_hit.len() > 0 {
|
// if not_yet_hit.len() > 0 {
|
||||||
// let replacement = &trace.intervals[*myrand.choose(not_yet_hit)];
|
// let replacement = &trace.intervals[*myrand.choose(not_yet_hit).unwrap()];
|
||||||
// interrupt_offsets[i] = (myrand.between(replacement.start_tick,
|
// interrupt_offsets[i] = (myrand.between(replacement.start_tick as usize,
|
||||||
// replacement.end_tick)).try_into().expect("ticks > u32");
|
// replacement.end_tick as usize)).try_into().expect("ticks > u32");
|
||||||
// // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
|
// // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
|
||||||
// do_rerun = true;
|
// do_rerun = true;
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
}
|
||||||
// else { // old version of the alternative search
|
else { // old version of the alternative search
|
||||||
{
|
|
||||||
let tmp = current_case.metadata_map().get::<STGNodeMetadata>();
|
let tmp = current_case.metadata_map().get::<STGNodeMetadata>();
|
||||||
if tmp.is_some() {
|
if tmp.is_some() {
|
||||||
let trace = tmp.expect("STGNodeMetadata not found");
|
let trace = tmp.expect("STGNodeMetadata not found");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user