save last post interrupt edge in app

This commit is contained in:
Alwin Berger 2022-04-06 21:03:21 +02:00
parent e8b24b0c7a
commit 47a4bc19d4
5 changed files with 89 additions and 6 deletions

View File

@ -269,6 +269,16 @@ fn fuzz(
.expect("Symbol xPortPendSVHandler not found"); .expect("Symbol xPortPendSVHandler not found");
let svh = virt2phys(svh,&elf.goblin()); let svh = virt2phys(svh,&elf.goblin());
println!("PendHandle at {:#x}", svh); println!("PendHandle at {:#x}", svh);
let app_code_start = elf
.resolve_symbol("__APP_CODE_START__", 0)
.expect("Symbol __APP_CODE_START__ not found");
let app_code_start = virt2phys(app_code_start,&elf.goblin());
let app_code_end = elf
.resolve_symbol("__APP_CODE_END__", 0)
.expect("Symbol __APP_CODE_END__ not found");
let app_code_end = virt2phys(app_code_end,&elf.goblin());
let app_range = app_code_start..app_code_end;
println!("App Code {:x}-{:x}",app_code_start,app_code_end);
@ -349,7 +359,7 @@ fn fuzz(
&mut harness, &mut harness,
&emu, &emu,
tuple_list!( tuple_list!(
QemuEdgeCoverageHelper::new(), QemuEdgeCoverageHelper::with_app_range(app_range),
// QemuCmpLogHelper::new(), // QemuCmpLogHelper::new(),
// QemuAsanHelper::new(), // QemuAsanHelper::new(),
QemuSysSnapshotHelper::new(), QemuSysSnapshotHelper::new(),

View File

@ -1,3 +1,4 @@
use libafl_qemu::edges::QemuEdgesMapMetadata;
use crate::sysstate::RawFreeRTOSSystemState; use crate::sysstate::RawFreeRTOSSystemState;
use crate::sysstate::CURRENT_SYSSTATE_VEC; use crate::sysstate::CURRENT_SYSSTATE_VEC;
use crate::sysstate::NUM_PRIOS; use crate::sysstate::NUM_PRIOS;
@ -11,6 +12,7 @@ use libafl_qemu::{
emu::Emulator, emu::Emulator,
executor::QemuExecutor, executor::QemuExecutor,
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
edges::SAVED_JUMP,
}; };
//============================= Struct definitions //============================= Struct definitions
@ -78,7 +80,7 @@ where
pub fn exec_syscall_hook<I, QT, S>( pub fn exec_syscall_hook<I, QT, S>(
emulator: &Emulator, emulator: &Emulator,
helpers: &mut QT, helpers: &mut QT,
_state: &mut S, state: &mut S,
pc: u64, pc: u64,
) )
where where
@ -99,6 +101,25 @@ where
let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr); let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr);
sysstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr); sysstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
unsafe {
match SAVED_JUMP {
Some(s) => {
let meta = state
.metadata_mut()
.get::<QemuEdgesMapMetadata>()
.unwrap();
for (k,v) in meta.map.iter() {
if *v==s {
// println!("Jump Saved {:x}",k.1);
sysstate.last_pc = Some(k.1); /* Currently save APP entry points */
break;
}
}
},
None => (),
}
}
// println!("{:?}",std::str::from_utf8(&current_tcb.pcTaskName)); // println!("{:?}",std::str::from_utf8(&current_tcb.pcTaskName));
for i in 0..NUM_PRIOS { for i in 0..NUM_PRIOS {

View File

@ -27,6 +27,7 @@ pub struct RawFreeRTOSSystemState {
prio_ready_lists: [freertos::List_t; NUM_PRIOS], prio_ready_lists: [freertos::List_t; NUM_PRIOS],
dumping_ground: HashMap<u32,freertos::rtos_struct>, dumping_ground: HashMap<u32,freertos::rtos_struct>,
input_counter: u32, input_counter: u32,
last_pc: Option<u64>,
} }
/// List of system state dumps from QemuHelpers /// List of system state dumps from QemuHelpers
static mut CURRENT_SYSSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![]; static mut CURRENT_SYSSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![];
@ -88,13 +89,15 @@ impl RefinedTCB {
pub struct RefinedFreeRTOSSystemState { pub struct RefinedFreeRTOSSystemState {
start_tick: u64, start_tick: u64,
end_tick: u64, end_tick: u64,
last_pc: Option<u64>,
input_counter: u32, input_counter: u32,
current_task: RefinedTCB, current_task: RefinedTCB,
ready_list_after: Vec<RefinedTCB>, ready_list_after: Vec<RefinedTCB>,
} }
impl PartialEq for RefinedFreeRTOSSystemState { impl PartialEq for RefinedFreeRTOSSystemState {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.current_task == other.current_task && self.ready_list_after == other.ready_list_after self.current_task == other.current_task && self.ready_list_after == other.ready_list_after &&
self.last_pc == other.last_pc
} }
} }
@ -102,6 +105,7 @@ impl Hash for RefinedFreeRTOSSystemState {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.current_task.hash(state); self.current_task.hash(state);
self.ready_list_after.hash(state); self.ready_list_after.hash(state);
self.last_pc.hash(state);
} }
} }
impl RefinedFreeRTOSSystemState { impl RefinedFreeRTOSSystemState {

View File

@ -130,6 +130,7 @@ for mut i in input.drain(..) {
end_tick: i.qemu_tick, end_tick: i.qemu_tick,
ready_list_after: collector, ready_list_after: collector,
input_counter: i.input_counter, input_counter: i.input_counter,
last_pc: i.last_pc,
}); });
start_tick=i.qemu_tick; start_tick=i.qemu_tick;
} }

