2023-06-02 10:00:13 +02:00

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);