168 lines
5.1 KiB
Rust
168 lines
5.1 KiB
Rust
//! systemstate referes to the State of a FreeRTOS fuzzing target
|
|
use std::collections::hash_map::DefaultHasher;
|
|
use libafl::bolts::HasRefCnt;
|
|
use libafl::bolts::AsSlice;
|
|
use std::hash::Hasher;
|
|
use std::hash::Hash;
|
|
use hashbrown::HashMap;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use freertos::TCB_t;
|
|
|
|
pub mod freertos;
|
|
pub mod helpers;
|
|
pub mod observers;
|
|
pub mod feedbacks;
|
|
pub mod graph;
|
|
pub mod schedulers;
|
|
|
|
// #[cfg(feature = "fuzz_interrupt")]
|
|
// pub const IRQ_INPUT_BYTES_NUMBER : u32 = 2; // Offset for interrupt bytes
|
|
// #[cfg(not(feature = "fuzz_interrupt"))]
|
|
// pub const IRQ_INPUT_BYTES_NUMBER : u32 = 0; // Offset for interrupt bytes
|
|
// pub const IRQ_INPUT_OFFSET : u32 = 347780; // Tick offset for app code start
|
|
|
|
// Constants
|
|
const NUM_PRIOS: usize = 5;
|
|
|
|
//============================= Struct definitions
|
|
/// Raw info Dump from Qemu
|
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
|
pub struct RawFreeRTOSSystemState {
|
|
qemu_tick: u64,
|
|
current_tcb: TCB_t,
|
|
prio_ready_lists: [freertos::List_t; NUM_PRIOS],
|
|
dumping_ground: HashMap<u32,freertos::rtos_struct>,
|
|
input_counter: u32,
|
|
last_pc: Option<u64>,
|
|
}
|
|
/// List of system state dumps from QemuHelpers
|
|
static mut CURRENT_SYSTEMSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![];
|
|
|
|
/// A reduced version of freertos::TCB_t
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
|
pub struct RefinedTCB {
|
|
pub task_name: String,
|
|
pub priority: u32,
|
|
pub base_priority: u32,
|
|
mutexes_held: u32,
|
|
notify_value: u32,
|
|
notify_state: u8,
|
|
}
|
|
|
|
impl Hash for RefinedTCB {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.task_name.hash(state);
|
|
self.priority.hash(state);
|
|
self.mutexes_held.hash(state);
|
|
#[cfg(not(feature = "no_hash_state"))]
|
|
self.notify_state.hash(state);
|
|
// self.notify_value.hash(state);
|
|
}
|
|
}
|
|
|
|
impl RefinedTCB {
|
|
pub fn from_tcb(input: &TCB_t) -> Self {
|
|
unsafe {
|
|
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
|
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
|
|
Self {
|
|
task_name: name,
|
|
priority: input.uxPriority,
|
|
base_priority: input.uxBasePriority,
|
|
mutexes_held: input.uxMutexesHeld,
|
|
notify_value: input.ulNotifiedValue[0],
|
|
notify_state: input.ucNotifyState[0],
|
|
}
|
|
}
|
|
}
|
|
pub fn from_tcb_owned(input: TCB_t) -> Self {
|
|
unsafe {
|
|
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
|
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
|
|
Self {
|
|
task_name: name,
|
|
priority: input.uxPriority,
|
|
base_priority: input.uxBasePriority,
|
|
mutexes_held: input.uxMutexesHeld,
|
|
notify_value: input.ulNotifiedValue[0],
|
|
notify_state: input.ucNotifyState[0],
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Refined information about the states an execution transitioned between
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
pub struct RefinedFreeRTOSSystemState {
|
|
pub start_tick: u64,
|
|
pub end_tick: u64,
|
|
last_pc: Option<u64>,
|
|
input_counter: u32,
|
|
pub current_task: RefinedTCB,
|
|
ready_list_after: Vec<RefinedTCB>,
|
|
}
|
|
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.last_pc == other.last_pc
|
|
}
|
|
}
|
|
|
|
impl Hash for RefinedFreeRTOSSystemState {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.current_task.hash(state);
|
|
self.ready_list_after.hash(state);
|
|
// self.last_pc.hash(state);
|
|
}
|
|
}
|
|
impl RefinedFreeRTOSSystemState {
|
|
fn get_time(&self) -> u64 {
|
|
self.end_tick-self.start_tick
|
|
}
|
|
}
|
|
|
|
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
pub struct FreeRTOSSystemStateMetadata {
|
|
pub inner: Vec<RefinedFreeRTOSSystemState>,
|
|
trace_length: usize,
|
|
indices: Vec<usize>, // Hashed enumeration of States
|
|
tcref: isize,
|
|
}
|
|
impl FreeRTOSSystemStateMetadata {
|
|
pub fn new(inner: Vec<RefinedFreeRTOSSystemState>) -> Self{
|
|
let tmp = inner.iter().enumerate().map(|x| compute_hash(x) as usize).collect();
|
|
Self {trace_length: inner.len(), inner: inner, indices: tmp, tcref: 0}
|
|
}
|
|
}
|
|
pub fn compute_hash<T>(obj: T) -> u64
|
|
where
|
|
T: Hash
|
|
{
|
|
let mut s = DefaultHasher::new();
|
|
obj.hash(&mut s);
|
|
s.finish()
|
|
}
|
|
|
|
impl AsSlice for FreeRTOSSystemStateMetadata {
|
|
/// Convert the slice of system-states to a slice of hashes over enumerated states
|
|
fn as_slice(&self) -> &[usize] {
|
|
self.indices.as_slice()
|
|
}
|
|
|
|
type Entry = usize;
|
|
}
|
|
|
|
impl HasRefCnt for FreeRTOSSystemStateMetadata {
|
|
fn refcnt(&self) -> isize {
|
|
self.tcref
|
|
}
|
|
|
|
fn refcnt_mut(&mut self) -> &mut isize {
|
|
&mut self.tcref
|
|
}
|
|
}
|
|
|
|
libafl::impl_serdeany!(FreeRTOSSystemStateMetadata);
|