View File

@ -1,3 +1,4 @@
use std::ops::Range;
use hashbrown::{hash_map::Entry, HashMap}; use hashbrown::{hash_map::Entry, HashMap};
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata}; use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
pub use libafl_targets::{EDGES_MAP, EDGES_MAP_SIZE, MAX_EDGES_NUM}; pub use libafl_targets::{EDGES_MAP, EDGES_MAP_SIZE, MAX_EDGES_NUM};
@ -31,6 +32,7 @@ libafl::impl_serdeany!(QemuEdgesMapMetadata);
#[derive(Debug)] #[derive(Debug)]
pub struct QemuEdgeCoverageHelper { pub struct QemuEdgeCoverageHelper {
filter: QemuInstrumentationFilter, filter: QemuInstrumentationFilter,
app_range: Option<Range<u64>>,
} }
impl QemuEdgeCoverageHelper { impl QemuEdgeCoverageHelper {
@ -38,18 +40,37 @@ impl QemuEdgeCoverageHelper {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
filter: QemuInstrumentationFilter::None, filter: QemuInstrumentationFilter::None,
app_range: None,
} }
} }
#[must_use] #[must_use]
pub fn with_instrumentation_filter(filter: QemuInstrumentationFilter) -> Self { pub fn with_instrumentation_filter(filter: QemuInstrumentationFilter, app_range: Option<Range<u64>>) -> Self {
Self { filter } Self { filter, app_range }
}
#[must_use]
pub fn with_app_range(app_range: Range<u64>) -> Self {
Self { filter: QemuInstrumentationFilter::None, app_range: Some(app_range) }
} }
#[must_use] #[must_use]
pub fn must_instrument(&self, addr: u64) -> bool { pub fn must_instrument(&self, addr: u64) -> bool {
self.filter.allowed(addr) self.filter.allowed(addr)
} }
#[must_use]
pub fn must_save(&self, src: u64, dst: u64) -> bool {
match &self.app_range {
None => false,
Some(s) => {
// println!("must_save {} {:x} {:x}",s.contains(&src) != s.contains(&dst),src,dst);
// s.contains(&src) && !s.contains(&dst)
// println!("must_save {} {:x} {:x}",src==0&&dst!=0x9cc,src,dst);
src==0&&dst!=0x9cc
},
}
}
} }
impl Default for QemuEdgeCoverageHelper { impl Default for QemuEdgeCoverageHelper {
@ -70,7 +91,14 @@ where
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
executor.hook_edge_generation(gen_unique_edge_ids::<I, QT, S>); executor.hook_edge_generation(gen_unique_edge_ids::<I, QT, S>);
executor.emulator().set_exec_edge_hook(trace_edge_hitcount); match self.app_range {
None => executor.emulator().set_exec_edge_hook(trace_edge_hitcount),
Some(_) => executor.emulator().set_exec_edge_hook(trace_edge_hitcount_and_app_range),
}
}
fn pre_exec(&mut self, _emulator: &Emulator, _input: &I) {
unsafe { SAVED_JUMP=None; }
} }
} }
@ -83,6 +111,9 @@ fn hash_me(mut x: u64) -> u64 {
x x
} }
pub static mut MUST_SAVE: [bool; EDGES_MAP_SIZE] = [false; EDGES_MAP_SIZE];
pub static mut SAVED_JUMP: Option<u64> = None;
pub fn gen_unique_edge_ids<I, QT, S>( pub fn gen_unique_edge_ids<I, QT, S>(
_emulator: &Emulator, _emulator: &Emulator,
helpers: &mut QT, helpers: &mut QT,
@ -95,10 +126,12 @@ where
I: Input, I: Input,
QT: QemuHelperTuple<I, S>, QT: QemuHelperTuple<I, S>,
{ {
let mut must_save = false;
if let Some(h) = helpers.match_first_type::<QemuEdgeCoverageHelper>() { if let Some(h) = helpers.match_first_type::<QemuEdgeCoverageHelper>() {
if !h.must_instrument(src) && !h.must_instrument(dest) { if !h.must_instrument(src) && !h.must_instrument(dest) {
return None; return None;
} }
must_save = h.must_save(src, dest);
} }
if state.metadata().get::<QemuEdgesMapMetadata>().is_none() { if state.metadata().get::<QemuEdgesMapMetadata>().is_none() {
state.add_metadata(QemuEdgesMapMetadata::new()); state.add_metadata(QemuEdgesMapMetadata::new());
@ -114,6 +147,9 @@ where
let nxt = (id as usize + 1) & (EDGES_MAP_SIZE - 1); let nxt = (id as usize + 1) & (EDGES_MAP_SIZE - 1);
unsafe { unsafe {
MAX_EDGES_NUM = max(MAX_EDGES_NUM, nxt); MAX_EDGES_NUM = max(MAX_EDGES_NUM, nxt);
if must_save {
MUST_SAVE[id as usize] = true;
}
} }
Some(id) Some(id)
} }
@ -123,6 +159,9 @@ where
meta.current_id = (id + 1) & (EDGES_MAP_SIZE as u64 - 1); meta.current_id = (id + 1) & (EDGES_MAP_SIZE as u64 - 1);
unsafe { unsafe {
MAX_EDGES_NUM = meta.current_id as usize; MAX_EDGES_NUM = meta.current_id as usize;
if must_save {
MUST_SAVE[id as usize] = true;
}
} }
Some(id as u64) Some(id as u64)
} }
@ -148,6 +187,14 @@ where
Some(hash_me(src) ^ hash_me(dest)) Some(hash_me(src) ^ hash_me(dest))
} }
pub extern "C" fn trace_edge_hitcount_and_app_range(id: u64) {
unsafe {
if MUST_SAVE[id as usize] { SAVED_JUMP=Some(id); }
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1);
}
}
pub extern "C" fn trace_edge_hitcount(id: u64) { pub extern "C" fn trace_edge_hitcount(id: u64) {
unsafe { unsafe {
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1); EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1);