253 lines
10 KiB
Rust
253 lines
10 KiB
Rust
use crate::fuzzer::DO_NUM_INTERRUPT;
|
|
use crate::systemstate::mutation::Mutator;
|
|
use crate::systemstate::graph::SysGraphMetadata;
|
|
use crate::systemstate::graph::SysGraphNode;
|
|
// use crate::systemstate::IRQ_INPUT_OFFSET;
|
|
// use crate::systemstate::IRQ_INPUT_BYTES_NUMBER;
|
|
use crate::systemstate::graph::SysGraphFeedbackState;
|
|
use libafl::inputs::HasBytesVec;
|
|
use libafl::bolts::rands::RandomSeed;
|
|
use libafl::bolts::rands::StdRand;
|
|
use libafl::prelude::Testcase;
|
|
use libafl::mutators::MutationResult;
|
|
use libafl::prelude::Corpus;
|
|
use libafl::prelude::UsesInput;
|
|
use core::marker::PhantomData;
|
|
use std::cmp::max;
|
|
use std::cmp::min;
|
|
use libafl::state::HasCorpus;
|
|
use libafl::state::HasSolutions;
|
|
use libafl::state::HasRand;
|
|
|
|
use libafl::bolts::tuples::MatchName;
|
|
use libafl::bolts::tuples::Named;
|
|
use libafl::Error;
|
|
use libafl::{inputs::Input, state::HasMetadata};
|
|
|
|
use super::FreeRTOSSystemStateMetadata;
|
|
use super::RefinedFreeRTOSSystemState;
|
|
|
|
use libafl::bolts::rands::Rand;
|
|
|
|
pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4);
|
|
|
|
//=============================== Interrupt
|
|
/// Sets up the interrupt to a random block in the trace. Works for both state and graph metadata
|
|
pub struct InterruptShifterMutator<S>
|
|
where
|
|
S: UsesInput,
|
|
{
|
|
phantom: PhantomData<S>,
|
|
}
|
|
impl<S> InterruptShifterMutator<S>
|
|
where
|
|
S: UsesInput,
|
|
{
|
|
pub fn new() -> Self {
|
|
InterruptShifterMutator{phantom: PhantomData}
|
|
}
|
|
}
|
|
impl<S> Mutator<S> for InterruptShifterMutator<S>
|
|
where
|
|
S: UsesInput + HasRand + HasMetadata + HasCorpus,
|
|
S::Input: HasBytesVec,
|
|
{
|
|
fn mutate(
|
|
&mut self,
|
|
state: &mut S,
|
|
_input: &mut Testcase<S::Input>,
|
|
_stage_idx: i32
|
|
) -> Result<MutationResult, Error>
|
|
{
|
|
// need our own random generator, because borrowing rules
|
|
let mut myrand = StdRand::new();
|
|
let mut target_bytes : Vec<u8> = vec![];
|
|
{
|
|
let input = _input.input_mut().as_ref().unwrap();
|
|
let tmp = &mut state.rand_mut();
|
|
myrand.set_seed(tmp.next());
|
|
target_bytes = input.bytes().to_vec();
|
|
}
|
|
|
|
// produce a slice of absolute interrupt times
|
|
let mut interrupt_offsets : [u32; 32] = [0u32; 32];
|
|
let mut num_interrupts : usize = 0;
|
|
{
|
|
let mut start_tick : u32 = 0;
|
|
for i in 0..DO_NUM_INTERRUPT {
|
|
let mut t : [u8; 4] = [0,0,0,0];
|
|
if target_bytes.len() > (i+1)*4 {
|
|
for j in 0 as usize..4 as usize {
|
|
t[j]=target_bytes[i*4+j];
|
|
}
|
|
if i == 0 {
|
|
start_tick = u32::from_le_bytes(t);
|
|
} else {
|
|
start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t)));
|
|
}
|
|
interrupt_offsets[i] = start_tick;
|
|
num_interrupts = i+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
println!("Vor Mutator: {:?}", interrupt_offsets[0..num_interrupts].to_vec());
|
|
// let num_i = min(target_bytes.len() / 4, DO_NUM_INTERRUPT);
|
|
let mut suffix = target_bytes.split_off(4 * num_interrupts);
|
|
let mut prefix : Vec<[u8; 4]> = vec![];
|
|
// let mut suffix : Vec<u8> = vec![];
|
|
// #[cfg(feature = "feed_systemtrace")]
|
|
{
|
|
let tmp = _input.metadata().get::<FreeRTOSSystemStateMetadata>();
|
|
if tmp.is_none() {
|
|
return Ok(MutationResult::Skipped);
|
|
}
|
|
let trace = tmp.expect("FreeRTOSSystemStateMetadata not found");
|
|
|
|
// calculate hits and identify snippets
|
|
let mut last_m = false;
|
|
let mut marks : Vec<(&RefinedFreeRTOSSystemState, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
|
|
for i in 0..trace.inner.len() {
|
|
let curr = &trace.inner[i];
|
|
let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64)));
|
|
if m {
|
|
marks.push((curr, i, 1));
|
|
println!("1: {}",curr.current_task.task_name);
|
|
} else if last_m {
|
|
marks.push((curr, i, 2));
|
|
println!("2: {}",curr.current_task.task_name);
|
|
} else {
|
|
marks.push((curr, i, 0));
|
|
}
|
|
last_m = m;
|
|
}
|
|
for i in 0..num_interrupts {
|
|
// bounds based on minimum inter-arrival time
|
|
let mut lb = 0;
|
|
let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32");
|
|
if i > 0 {
|
|
lb = interrupt_offsets[i-1]+MINIMUM_INTER_ARRIVAL_TIME;
|
|
}
|
|
if i < num_interrupts-1 {
|
|
ub = interrupt_offsets[i+1]-MINIMUM_INTER_ARRIVAL_TIME;
|
|
}
|
|
// get old hit and handler
|
|
let old_hit = marks.iter().filter(
|
|
|x| x.0.start_tick < (interrupt_offsets[i] as u64) && (interrupt_offsets[i] as u64) < x.0.end_tick
|
|
).next();
|
|
let old_handler = match old_hit {
|
|
Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 {
|
|
Some(marks[s.1+1])
|
|
} else {None},
|
|
None => None
|
|
};
|
|
// find reachable alternatives
|
|
let alternatives : Vec<_> = marks.iter().filter(|x|
|
|
(
|
|
x.0.start_tick < (lb as u64) && (lb as u64) < x.0.end_tick
|
|
|| x.0.start_tick < (ub as u64) && (ub as u64) < x.0.end_tick )
|
|
).collect();
|
|
// in cases there are no alternatives
|
|
if alternatives.len() == 0 {
|
|
if old_hit.is_none() {
|
|
// choose something random
|
|
let untouched : Vec<_> = marks.iter().filter(
|
|
|x| x.2 == 0
|
|
).collect();
|
|
let tmp = interrupt_offsets[i];
|
|
let choice = myrand.choose(untouched);
|
|
interrupt_offsets[i] = myrand.between(choice.0.start_tick, choice.0.end_tick)
|
|
.try_into().expect("tick > u32");
|
|
// println!("no alternatives, choose random i: {} {} -> {}",i,tmp,interrupt_offsets[i]);
|
|
continue;
|
|
} else {
|
|
// do nothing
|
|
// println!("no alternatives, do nothing i: {} {}",i,interrupt_offsets[i]);
|
|
continue;
|
|
}
|
|
}
|
|
let replacement = myrand.choose(alternatives);
|
|
if (old_hit.map_or(false, |x| x == replacement)) {
|
|
// use the old value
|
|
// println!("chose old value, do nothing i: {} {}",i,interrupt_offsets[i]);
|
|
continue;
|
|
} else {
|
|
let extra = if (old_hit.map_or(false, |x| x.1 < replacement.1)) {
|
|
// move futher back, respect old_handler
|
|
old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick)
|
|
} else { 0 };
|
|
let tmp = interrupt_offsets[i];
|
|
interrupt_offsets[i] = (myrand.between(replacement.0.start_tick,
|
|
replacement.0.end_tick) + extra).try_into().expect("ticks > u32");
|
|
// println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
|
|
}
|
|
}
|
|
// println!("Mutator: {:?}", interrupt_offsets[0..num_interrupts].to_vec());
|
|
let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
|
|
numbers.sort();
|
|
let mut start : u32 = 0;
|
|
for i in 0..numbers.len() {
|
|
let tmp = numbers[i];
|
|
numbers[i] = numbers[i]-start;
|
|
start = tmp;
|
|
}
|
|
for i in 0..numbers.len() {
|
|
prefix.push(u32::to_le_bytes(numbers[i]));
|
|
}
|
|
}
|
|
// #[cfg(feature = "sched_state")]
|
|
// {
|
|
// let feedbackstate = state
|
|
// .feedback_states()
|
|
// .match_name::<SysGraphFeedbackState>("SysMap")
|
|
// .unwrap();
|
|
// let g = &feedbackstate.graph;
|
|
// let tmp = state.metadata().get::<SysGraphMetadata>();
|
|
// if tmp.is_none() { // if there are no metadata it was probably not interesting anyways
|
|
// return Ok(MutationResult::Skipped);
|
|
// }
|
|
// let trace = tmp.expect("SysGraphMetadata not found");
|
|
// let target_block : &SysGraphNode = &g[*myrand.choose(trace.inner.iter())];
|
|
// target_tick = match target_block.variants.iter().find(|x| &x.input == target_bytes) {
|
|
// Some(s) => myrand.between(s.start_tick,s.end_tick)-IRQ_INPUT_OFFSET as u64,
|
|
// None => myrand.between(target_block.variants[0].start_tick,target_block.variants[0].end_tick)-IRQ_INPUT_OFFSET as u64,
|
|
// };
|
|
|
|
// }
|
|
|
|
// calculate ranges, alternative hits
|
|
// move snippets
|
|
|
|
let mut n = [prefix.concat(), suffix].concat();
|
|
let input = _input.input_mut().as_mut().unwrap();
|
|
input.bytes_mut().clear();
|
|
input.bytes_mut().append(&mut n);
|
|
return Ok(MutationResult::Mutated);
|
|
// if target_bytes.len() > IRQ_INPUT_BYTES_NUMBER as usize && IRQ_INPUT_BYTES_NUMBER > 0 {
|
|
// for i in 0..IRQ_INPUT_BYTES_NUMBER as usize {
|
|
// target_bytes[i] = u64::to_le_bytes(target_tick)[i];
|
|
// }
|
|
// return Ok(MutationResult::Mutated);
|
|
// } else {
|
|
// return Ok(MutationResult::Skipped);
|
|
// }
|
|
}
|
|
|
|
fn post_exec(
|
|
&mut self,
|
|
_state: &mut S,
|
|
_stage_idx: i32,
|
|
_corpus_idx: Option<usize>
|
|
) -> Result<(), Error> {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<S> Named for InterruptShifterMutator<S>
|
|
where
|
|
S: UsesInput,
|
|
{
|
|
fn name(&self) -> &str {
|
|
"InterruptShifterMutator"
|
|
}
|
|
} |