break on all api functions

This commit is contained in:
Alwin Berger 2024-02-26 08:40:07 +01:00
parent 3817892ff1
commit 5d9bcba0e6
7 changed files with 97 additions and 17 deletions

View File

@ -21,4 +21,5 @@ waters_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break
watersv2_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_branchless,main_branchless,FUZZ_INPUT,4,trigger_Qemu_break
micro_int,main_int,FUZZ_INPUT,16,trigger_Qemu_break micro_int,main_int,FUZZ_INPUT,16,trigger_Qemu_break
micro_longint,main_micro_longint,FUZZ_INPUT,16,trigger_Qemu_break micro_longint,main_micro_longint,FUZZ_INPUT,16,trigger_Qemu_break
minimal,main_minimal,FUZZ_INPUT,4096,trigger_Qemu_break
1 kernel main_function input_symbol input_size return_function
21 watersv2_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break
22 micro_branchless main_branchless FUZZ_INPUT 4 trigger_Qemu_break
23 micro_int main_int FUZZ_INPUT 16 trigger_Qemu_break
24 micro_longint main_micro_longint FUZZ_INPUT 16 trigger_Qemu_break
25 minimal main_minimal FUZZ_INPUT 4096 trigger_Qemu_break

View File

@ -3,6 +3,7 @@
use core::time::Duration; 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 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::{ use libafl_bolts::{
core_affinity::Cores, core_affinity::Cores,
current_nanos, current_nanos,
@ -36,11 +37,7 @@ use libafl_qemu::{
}; };
use rand::{SeedableRng, StdRng, Rng}; use rand::{SeedableRng, StdRng, Rng};
use crate::{ use crate::{
clock::{QemuClockObserver, ClockTimeFeedback, QemuClockIncreaseFeedback, IcHist, FUZZ_START_TIMESTAMP}, 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}
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},
}; };
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
@ -310,8 +307,8 @@ pub fn fuzz() {
// let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin()); // let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin());
#[cfg(feature = "systemstate")] #[cfg(feature = "systemstate")]
println!("Task Queue at {:#x}", task_queue_addr); println!("Task Queue at {:#x}", task_queue_addr);
#[cfg(feature = "systemstate")] // #[cfg(feature = "systemstate")]
let svh = load_symbol(&elf, "xPortPendSVHandler", false); // let svh = load_symbol(&elf, "xPortPendSVHandler", false);
// let svh=virt2phys(svh, &elf); // let svh=virt2phys(svh, &elf);
// let svh = elf // let svh = elf
// .resolve_symbol("vPortEnterCritical", 0) // .resolve_symbol("vPortEnterCritical", 0)
@ -345,6 +342,17 @@ pub fn fuzz() {
unsafe {RNG_SEED = str::parse::<u64>(&seed).expect("SEED_RANDOM must be an integer.");} unsafe {RNG_SEED = str::parse::<u64>(&seed).expect("SEED_RANDOM must be an integer.");}
} }
#[cfg(feature = "systemstate")]
let mut api_addreses : HashMap<GuestAddr,&'static str> = 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| { let mut run_client = |state: Option<_>, mut mgr, _core_id| {
// Initialize QEMU // Initialize QEMU
let args: Vec<String> = vec![ let args: Vec<String> = vec![
@ -537,7 +545,7 @@ pub fn fuzz() {
let qhelpers = tuple_list!( let qhelpers = tuple_list!(
QemuEdgeCoverageHelper::default(), QemuEdgeCoverageHelper::default(),
QemuStateRestoreHelper::new(), 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); let mut hooks = QemuHooks::new(emu.clone(),qhelpers);

View File

@ -1,6 +1,7 @@
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::io::Write; use std::io::Write;
use std::ops::Range; use std::ops::Range;
use hashbrown::HashMap;
use libafl::prelude::ExitKind; use libafl::prelude::ExitKind;
use libafl::prelude::UsesInput; use libafl::prelude::UsesInput;
use libafl_qemu::Emulator; use libafl_qemu::Emulator;
@ -32,12 +33,47 @@ pub static mut INTR_DONE : bool = true;
// only used when inputs are injected // only used when inputs are injected
pub static mut NEXT_INPUT : Vec<u8> = Vec::new(); pub static mut NEXT_INPUT : Vec<u8> = 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 //============================= Qemu Helper
/// A Qemu Helper with reads FreeRTOS specific structs from Qemu whenever certain syscalls occur, also inject inputs /// A Qemu Helper with reads FreeRTOS specific structs from Qemu whenever certain syscalls occur, also inject inputs
#[derive(Debug)] #[derive(Debug)]
pub struct QemuSystemStateHelper { pub struct QemuSystemStateHelper {
kerneladdr: GuestAddr, watchaddr: HashMap<GuestAddr, &'static str>,
tcb_addr: GuestAddr, tcb_addr: GuestAddr,
ready_queues: GuestAddr, ready_queues: GuestAddr,
delay_queue: GuestAddr, delay_queue: GuestAddr,
@ -49,7 +85,7 @@ pub struct QemuSystemStateHelper {
impl QemuSystemStateHelper { impl QemuSystemStateHelper {
#[must_use] #[must_use]
pub fn new( pub fn new(
kerneladdr: GuestAddr, watchaddr: HashMap<GuestAddr, &'static str>,
tcb_addr: GuestAddr, tcb_addr: GuestAddr,
ready_queues: GuestAddr, ready_queues: GuestAddr,
delay_queue: GuestAddr, delay_queue: GuestAddr,
@ -58,7 +94,7 @@ impl QemuSystemStateHelper {
app_range: Range<GuestAddr>, app_range: Range<GuestAddr>,
) -> Self { ) -> Self {
QemuSystemStateHelper { QemuSystemStateHelper {
kerneladdr, watchaddr: watchaddr,
tcb_addr: tcb_addr, tcb_addr: tcb_addr,
ready_queues: ready_queues, ready_queues: ready_queues,
delay_queue, delay_queue,
@ -77,7 +113,9 @@ where
where where
QT: QemuHelperTuple<S>, QT: QemuHelperTuple<S>,
{ {
_hooks.instruction(self.kerneladdr, Hook::Function(exec_syscall_hook::<QT, S>), false); for wp in self.watchaddr.keys() {
_hooks.instruction(*wp, Hook::Function(exec_syscall_hook::<QT, S>), false);
}
#[cfg(feature = "trace_abbs")] #[cfg(feature = "trace_abbs")]
_hooks.jmps(Hook::Function(gen_jmp_is_syscall::<QT, S>), Hook::Function(trace_api_call::<QT, S>)); _hooks.jmps(Hook::Function(gen_jmp_is_syscall::<QT, S>), Hook::Function(trace_api_call::<QT, S>));
} }
@ -92,7 +130,7 @@ where
} }
fn post_exec<OT>(&mut self, emulator: &Emulator, _input: &S::Input, _observers: &mut OT, _exit_kind: &mut ExitKind) { fn post_exec<OT>(&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] #[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::<freertos::List_t>()).unwrap(); let listbytes : GuestAddr = GuestAddr::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
let mut systemstate = RawFreeRTOSSystemState::default(); let mut systemstate = RawFreeRTOSSystemState::default();
unsafe { 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.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); } unsafe { CURRENT_SYSTEMSTATE_VEC.push(systemstate); }
} }
pub fn exec_syscall_hook<QT, S>( pub fn exec_syscall_hook<QT, S>(
hooks: &mut QemuHooks<QT, S>, hooks: &mut QemuHooks<QT, S>,
_state: Option<&mut S>, _state: Option<&mut S>,
_pc: GuestAddr, pc: GuestAddr,
) )
where where
S: UsesInput, S: UsesInput,
@ -194,7 +234,7 @@ where
{ {
let emulator = hooks.emulator(); let emulator = hooks.emulator();
let h = hooks.helpers().match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel"); let h = hooks.helpers().match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
trigger_collection(emulator, h); trigger_collection(emulator, pc, h);
} }
thread_local!(static LAST_API_CALL : UnsafeCell<Option<(GuestAddr,GuestAddr)>> = UnsafeCell::new(None)); thread_local!(static LAST_API_CALL : UnsafeCell<Option<(GuestAddr,GuestAddr)>> = UnsafeCell::new(None));

View File

@ -2,6 +2,7 @@
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use libafl_bolts::HasRefCnt; use libafl_bolts::HasRefCnt;
use libafl_bolts::AsSlice; use libafl_bolts::AsSlice;
use libafl_qemu::GuestAddr;
use std::hash::Hasher; use std::hash::Hasher;
use std::hash::Hash; use std::hash::Hash;
use hashbrown::HashMap; use hashbrown::HashMap;
@ -37,6 +38,7 @@ pub struct RawFreeRTOSSystemState {
dumping_ground: HashMap<u32,freertos::rtos_struct>, dumping_ground: HashMap<u32,freertos::rtos_struct>,
input_counter: u32, input_counter: u32,
last_pc: Option<u64>, last_pc: Option<u64>,
capture_point: &'static str
} }
/// List of system state dumps from QemuHelpers /// List of system state dumps from QemuHelpers
static mut CURRENT_SYSTEMSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![]; static mut CURRENT_SYSTEMSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![];
@ -113,6 +115,7 @@ pub struct RefinedFreeRTOSSystemState {
pub current_task: (RefinedTCB, u32), pub current_task: (RefinedTCB, u32),
ready_list_after: Vec<(RefinedTCB, u32)>, ready_list_after: Vec<(RefinedTCB, u32)>,
delay_list_after: Vec<(RefinedTCB, u32)>, delay_list_after: Vec<(RefinedTCB, u32)>,
pub capture_point: String
} }
impl PartialEq for RefinedFreeRTOSSystemState { impl PartialEq for RefinedFreeRTOSSystemState {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {

View File

@ -163,6 +163,7 @@ fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> Vec<RefinedF
delay_list_after: delay_list, delay_list_after: delay_list,
input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER, input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
last_pc: i.last_pc, last_pc: i.last_pc,
capture_point: i.capture_point.to_string()
}); });
start_tick=i.qemu_tick; start_tick=i.qemu_tick;
} }

5
fuzzers/FRET/tests/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
dump
demo*
*.dot
*.time
*.case

View File

@ -0,0 +1,22 @@
#!/bin/sh
# cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_afl,observer_hitcounts
# Test basic fuzzing loop
../target/debug/fret -k ../benchmark/build/waters.elf -c ../benchmark/target_symbols.csv -n ./dump/waters -tar fuzz -t 10 -s 123
# Test reprodcibility
rm -f ./dump/demo.case.time
../target/debug/fret -k ../benchmark/build/waters.elf -c ../benchmark/target_symbols.csv -n ./dump/demo -tr showmap -i ./demo.case
if [[ $(cut -d, -f1 ./dump/demo.case.time) != $(cut -d, -f1 ./demo.example.time) ]]; then echo "Not reproducible!" && exit 1; else echo "Reproducible"; fi
# Test state dump
# cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_afl,observer_hitcounts,systemstate
if [[ -n "$(diff -q demo.example.state.ron dump/demo.trace.ron)" ]]; then echo "State not reproducible!"; else echo "State Reproducible"; fi
# Test abb traces
# cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_afl,observer_hitcounts,systemstate,trace_abbs
if [[ -n "$(diff -q demo.example.abb.ron dump/demo.trace.ron)" ]]; then echo "ABB not reproducible!"; else echo "ABB Reproducible"; fi
# ../target/debug/fret -k ../benchmark/build/minimal.elf -c ../benchmark/target_symbols.csv -n ./dump/minimal -tar fuzz -t 100 -s 123
# ../target/debug/fret -k ../benchmark/build/minimal.elf -c ../benchmark/target_symbols.csv -n ./dump/minimal_worst -tr showmap -i ./dump/minimal.case