diff --git a/fuzzers/FRET/benchmark/target_symbols.csv b/fuzzers/FRET/benchmark/target_symbols.csv index fc39889c78..c42ba19ae7 100644 --- a/fuzzers/FRET/benchmark/target_symbols.csv +++ b/fuzzers/FRET/benchmark/target_symbols.csv @@ -21,4 +21,5 @@ waters_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break watersv2_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break micro_branchless,main_branchless,FUZZ_INPUT,4,trigger_Qemu_break micro_int,main_int,FUZZ_INPUT,16,trigger_Qemu_break -micro_longint,main_micro_longint,FUZZ_INPUT,16,trigger_Qemu_break \ No newline at end of file +micro_longint,main_micro_longint,FUZZ_INPUT,16,trigger_Qemu_break +minimal,main_minimal,FUZZ_INPUT,4096,trigger_Qemu_break \ No newline at end of file diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index 8e660faaa5..0fc7560507 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -3,6 +3,7 @@ use core::time::Duration; use std::{env, path::PathBuf, process::{self, abort}, io::{Read, Write}, fs::{self, OpenOptions}, cmp::{min, max}, mem::transmute_copy, collections::btree_map::Range, ptr::addr_of_mut, ffi::OsStr}; +use hashbrown::HashMap; use libafl_bolts::{ core_affinity::Cores, current_nanos, @@ -36,11 +37,7 @@ use libafl_qemu::{ }; use rand::{SeedableRng, StdRng, Rng}; use crate::{ - clock::{QemuClockObserver, ClockTimeFeedback, QemuClockIncreaseFeedback, IcHist, FUZZ_START_TIMESTAMP}, - qemustate::QemuStateRestoreHelper, - systemstate::{helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{SysMapFeedback, SysGraphFeedbackState, GraphMaximizerCorpusScheduler}, schedulers::{LongestTraceScheduler, GenerationScheduler}}, worst::{TimeMaximizerCorpusScheduler, ExecTimeIncFeedback, TimeStateMaximizerCorpusScheduler, AlwaysTrueFeedback}, - mutational::MyStateStage, - mutational::{MINIMUM_INTER_ARRIVAL_TIME}, + clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP}, mutational::{MyStateStage, MINIMUM_INTER_ARRIVAL_TIME}, qemustate::QemuStateRestoreHelper, systemstate::{self, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{GraphMaximizerCorpusScheduler, SysGraphFeedbackState, SysMapFeedback}, helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}}, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, TimeMaximizerCorpusScheduler, TimeStateMaximizerCorpusScheduler} }; use std::time::{SystemTime, UNIX_EPOCH}; use clap::{Parser, Subcommand}; @@ -310,8 +307,8 @@ pub fn fuzz() { // let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin()); #[cfg(feature = "systemstate")] println!("Task Queue at {:#x}", task_queue_addr); - #[cfg(feature = "systemstate")] - let svh = load_symbol(&elf, "xPortPendSVHandler", false); + // #[cfg(feature = "systemstate")] + // let svh = load_symbol(&elf, "xPortPendSVHandler", false); // let svh=virt2phys(svh, &elf); // let svh = elf // .resolve_symbol("vPortEnterCritical", 0) @@ -345,6 +342,17 @@ pub fn fuzz() { unsafe {RNG_SEED = str::parse::(&seed).expect("SEED_RANDOM must be an integer.");} } + #[cfg(feature = "systemstate")] + let mut api_addreses : HashMap = HashMap::new(); + #[cfg(feature = "systemstate")] + for s in systemstate::helpers::API_SYMBOLS { + if let Some(sb) = try_load_symbol(&elf, &s, false) { + api_addreses.insert(sb,s); + } + } + + // Client setup ================================================================================ + let mut run_client = |state: Option<_>, mut mgr, _core_id| { // Initialize QEMU let args: Vec = vec![ @@ -537,7 +545,7 @@ pub fn fuzz() { let qhelpers = tuple_list!( QemuEdgeCoverageHelper::default(), QemuStateRestoreHelper::new(), - QemuSystemStateHelper::new(svh,curr_tcb_pointer,task_queue_addr,task_delay_addr,task_delay_overflow_addr,input_counter_ptr,app_range.clone()) + QemuSystemStateHelper::new(api_addreses,curr_tcb_pointer,task_queue_addr,task_delay_addr,task_delay_overflow_addr,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 9e9e32e165..7342715e84 100644 --- a/fuzzers/FRET/src/systemstate/helpers.rs +++ b/fuzzers/FRET/src/systemstate/helpers.rs @@ -1,6 +1,7 @@ use std::cell::UnsafeCell; use std::io::Write; use std::ops::Range; +use hashbrown::HashMap; use libafl::prelude::ExitKind; use libafl::prelude::UsesInput; use libafl_qemu::Emulator; @@ -32,12 +33,47 @@ pub static mut INTR_DONE : bool = true; // only used when inputs are injected pub static mut NEXT_INPUT : Vec = Vec::new(); +//============================= API symbols + +pub static API_SYMBOLS : &'static [&str] = &[ +// Task Creation +"xTaskCreate", "xTaskCreateStatic", "vTaskDelete", "xTaskGetStaticBuffers", +// Task Control +"vTaskDelay","vTaskDelayUntil","xTaskDelayUntil", "uxTaskPriorityGet", "uxTaskPriorityGetFromISR", "uxTaskBasePriorityGet","uxTaskBasePriorityGetFromISR", "vTaskPrioritySet","vTaskSuspend","vTaskResume","xTaskResumeFromISR","xTaskAbortDelay", +// Task Utilities +"uxTaskGetSystemState","vTaskGetInfo","xTaskGetCurrentTaskHandle","xTaskGetIdleTaskHandle","uxTaskGetStackHighWaterMark","eTaskGetState","pcTaskGetName","xTaskGetHandle","xTaskGetTickCount","xTaskGetTickCountFromISR","xTaskGetSchedulerState","uxTaskGetNumberOfTasks","vTaskList","vTaskListTasks","vTaskStartTrace","ulTaskEndTrace","vTaskGetRunTimeStats","vTaskGetRunTimeStatistics","vTaskGetIdleRunTimeCounter","ulTaskGetRunTimeCounter","ulTaskGetRunTimePercent","ulTaskGetIdleRunTimeCounter","ulTaskGetIdleRunTimePercent","vTaskSetApplicationTaskTag","xTaskGetApplicationTaskTag","xTaskCallApplicationTaskHook","pvTaskGetThreadLocalStoragePointer","vTaskSetThreadLocalStoragePointer","vTaskSetTimeOutState","xTaskCheckForTimeOut", +// RTOS Kernel Control +"taskYIELD","taskENTER_CRITICAL","taskEXIT_CRITICAL","taskENTER_CRITICAL_FROM_ISR","taskEXIT_CRITICAL_FROM_ISR","taskDISABLE_INTERRUPTS","taskENABLE_INTERRUPTS","vTaskStartScheduler","vTaskEndScheduler","vTaskSuspendAll","xTaskResumeAll","vTaskStepTick", +// Direct To Task Notifications +"xTaskNotifyGive","xTaskNotifyGiveIndexed","vTaskNotifyGiveFromISR","vTaskNotifyGiveIndexedFromISR","ulTaskNotifyTake","ulTaskNotifyTakeIndexed","xTaskNotify","xTaskNotifyIndexed","xTaskNotifyAndQuery","xTaskNotifyAndQueryIndexed","xTaskNotifyAndQueryFromISR","xTaskNotifyAndQueryFromISRIndexed","xTaskNotifyFromISR","xTaskNotifyFromISRIndexed","xTaskNotifyWait","xTaskNotifyWaitIndexed","xTaskNotifyStateClear","xTaskNotifyStateClearIndexed","ulTasknotifyValueClear","ulTasknotifyValueClearIndexed", +// Queues +"xQueueCreate","xQueueCreateStatic","vQueueDelete","xQueueSend","xQueueSendFromISR","xQueueSendToBack","xQueueSendToBackFromISR","xQueueSendToFront","xQueueSendToFrontFromISR","xQueueReceive","xQueueReceiveFromISR","uxQueueMessagesWaiting","uxQueueMessagesWaitingFromISR","uxQueueSpacesAvailable","xQueueReset","xQueuePeek","xQueuePeekFromISR","vQueueAddToRegistry","pcQueueGetName","vQueueUnregisterQueue","xQueueIsQueueEmptyFromISR","xQueueIsQueueFullFromISR","xQueueOverwrite","xQueueOverwriteFromISR","xQueueGetStaticBuffers", +// Queue Sets +"xQueueCreateSet","xQueueAddToSet","xQueueRemoveFromSet","xQueueSelectFromSet","xQueueSelectFromSetFromISR", +// Stream Buffers +"xStreamBufferCreate","xStreamBufferCreateStatic","xStreamBufferSend","xStreamBufferSendFromISR","xStreamBufferReceive","xStreamBufferReceiveFromISR","vStreamBufferDelete","xStreamBufferBytesAvailable","xStreamBufferSpacesAvailable","xStreamBufferSetTriggerLevel","xStreamBufferReset","xStreamBufferIsEmpty","xStreamBufferIsFull","xStreamBufferGetStaticBuffers", +// Message Buffers +"xMessageBufferCreate","xMessageBufferCreateStatic","xMessageBufferSend","xMessageBufferSendFromISR","xMessageBufferReceive","xMessageBufferReceiveFromISR","vMessageBufferDelete","xMessageBufferSpacesAvailable","xMessageBufferReset","xMessageBufferIsEmpty","xMessageBufferIsFull","xMessageBufferGetStaticBuffers", +// Semaphores +"xSemaphoreCreateBinary","xSemaphoreCreateBinaryStatic","vSemaphoreCreateBinary","xSemaphoreCreateCounting","xSemaphoreCreateCountingStatic","xSemaphoreCreateMutex","xSemaphoreCreateMutexStatic","xSemaphoreCreateRecursiveMutex","xSemaphoreCreateRecursiveMutexStatic","vSemaphoreDelete","xSemaphoreGetMutexHolder","xSemaphoreTake","xSemaphoreTakeFromISR","xSemaphoreTakeRecursive","xSemaphoreGive","xSemaphoreGiveRecursive","xSemaphoreGiveFromISR","uxSemaphoreGetCount","xSemaphoreGetStaticBuffer", +// Software Timers +"xTimerCreate","xTimerCreateStatic","xTimerIsTimerActive","pvTimerGetTimerID","pcTimerGetName","vTimerSetReloadMode","xTimerStart","xTimerStop","xTimerChangePeriod","xTimerDelete","xTimerReset","xTimerStartFromISR","xTimerStopFromISR","xTimerChangePeriodFromISR","xTimerResetFromISR","pvTimerGetTimerID","vTimerSetTimerID","xTimerGetTimerDaemonTaskHandle","xTimerPendFunctionCall","xTimerPendFunctionCallFromISR","pcTimerGetName","xTimerGetPeriod","xTimerGetExpiryTime","xTimerGetReloadMode", +// Event Groups +"vEventGroupDelete","xEventGroupClearBits","xEventGroupClearBitsFromISR","xEventGroupCreate","xEventGroupCreateStatic","xEventGroupGetBits","xEventGroupGetBitsFromISR","xEventGroupGetStaticBuffer","xEventGroupSetBits","xEventGroupSetBitsFromISR","xEventGroupSync","xEventGroupWaitBits", +// MPU Specific functions +"xTaskCreateRestricted","xTaskCreateRestrictedStatic","vTaskAllocateMPURegions","portSWITCH_TO_USER_MODE", +// Co-routines +"xCoRoutineCreate","crDELAY","crQUEUE_SEND","crQUEUE_RECEIVE","crQUEUE_SEND_FROM_ISR","crQUEUE_RECEIVE_FROM_ISR","vCoRoutineSchedule", +// Custom resolved macros +"vPortEnterCritical","vPortExitCritical","xTaskGenericNotify","xTaskGenericNotifyFromISR","xQueueGenericSend","xQueueGenericReset" +]; + //============================= Qemu Helper /// A Qemu Helper with reads FreeRTOS specific structs from Qemu whenever certain syscalls occur, also inject inputs #[derive(Debug)] pub struct QemuSystemStateHelper { - kerneladdr: GuestAddr, + watchaddr: HashMap, tcb_addr: GuestAddr, ready_queues: GuestAddr, delay_queue: GuestAddr, @@ -49,7 +85,7 @@ pub struct QemuSystemStateHelper { impl QemuSystemStateHelper { #[must_use] pub fn new( - kerneladdr: GuestAddr, + watchaddr: HashMap, tcb_addr: GuestAddr, ready_queues: GuestAddr, delay_queue: GuestAddr, @@ -58,7 +94,7 @@ impl QemuSystemStateHelper { app_range: Range, ) -> Self { QemuSystemStateHelper { - kerneladdr, + watchaddr: watchaddr, tcb_addr: tcb_addr, ready_queues: ready_queues, delay_queue, @@ -77,7 +113,9 @@ where where QT: QemuHelperTuple, { - _hooks.instruction(self.kerneladdr, Hook::Function(exec_syscall_hook::), false); + for wp in self.watchaddr.keys() { + _hooks.instruction(*wp, Hook::Function(exec_syscall_hook::), false); + } #[cfg(feature = "trace_abbs")] _hooks.jmps(Hook::Function(gen_jmp_is_syscall::), Hook::Function(trace_api_call::)); } @@ -92,7 +130,7 @@ where } fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input, _observers: &mut OT, _exit_kind: &mut ExitKind) { - trigger_collection(emulator, self) + trigger_collection(emulator,0, self); } } @@ -128,7 +166,7 @@ fn read_freertos_list(systemstate : &mut RawFreeRTOSSystemState, emulator: &Emul } #[inline] -fn trigger_collection(emulator: &Emulator, h: &QemuSystemStateHelper) { +fn trigger_collection(emulator: &Emulator, pc: GuestAddr, h: &QemuSystemStateHelper) { let listbytes : GuestAddr = GuestAddr::try_from(std::mem::size_of::()).unwrap(); let mut systemstate = RawFreeRTOSSystemState::default(); unsafe { @@ -180,13 +218,15 @@ fn trigger_collection(emulator: &Emulator, h: &QemuSystemStateHelper) { systemstate.prio_ready_lists[i] = read_freertos_list(&mut systemstate, emulator, target); } + systemstate.capture_point = h.watchaddr.get(&pc).unwrap_or(&"unknown"); + unsafe { CURRENT_SYSTEMSTATE_VEC.push(systemstate); } } pub fn exec_syscall_hook( hooks: &mut QemuHooks, _state: Option<&mut S>, - _pc: GuestAddr, + pc: GuestAddr, ) where S: UsesInput, @@ -194,7 +234,7 @@ where { let emulator = hooks.emulator(); let h = hooks.helpers().match_first_type::().expect("QemuSystemHelper not found in helper tupel"); - trigger_collection(emulator, h); + trigger_collection(emulator, pc, h); } thread_local!(static LAST_API_CALL : UnsafeCell> = UnsafeCell::new(None)); diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index ded4f2ed57..3a46aff80b 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -2,6 +2,7 @@ use std::collections::hash_map::DefaultHasher; use libafl_bolts::HasRefCnt; use libafl_bolts::AsSlice; +use libafl_qemu::GuestAddr; use std::hash::Hasher; use std::hash::Hash; use hashbrown::HashMap; @@ -37,6 +38,7 @@ pub struct RawFreeRTOSSystemState { dumping_ground: HashMap, input_counter: u32, last_pc: Option, + capture_point: &'static str } /// List of system state dumps from QemuHelpers static mut CURRENT_SYSTEMSTATE_VEC: Vec = vec![]; @@ -113,6 +115,7 @@ pub struct RefinedFreeRTOSSystemState { pub current_task: (RefinedTCB, u32), ready_list_after: Vec<(RefinedTCB, u32)>, delay_list_after: Vec<(RefinedTCB, u32)>, + pub capture_point: String } impl PartialEq for RefinedFreeRTOSSystemState { fn eq(&self, other: &Self) -> bool { diff --git a/fuzzers/FRET/src/systemstate/observers.rs b/fuzzers/FRET/src/systemstate/observers.rs index 6491dd9bb6..963f12758b 100644 --- a/fuzzers/FRET/src/systemstate/observers.rs +++ b/fuzzers/FRET/src/systemstate/observers.rs @@ -163,6 +163,7 @@ fn refine_system_states(input: &mut Vec) -> Vec