WIP: store memory reads
This commit is contained in:
parent
05c17d3159
commit
3db17ceb98
@ -1,5 +1,6 @@
|
||||
use std::ops::Range;
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::HashSet;
|
||||
use libafl::prelude::ExitKind;
|
||||
use libafl::prelude::UsesInput;
|
||||
use libafl_qemu::elf::EasyElf;
|
||||
@ -9,6 +10,8 @@ use libafl_qemu::GuestPhysAddr;
|
||||
use libafl_qemu::QemuHooks;
|
||||
use libafl_qemu::Hook;
|
||||
use libafl_qemu::helpers::{QemuHelper, QemuHelperTuple};
|
||||
use libafl_qemu::sys::TCGTemp;
|
||||
use libafl_qemu::qemu::MemAccessInfo;
|
||||
|
||||
use crate::systemstate::RawFreeRTOSSystemState;
|
||||
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
|
||||
@ -98,6 +101,7 @@ pub struct QemuSystemStateHelper {
|
||||
// Address of interrupt routines
|
||||
isr_addrs: HashMap<GuestAddr, String>,
|
||||
isr_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
|
||||
input_mem: Range<GuestAddr>,
|
||||
tcb_addr: GuestAddr,
|
||||
ready_queues: GuestAddr,
|
||||
delay_queue: GuestAddr,
|
||||
@ -116,6 +120,7 @@ impl QemuSystemStateHelper {
|
||||
api_fn_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
|
||||
isr_addrs: HashMap<GuestAddr, String>,
|
||||
isr_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
|
||||
input_mem: Range<GuestAddr>,
|
||||
tcb_addr: GuestAddr,
|
||||
ready_queues: GuestAddr,
|
||||
delay_queue: GuestAddr,
|
||||
@ -131,6 +136,7 @@ impl QemuSystemStateHelper {
|
||||
api_fn_ranges,
|
||||
isr_addrs,
|
||||
isr_ranges,
|
||||
input_mem,
|
||||
tcb_addr: tcb_addr,
|
||||
ready_queues: ready_queues,
|
||||
delay_queue,
|
||||
@ -159,6 +165,8 @@ where
|
||||
_hooks.instruction(*wp, Hook::Function(exec_isr_hook::<QT, S>), false);
|
||||
}
|
||||
_hooks.jmps(Hook::Function(gen_jmp_is_syscall::<QT, S>), Hook::Function(trace_jmp::<QT, S>));
|
||||
_hooks.reads(Hook::Function(gen_read_is_input::<QT, S>), Hook::Empty,Hook::Empty,Hook::Empty,Hook::Empty,Hook::Function(trace_reads::<QT, S>));
|
||||
unsafe { INPUT_MEM = self.input_mem.clone() };
|
||||
}
|
||||
|
||||
// TODO: refactor duplicate code
|
||||
@ -173,6 +181,7 @@ where
|
||||
unsafe {
|
||||
let c = emulator.cpu_from_index(0);
|
||||
let pc = c.read_reg::<i32, u32>(15).unwrap();
|
||||
if CURRENT_SYSTEMSTATE_VEC.len() == 0 {return;}
|
||||
CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].edge = (pc,0);
|
||||
CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].capture_point = (CaptureEvent::End,"Breakpoint".to_string());
|
||||
}
|
||||
@ -297,6 +306,7 @@ fn trigger_collection(emulator: &libafl_qemu::Qemu, edge: (GuestAddr, GuestAddr)
|
||||
systemstate.prio_ready_lists[i] = read_freertos_list(&mut systemstate, emulator, target);
|
||||
}
|
||||
}
|
||||
systemstate.mem_reads = unsafe { MEM_READ.take().unwrap_or_default() };
|
||||
|
||||
|
||||
|
||||
@ -393,6 +403,51 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
//============================= Read Hooks
|
||||
pub fn gen_read_is_input<QT, S>(
|
||||
hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
_addr: *mut TCGTemp,
|
||||
_info: MemAccessInfo,
|
||||
) -> Option<u64>
|
||||
where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
if let Some(h) = hooks.helpers().match_first_type::<QemuSystemStateHelper>() {
|
||||
if h.app_range.contains(&pc) {
|
||||
// println!("gen_read {:x}", pc);
|
||||
return Some(1);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
static mut INPUT_MEM : Range<GuestAddr> = 0..0;
|
||||
static mut MEM_READ : Option<HashSet<GuestAddr>> = None;
|
||||
|
||||
pub fn trace_reads<QT, S>(
|
||||
_hooks: &mut QemuHooks<QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_id: u64,
|
||||
addr: GuestAddr,
|
||||
_size: usize
|
||||
)
|
||||
where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
if unsafe { INPUT_MEM.contains(&addr) } {
|
||||
if unsafe { MEM_READ.is_none() } {
|
||||
unsafe { MEM_READ = Some(HashSet::from([addr])) };
|
||||
} else {
|
||||
unsafe { MEM_READ.as_mut().unwrap().insert(addr) };
|
||||
}
|
||||
// println!("exec_read {:x} {}", addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
//============================= Utility functions
|
||||
|
||||
fn get_icount(emulator : &libafl_qemu::Qemu) -> u64 {
|
||||
|
@ -48,7 +48,8 @@ pub struct RawFreeRTOSSystemState {
|
||||
dumping_ground: HashMap<u32,freertos::rtos_struct>,
|
||||
input_counter: u32,
|
||||
edge: (GuestAddr,GuestAddr),
|
||||
capture_point: (CaptureEvent,String)
|
||||
capture_point: (CaptureEvent,String),
|
||||
mem_reads: HashSet<u32>
|
||||
}
|
||||
/// List of system state dumps from QemuHelpers
|
||||
static mut CURRENT_SYSTEMSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![];
|
||||
@ -222,6 +223,7 @@ impl ExecInterval {
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct FreeRTOSSystemStateMetadata {
|
||||
pub inner: Vec<ReducedFreeRTOSSystemState>,
|
||||
// TODO: Add abbs and memory reads
|
||||
trace_length: usize,
|
||||
indices: Vec<usize>, // Hashed enumeration of States
|
||||
tcref: isize,
|
||||
@ -262,13 +264,22 @@ impl HasRefCnt for FreeRTOSSystemStateMetadata {
|
||||
|
||||
libafl_bolts::impl_serdeany!(FreeRTOSSystemStateMetadata);
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[derive(Default, Serialize, Deserialize, Clone)]
|
||||
pub struct AtomicBasicBlock {
|
||||
start: GuestAddr,
|
||||
ends: HashSet<GuestAddr>,
|
||||
level: u8,
|
||||
instance_id: usize
|
||||
}
|
||||
|
||||
impl PartialEq for AtomicBasicBlock {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.start == other.start && self.ends == other.ends && self.level == other.level
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for AtomicBasicBlock {}
|
||||
|
||||
impl Hash for AtomicBasicBlock {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// Use a combination of the start address and the set of ending addresses to compute the hash value
|
||||
@ -340,6 +351,10 @@ impl AtomicBasicBlock {
|
||||
self.hash(&mut s);
|
||||
s.finish()
|
||||
}
|
||||
|
||||
pub fn instance_eq(&self, other: &Self) -> bool {
|
||||
self == other && self.instance_id == other.instance_id
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,6 +32,7 @@ pub struct QemuSystemStateObserver<I>
|
||||
pub last_run: Vec<ReducedFreeRTOSSystemState>,
|
||||
pub last_states: HashMap<u64, ReducedFreeRTOSSystemState>,
|
||||
pub last_trace: Vec<ExecInterval>,
|
||||
pub last_reads: Vec<HashSet<u32>>,
|
||||
pub last_input: I,
|
||||
pub success: bool,
|
||||
name: Cow<'static, str>,
|
||||
@ -57,8 +58,9 @@ where
|
||||
// println!("{:?}",temp);
|
||||
let temp = states2intervals(temp.0, temp.1);
|
||||
self.last_trace = temp.0;
|
||||
self.last_states = temp.1;
|
||||
self.success = temp.2;
|
||||
self.last_reads = temp.1;
|
||||
self.last_states = temp.2;
|
||||
self.success = temp.3;
|
||||
// println!("{:?}",temp);
|
||||
}
|
||||
// let abbs = extract_abbs_from_trace(&self.last_run);
|
||||
@ -88,7 +90,7 @@ impl<I> HasLen for QemuSystemStateObserver<I>
|
||||
impl<I> QemuSystemStateObserver<I>
|
||||
where I: Default {
|
||||
pub fn new() -> Self {
|
||||
Self{last_run: vec![], last_trace: vec![], last_input: I::default(), name: Cow::from("systemstate".to_string()), last_states: HashMap::new(), success: false }
|
||||
Self{last_run: vec![], last_trace: vec![], last_reads: vec![], last_input: I::default(), name: Cow::from("systemstate".to_string()), last_states: HashMap::new(), success: false }
|
||||
}
|
||||
}
|
||||
impl<I> Default for QemuSystemStateObserver<I>
|
||||
@ -137,7 +139,7 @@ fn tcb_list_to_vec_cached(list: List_t, dump: &mut HashMap<u32,rtos_struct>) ->
|
||||
ret
|
||||
}
|
||||
/// Drains a List of raw SystemStates to produce a refined trace
|
||||
fn refine_system_states(mut input: Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (u32, u32))>) {
|
||||
fn refine_system_states(mut input: Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (u32, u32), HashSet<u32>)>) {
|
||||
let mut ret = (Vec::<_>::new(), Vec::<_>::new());
|
||||
for mut i in input.drain(..) {
|
||||
let cur = RefinedTCB::from_tcb_owned(i.current_tcb);
|
||||
@ -160,20 +162,21 @@ fn refine_system_states(mut input: Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedF
|
||||
delay_list_after: delay_list,
|
||||
// input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
|
||||
});
|
||||
ret.1.push((i.qemu_tick, i.capture_point.0, i.capture_point.1.to_string(), i.edge));
|
||||
ret.1.push((i.qemu_tick, i.capture_point.0, i.capture_point.1.to_string(), i.edge, i.mem_reads));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Transform the states and metadata into a list of ExecIntervals
|
||||
fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, CaptureEvent, String, (u32, u32))>) -> (Vec<ExecInterval>, HashMap<u64, ReducedFreeRTOSSystemState>, bool) {
|
||||
if trace.len() == 0 {return (Vec::new(), HashMap::new(), true);}
|
||||
/// Transform the states and metadata into a list of ExecIntervals, along with a HashMap of states, a list of HashSets marking memory reads and a bool indicating success
|
||||
fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, CaptureEvent, String, (u32, u32), HashSet<u32>)>) -> (Vec<ExecInterval>, Vec<HashSet<u32>>, HashMap<u64, ReducedFreeRTOSSystemState>, bool) {
|
||||
if trace.len() == 0 {return (Vec::new(), Vec::new(), HashMap::new(), true);}
|
||||
let mut isr_stack : VecDeque<u8> = VecDeque::from([]); // 2+ = ISR, 1 = systemcall, 0 = APP. Trace starts with an ISREnd and executes the app
|
||||
|
||||
|
||||
let mut level_of_task : HashMap<&str, u8> = HashMap::new();
|
||||
|
||||
let mut ret: Vec<ExecInterval> = vec![];
|
||||
let mut reads: Vec<HashSet<u32>> = vec![];
|
||||
let mut edges: Vec<(u32, u32)> = vec![];
|
||||
let mut last_hash : u64 = trace[0].get_hash();
|
||||
let mut table : HashMap<u64, ReducedFreeRTOSSystemState> = HashMap::new();
|
||||
@ -244,14 +247,16 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
|
||||
tick_spend_preempted: 0,
|
||||
abb: None
|
||||
});
|
||||
reads.push(meta[i].4.clone());
|
||||
last_hash = next_hash;
|
||||
edges.push((meta[i].3.1, meta[i+1].3.0));
|
||||
}
|
||||
let t = add_abb_info(&mut ret, &table, &edges);
|
||||
(ret, table, t)
|
||||
(ret, reads, table, t)
|
||||
}
|
||||
|
||||
fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, edges: &Vec<(u32, u32)>) -> bool {
|
||||
let mut id_count = 0;
|
||||
let mut ret = true;
|
||||
let mut task_has_started : HashSet<String> = HashSet::new();
|
||||
let mut wip_abb_trace : Vec<Rc<RefCell<AtomicBasicBlock>>> = vec![];
|
||||
@ -273,21 +278,24 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
// assert_eq!(open_abb, None);
|
||||
ret &= open_abb.is_none();
|
||||
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
|
||||
id_count+=1;
|
||||
},
|
||||
// generic isr abb start
|
||||
CaptureEvent::ISRStart => {
|
||||
// assert_eq!(open_abb, None);
|
||||
ret &= open_abb.is_none();
|
||||
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
|
||||
id_count+=1;
|
||||
},
|
||||
// generic app abb start
|
||||
CaptureEvent::APIEnd => {
|
||||
// assert_eq!(open_abb, None);
|
||||
ret &= open_abb.is_none();
|
||||
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
|
||||
id_count+=1;
|
||||
},
|
||||
// generic continued blocks
|
||||
CaptureEvent::ISREnd => {
|
||||
@ -295,7 +303,8 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
if trace[i].start_capture.1=="xPortPendSVHandler" && !task_has_started.contains(curr_name) {
|
||||
// assert_eq!(open_abb, None);
|
||||
ret &= open_abb.is_none();
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: 0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: 0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
|
||||
id_count+=1;
|
||||
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
task_has_started.insert(curr_name.clone());
|
||||
} else {
|
||||
@ -310,7 +319,8 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
// println!("Continued block with no start {} {} {:?} {:?} {:x}-{:x} {} {}", curr_name, trace[i].start_tick, trace[i].start_capture, trace[i].end_capture, edges[i].0, edges[i].1, task_has_started.contains(curr_name),trace[i].level);
|
||||
// println!("{:x?}", open_abb_at_this_ret_addr_and_task);
|
||||
ret = false;
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].1, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})))
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].1, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
|
||||
id_count+=1;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user