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
|
||||
};
|
||||
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 libafl::state::HasCurrentTestcase;
|
||||
|
||||
use super::stg::{STGEdge, STGNode};
|
||||
|
||||
pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
|
||||
// one isn per 2**4 ns
|
||||
// virtual insn/sec 62500000 = 1/16 GHz
|
||||
@ -53,6 +56,43 @@ pub fn input_bytes_to_interrupt_times(buf: &[u8]) -> Vec<u32> {
|
||||
|
||||
//======================= 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
|
||||
#[derive(Clone, Debug, Default)]
|
||||
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")));
|
||||
}
|
||||
} else {
|
||||
// let choice = myrand.between(1,100);
|
||||
// if choice <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts
|
||||
// do_rerun = true;
|
||||
// // let metadata = state.metadata_map();
|
||||
// let hist = metadata.get::<IcHist>().unwrap();
|
||||
// let maxtick : u64 = hist.1.0;
|
||||
// // let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
|
||||
// let mut numbers : Vec<u32> = vec![];
|
||||
// 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")));
|
||||
// }
|
||||
// }
|
||||
// else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases
|
||||
// let feedbackstate = match state
|
||||
// .named_metadata_map_mut()
|
||||
// .get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
||||
// Some(s) => s,
|
||||
// None => {
|
||||
// panic!("STGfeedbackstate not visible")
|
||||
// }
|
||||
// };
|
||||
// let tmp = _input.metadata_map().get::<STGNodeMetadata>();
|
||||
let choice = myrand.between(1,100);
|
||||
if choice <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts
|
||||
do_rerun = true;
|
||||
// let metadata = state.metadata_map();
|
||||
let hist = metadata.get::<IcHist>().unwrap();
|
||||
let maxtick : u64 = hist.1.0;
|
||||
// let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
|
||||
let mut numbers : Vec<u32> = vec![];
|
||||
for i in 0..num_interrupts {
|
||||
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
|
||||
let feedbackstate = match state
|
||||
.named_metadata_map()
|
||||
.get::<STGFeedbackState>("stgfeedbackstate") {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
panic!("STGfeedbackstate not visible")
|
||||
}
|
||||
};
|
||||
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() {
|
||||
// let trace = tmp.expect("STGNodeMetadata not found");
|
||||
// let mut node_indices = vec![];
|
||||
// for i in (0..trace.intervals.len()).into_iter() {
|
||||
// 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));
|
||||
// continue;
|
||||
// }
|
||||
@ -190,18 +241,17 @@ where
|
||||
// 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();
|
||||
// if not_yet_hit.len() > 0 {
|
||||
// let replacement = &trace.intervals[*myrand.choose(not_yet_hit)];
|
||||
// interrupt_offsets[i] = (myrand.between(replacement.start_tick,
|
||||
// replacement.end_tick)).try_into().expect("ticks > u32");
|
||||
// let replacement = &trace.intervals[*myrand.choose(not_yet_hit).unwrap()];
|
||||
// interrupt_offsets[i] = (myrand.between(replacement.start_tick as usize,
|
||||
// replacement.end_tick as usize)).try_into().expect("ticks > u32");
|
||||
// // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
|
||||
// do_rerun = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else { // old version of the alternative search
|
||||
{
|
||||
}
|
||||
else { // old version of the alternative search
|
||||
let tmp = current_case.metadata_map().get::<STGNodeMetadata>();
|
||||
if tmp.is_some() {
|
||||
let trace = tmp.expect("STGNodeMetadata not found");
|
||||
|
Loading…
x
Reference in New Issue
Block a user