From 7e79f4051d3eeeef365f3835be8ebac6073be2a1 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Sat, 9 Mar 2024 13:41:26 +0100 Subject: [PATCH] clean trace from ISRs without effect, prevent race-conditions --- fuzzers/FRET/src/fuzzer.rs | 4 +- fuzzers/FRET/src/systemstate/helpers.rs | 98 +++++++++++++---------- fuzzers/FRET/src/systemstate/mod.rs | 3 +- fuzzers/FRET/src/systemstate/observers.rs | 26 +++++- 4 files changed, 86 insertions(+), 45 deletions(-) diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index edc1afd8e7..ab4b989a96 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -335,6 +335,8 @@ pub fn fuzz() { let task_queue_addr = load_symbol(&elf, "pxReadyTasksLists", false); let task_delay_addr = load_symbol(&elf, "pxDelayedTaskList", false); let task_delay_overflow_addr = load_symbol(&elf, "pxOverflowDelayedTaskList", false); + let scheduler_lock = load_symbol(&elf, "uxSchedulerSuspended", false); + let critical_section = load_symbol(&elf, "uxCriticalNesting", false); // let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin()); #[cfg(feature = "systemstate")] println!("Task Queue at {:#x}", task_queue_addr); @@ -589,7 +591,7 @@ pub fn fuzz() { let qhelpers = tuple_list!( QemuEdgeCoverageHelper::default(), QemuStateRestoreHelper::new(), - QemuSystemStateHelper::new(api_addreses,api_ranges,isr_addreses,isr_ranges,curr_tcb_pointer,task_queue_addr,task_delay_addr,task_delay_overflow_addr,input_counter_ptr,app_range.clone()) + QemuSystemStateHelper::new(api_addreses,api_ranges,isr_addreses,isr_ranges,curr_tcb_pointer,task_queue_addr,task_delay_addr,task_delay_overflow_addr,scheduler_lock, critical_section,input_counter_ptr,app_range.clone()) ); let mut hooks = QemuHooks::new(emu.clone(),qhelpers); diff --git a/fuzzers/FRET/src/systemstate/helpers.rs b/fuzzers/FRET/src/systemstate/helpers.rs index 0e5f36be5b..b3ddaa24e4 100644 --- a/fuzzers/FRET/src/systemstate/helpers.rs +++ b/fuzzers/FRET/src/systemstate/helpers.rs @@ -17,6 +17,7 @@ use crate::systemstate::extract_abbs_from_trace; use crate::systemstate::RawFreeRTOSSystemState; use crate::systemstate::CURRENT_SYSTEMSTATE_VEC; use crate::systemstate::NUM_PRIOS; +use super::freertos::void_ptr; use super::freertos::TCB_t; use super::freertos::rtos_struct::List_Item_struct; use super::freertos::rtos_struct::*; @@ -92,6 +93,8 @@ pub struct QemuSystemStateHelper { ready_queues: GuestAddr, delay_queue: GuestAddr, delay_queue_overflow: GuestAddr, + scheduler_lock_addr: GuestAddr, + critical_addr: GuestAddr, input_counter: Option, app_range: Range, } @@ -107,6 +110,8 @@ impl QemuSystemStateHelper { ready_queues: GuestAddr, delay_queue: GuestAddr, delay_queue_overflow: GuestAddr, + scheduler_lock_addr: GuestAddr, + critical_addr: GuestAddr, input_counter: Option, app_range: Range, ) -> Self { @@ -119,6 +124,8 @@ impl QemuSystemStateHelper { ready_queues: ready_queues, delay_queue, delay_queue_overflow, + scheduler_lock_addr, + critical_addr, input_counter: input_counter, app_range, } @@ -156,7 +163,7 @@ where trigger_collection(emulator,(None, None), self); unsafe { let c = emulator.cpu_from_index(0); - let pc = c.read_reg::(15).unwrap();; + let pc = c.read_reg::(15).unwrap(); CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].edge = (Some(pc),None); CURRENT_SYSTEMSTATE_VEC[CURRENT_SYSTEMSTATE_VEC.len()-1].capture_point = (CaptureEvent::End,"Breakpoint"); } @@ -173,7 +180,7 @@ where } unsafe { let abbs = extract_abbs_from_trace(&CURRENT_SYSTEMSTATE_VEC); - println!("{:?}", abbs); + //println!("{:?}", abbs); } } } @@ -213,44 +220,6 @@ fn read_freertos_list(systemstate : &mut RawFreeRTOSSystemState, emulator: &Emul fn trigger_collection(emulator: &Emulator, edge: (Option,Option), h: &QemuSystemStateHelper) { let listbytes : GuestAddr = GuestAddr::try_from(std::mem::size_of::()).unwrap(); let mut systemstate = RawFreeRTOSSystemState::default(); - unsafe { - // TODO: investigate why can_do_io is not set sometimes, as this is just a workaround - let c = emulator.cpu_from_index(0); - let can_do_io = (*c.raw_ptr()).neg.can_do_io; - (*c.raw_ptr()).neg.can_do_io = true; - systemstate.qemu_tick = emu::icount_get_raw(); - (*c.raw_ptr()).neg.can_do_io = can_do_io; - } - let mut buf : [u8; 4] = [0,0,0,0]; - match h.input_counter { - Some(s) => unsafe { emulator.read_mem(s, &mut buf); }, - None => (), - }; - systemstate.input_counter = GuestAddr::from_le_bytes(buf); - - let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr); - if curr_tcb_addr == 0 { - return; - }; - systemstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr); - - // println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName)); - - // Extract delay list - let mut target : GuestAddr = h.delay_queue; - target = freertos::emu_lookup::lookup(emulator, target); - systemstate.delay_list = read_freertos_list(&mut systemstate, emulator, target); - - // Extract delay list overflow - let mut target : GuestAddr = h.delay_queue_overflow; - target = freertos::emu_lookup::lookup(emulator, target); - systemstate.delay_list_overflow = read_freertos_list(&mut systemstate, emulator, target); - - // Extract priority lists - for i in 0..NUM_PRIOS { - let target : GuestAddr = listbytes*GuestAddr::try_from(i).unwrap()+h.ready_queues; - systemstate.prio_ready_lists[i] = read_freertos_list(&mut systemstate, emulator, target); - } // Note type of capture match edge.1 { @@ -284,10 +253,57 @@ fn trigger_collection(emulator: &Emulator, edge: (Option,Option unsafe { emulator.read_mem(s, &mut buf); }, + None => (), + }; + systemstate.input_counter = GuestAddr::from_le_bytes(buf); + + let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr); + if curr_tcb_addr == 0 { + return; + }; + + // println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName)); + let critical : void_ptr = freertos::emu_lookup::lookup(emulator, h.critical_addr); + let suspended : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_lock_addr); + + // During ISRs it is only safe to extract structs if they are not currently being modified + if (systemstate.capture_point.0==CaptureEvent::ISRStart || systemstate.capture_point.0==CaptureEvent::ISREnd) && critical == 0 && suspended == 0 { + systemstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr); + // Extract delay list + let mut target : GuestAddr = h.delay_queue; + target = freertos::emu_lookup::lookup(emulator, target); + systemstate.delay_list = read_freertos_list(&mut systemstate, emulator, target); + + // Extract delay list overflow + let mut target : GuestAddr = h.delay_queue_overflow; + target = freertos::emu_lookup::lookup(emulator, target); + systemstate.delay_list_overflow = read_freertos_list(&mut systemstate, emulator, target); + + // Extract priority lists + for i in 0..NUM_PRIOS { + let target : GuestAddr = listbytes*GuestAddr::try_from(i).unwrap()+h.ready_queues; + systemstate.prio_ready_lists[i] = read_freertos_list(&mut systemstate, emulator, target); + } + } + + + unsafe { CURRENT_SYSTEMSTATE_VEC.push(systemstate); } } diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index 1da810d219..ec7020a78b 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -137,7 +137,8 @@ impl PartialEq for RefinedFreeRTOSSystemState { fn eq(&self, other: &Self) -> bool { self.current_task == other.current_task && self.ready_list_after == other.ready_list_after && self.delay_list_after == other.delay_list_after - // && self.last_pc == other.last_pc + // && self.edge == other.edge + // && self.capture_point == other.capture_point } } diff --git a/fuzzers/FRET/src/systemstate/observers.rs b/fuzzers/FRET/src/systemstate/observers.rs index 3797ae090d..b5a08b1360 100644 --- a/fuzzers/FRET/src/systemstate/observers.rs +++ b/fuzzers/FRET/src/systemstate/observers.rs @@ -8,6 +8,7 @@ use libafl::Error; use libafl::observers::Observer; use serde::{Deserialize, Serialize}; use hashbrown::HashMap; +use crate::systemstate::CaptureEvent; use super::{ CURRENT_SYSTEMSTATE_VEC, @@ -43,7 +44,7 @@ where #[inline] fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> { - unsafe {self.last_run = refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC);} + unsafe {self.last_run = post_process_trace(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));} self.last_input=_input.target_bytes().as_slice().to_owned(); Ok(()) } @@ -168,4 +169,25 @@ fn refine_system_states(input: &mut Vec) -> Vec) -> Vec { + // remove subsequent pairs of equal states where an ISRStart follows an ISREnd + let mut i = 1; + while i < trace.len() - 1 { + if trace[i] == trace[i + 1] && + matches!(trace[i].capture_point.0, CaptureEvent::ISRStart) && + matches!(trace[i + 1].capture_point.0, CaptureEvent::ISREnd) && + trace[i].capture_point.1 == trace[i + 1].capture_point.1 + { + // extend the end of the last ABB until the end of the next one + trace[i-1].end_tick = trace[i+1].end_tick; + + trace.remove(i + 1); + trace.remove(i); + } else { + i+=1; + } + } + trace +}