refactor interrupt mutation

This commit is contained in:
Alwin Berger 2024-09-12 13:19:28 +02:00
parent 835d1e1a79
commit 8165fd7cfc

View File

@ -27,15 +27,15 @@ use super::stg::{STGEdge, STGNode};
pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u32> { pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u32> {
let len = buf.len(); let len = buf.len();
let mut start_tick : u32 = 0; let mut start_tick;
let mut ret = Vec::with_capacity(DO_NUM_INTERRUPT); let mut ret = Vec::with_capacity(min(DO_NUM_INTERRUPT, len/4));
for i in 0..DO_NUM_INTERRUPT { for i in 0..DO_NUM_INTERRUPT {
let mut t : [u8; 4] = [0,0,0,0]; let mut buf4b : [u8; 4] = [0,0,0,0];
if len > (i+1)*4 { if len >= (i+1)*4 {
for j in 0usize..4usize { for j in 0usize..4usize {
t[j]=buf[i*4+j]; buf4b[j]=buf[i*4+j];
} }
start_tick = u32::from_le_bytes(t); start_tick = u32::from_le_bytes(buf4b);
if start_tick < FIRST_INT {start_tick=0;} if start_tick < FIRST_INT {start_tick=0;}
ret.push(start_tick); ret.push(start_tick);
} else {break;} } else {break;}
@ -53,6 +53,14 @@ pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u3
ret ret
} }
pub fn interrupt_times_to_input_bytes(interrupt_times: &[u32]) -> Vec<u8> {
let mut ret = Vec::with_capacity(interrupt_times.len()*4);
for i in interrupt_times {
ret.extend(u32::to_le_bytes(*i));
}
ret
}
//======================= Custom mutator //======================= Custom mutator
@ -136,60 +144,46 @@ where
myrand.set_seed(state.rand_mut().next()); myrand.set_seed(state.rand_mut().next());
let mut loopcount = 0; let mut rerun_count = 0; // count how many times we rerun the executor
let mut loopbound = 50; // Try many times to find a mutation that is not already in the corpus
loop { let loopbound = 50;
for _ in 0..loopbound {
// Choose which isr to mutate
let interrup_config = match myrand.choose(&self.interrup_config) { let interrup_config = match myrand.choose(&self.interrup_config) {
Some(s) => s, Some(s) => s,
Option::None => return Ok(()) Option::None => return Ok(())
}; };
let name = format!("isr_{}_times", interrup_config.0); let name = format!("isr_{}_times", interrup_config.0);
// manager.log(state, LogSeverity::Info, format!("Mutation {}/{}", loopbound, loopcount))?; // manager.log(state, LogSeverity::Info, format!("Mutation {}/{}", loopbound, loopcount))?;
loopbound-=1;
let current_case = state.current_testcase()?;
let old_input = current_case.input().as_ref().unwrap();
let old_interrupt_times = old_input.parts_by_name(&name).next();
let mut new_input = old_input.clone();
let mut new_interrupt_times : &mut I = if new_input.parts_by_name(&name).next().is_some() { let curr_case = state.current_testcase()?;
let curr_input = curr_case.input().as_ref().unwrap();
let mut new_input = curr_input.clone();
let new_interrupt_part : &mut I = if new_input.parts_by_name(&name).next().is_some() {
new_input.parts_by_name_mut(&name).next().unwrap() new_input.parts_by_name_mut(&name).next().unwrap()
} else { } else {
new_input.add_part(String::from(&name), I::default()); new_input.parts_by_name_mut(&name).next().unwrap() new_input.add_part(String::from(&name), I::default()); new_input.parts_by_name_mut(&name).next().unwrap()
}.1; }.1;
let old_interrupt_times = input_bytes_to_interrupt_times(new_interrupt_part.bytes(), *interrup_config);
let mut new_interrupt_times = Vec::with_capacity(MAX_NUM_INTERRUPT);
let mut do_rerun = false; let mut do_rerun = false;
// if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time // if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time
{ {
// produce a slice of absolute interrupt times
let mut interrupt_offsets : [u32; MAX_NUM_INTERRUPT] = [u32::MAX; MAX_NUM_INTERRUPT];
let mut num_interrupts : usize = 0;
{
let t = input_bytes_to_interrupt_times(new_interrupt_times.bytes(), *interrup_config);
for i in 0..t.len() {interrupt_offsets[i]=t[i];}
num_interrupts=t.len();
}
interrupt_offsets.sort_unstable();
// println!("Vor Mutator: {:?}", interrupt_offsets[0..num_interrupts].to_vec());
let mut prefix : Vec<[u8; 4]> = vec![];
// let mut suffix : Vec<u8> = vec![];
#[cfg(feature = "mutate_stg")] #[cfg(feature = "mutate_stg")]
{ {
let metadata = state.metadata_map(); let metadata = state.metadata_map();
let hist = metadata.get::<IcHist>().unwrap(); let maxtick = {metadata.get::<IcHist>().unwrap().1.0};
let maxtick : u64 = hist.1.0; drop(new_interrupt_part.drain(..).collect::<Vec<u8>>());
drop(hist);
{ {
let choice = myrand.between(1,100); let choice = myrand.between(1,100);
if choice <= 25 || *interrupt_offsets.get(0).unwrap_or(&u32::MAX) as u64 > maxtick { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts if choice <= 25 || *old_interrupt_times.get(0).unwrap_or(&u32::MAX) as u64 > maxtick { // 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 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![]; for _ in 0..myrand.between(0,min(MAX_NUM_INTERRUPT, (maxtick as usize * 3) / (interrup_config.1 as usize * QEMU_ISNS_PER_USEC as usize * 2))) {
for i in 0..myrand.between(0,2*min(MAX_NUM_INTERRUPT, maxtick as usize / (interrup_config.1 as usize * QEMU_ISNS_PER_USEC as usize))) { new_interrupt_times.push(myrand.between(0, min(maxtick, u32::MAX as u64) as usize).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
@ -201,15 +195,10 @@ where
panic!("STGfeedbackstate not visible") panic!("STGfeedbackstate not visible")
} }
}; };
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() { if let Some(meta) = curr_case.metadata_map().get::<STGNodeMetadata>() {
if let Some(t) = try_force_new_branches(&interrupt_offsets, feedbackstate, meta, *interrup_config) { if let Some(t) = try_force_new_branches(&old_interrupt_times, feedbackstate, meta, *interrup_config) {
do_rerun = true; do_rerun = true;
for i in 0..t.len() { new_interrupt_times=t;
if i<num_interrupts {
interrupt_offsets[i]=t[i];
} else {break;}
}
} }
} }
// let tmp = current_case.metadata_map().get::<STGNodeMetadata>(); // let tmp = current_case.metadata_map().get::<STGNodeMetadata>();
@ -262,7 +251,8 @@ where
// } // }
} }
else { // old version of the alternative search else { // old version of the alternative search
let tmp = current_case.metadata_map().get::<STGNodeMetadata>(); new_interrupt_times = old_interrupt_times.clone();
let tmp = curr_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");
@ -271,7 +261,7 @@ where
let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
for i in 0..trace.intervals.len() { for i in 0..trace.intervals.len() {
let curr = &trace.intervals[i]; let curr = &trace.intervals[i];
let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64))); let m = old_interrupt_times.iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64)));
if m { if m {
marks.push((curr, i, 1)); marks.push((curr, i, 1));
// println!("1: {}",curr.current_task.0.task_name); // println!("1: {}",curr.current_task.0.task_name);
@ -283,22 +273,23 @@ where
} }
last_m = m; last_m = m;
} }
for i in 0..num_interrupts { for i in 0..old_interrupt_times.len() {
// bounds based on minimum inter-arrival time // bounds based on minimum inter-arrival time
let mut lb = FIRST_INT; let mut lb = FIRST_INT;
let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32"); let mut ub : u32 = trace.intervals[trace.intervals.len()-1].end_tick.try_into().expect("ticks > u32");
if i > 0 { if i > 0 {
lb = u32::saturating_add(interrupt_offsets[i-1], interrup_config.1 * QEMU_ISNS_PER_USEC); // use the new times, because changes to preceding timings are not accounted for yet
lb = u32::saturating_add(new_interrupt_times[i-1], interrup_config.1 * QEMU_ISNS_PER_USEC);
} }
if i < num_interrupts-1 { if i < old_interrupt_times.len()-1 {
ub = u32::saturating_sub(interrupt_offsets[i+1], interrup_config.1 * QEMU_ISNS_PER_USEC); ub = u32::saturating_sub(new_interrupt_times[i+1], interrup_config.1 * QEMU_ISNS_PER_USEC);
} }
// get old hit and handler // get old hit and handler
let old_hit = marks.iter().filter( 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 |x| x.0.start_tick < (old_interrupt_times[i] as u64) && (old_interrupt_times[i] as u64) < x.0.end_tick
).next(); ).next();
let old_handler = match old_hit { let old_handler = match old_hit {
Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 { Some(s) => if s.1 < old_interrupt_times.len()-1 && s.1 < marks.len()-1 {
Some(marks[s.1+1]) Some(marks[s.1+1])
} else {None}, } else {None},
None => None None => None
@ -318,9 +309,9 @@ where
|x| x.2 == 0 |x| x.2 == 0
).collect(); ).collect();
if untouched.len() > 0 { if untouched.len() > 0 {
let tmp = interrupt_offsets[i]; let tmp = old_interrupt_times[i];
let choice = myrand.choose(untouched).unwrap(); let choice = myrand.choose(untouched).unwrap();
interrupt_offsets[i] = myrand.between(choice.0.start_tick as usize, choice.0.end_tick as usize) new_interrupt_times[i] = myrand.between(choice.0.start_tick as usize, choice.0.end_tick as usize)
.try_into().expect("tick > u32"); .try_into().expect("tick > u32");
do_rerun = true; do_rerun = true;
} }
@ -342,15 +333,13 @@ where
// move futher back, respect old_handler // move futher back, respect old_handler
old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick) old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick)
} else { 0 }; } else { 0 };
let tmp = interrupt_offsets[i]; // let tmp = new_interrupt_times[i];
interrupt_offsets[i] = (myrand.between(replacement.0.start_tick as usize, new_interrupt_times[i] = (myrand.between(replacement.0.start_tick as usize,
replacement.0.end_tick as usize) + extra as usize).try_into().expect("ticks > u32"); replacement.0.end_tick as usize) + extra 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;
} }
} }
let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
numbers.sort();
// println!("Mutator: {:?}", numbers); // println!("Mutator: {:?}", numbers);
// let mut start : u32 = 0; // let mut start : u32 = 0;
// for i in 0..numbers.len() { // for i in 0..numbers.len() {
@ -358,9 +347,7 @@ where
// numbers[i] = numbers[i]-start; // numbers[i] = numbers[i]-start;
// start = tmp; // start = tmp;
// } // }
for i in 0..numbers.len() { new_interrupt_part.extend(&interrupt_times_to_input_bytes(&new_interrupt_times));
prefix.push(u32::to_le_bytes(numbers[i]));
}
} }
} }
} }
@ -370,23 +357,18 @@ where
if myrand.between(1,100) <= 25 { // we have no hint if interrupt times will change anything if myrand.between(1,100) <= 25 { // we have no hint if interrupt times will change anything
do_rerun = true; do_rerun = true;
let metadata = state.metadata_map(); let metadata = state.metadata_map();
let hist = metadata.get::<IcHist>().unwrap(); let maxtick = {metadata.get::<IcHist>().unwrap().1.0};
let maxtick : u64 = hist.1.0; new_interrupt_times = Vec::with_capacity(MAX_NUM_INTERRUPT);
// let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap(); for i in 0..myrand.between(0,min(MAX_NUM_INTERRUPT, (maxtick as usize * 3) / (interrup_config.1 as usize * QEMU_ISNS_PER_USEC as usize * 2))) {
let mut numbers : Vec<u32> = vec![]; new_interrupt_times.push(myrand.between(0, min(maxtick, u32::MAX as u64) as usize).try_into().expect("ticks > u32"));
for i in 0..num_interrupts {
prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick as usize, u32::MAX as usize)).try_into().expect("ticks > u32")));
} }
} }
} }
let _t= new_interrupt_times.drain(..).collect::<Vec<_>>(); new_interrupt_part.extend(&interrupt_times_to_input_bytes(&new_interrupt_times));
drop(_t);
new_interrupt_times.extend(&prefix.concat());
} }
drop(current_case); drop(curr_case);
// InterruptShifterMutator::mutate(&mut mymut, state, &mut input, 0)?;
if do_rerun { if do_rerun {
loopcount+=1; rerun_count+=1;
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, new_input)?; let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, new_input)?;
if corpus_idx.is_none() && loopbound<=0 { break;} if corpus_idx.is_none() && loopbound<=0 { break;}
} else {if loopbound<=0 {break;}} } else {if loopbound<=0 {break;}}