Merge branch 'main' into vh
This commit is contained in:
commit
bd4181e3a9
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "fuzzers/qemufuzzer/qemu-fuzz"]
|
||||
path = fuzzers/qemufuzzer/qemu-fuzz
|
||||
url = git@github.com:AFLplusplus/qemu-fuzz.git
|
@ -40,3 +40,4 @@ serde = { version = "1.0", default-features = false, features = ["alloc"] } # se
|
||||
erased-serde = "0.3.12"
|
||||
postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat
|
||||
static_assertions = "1.1.0"
|
||||
#TODO: for llmp brotli = { version = "3.3.0", default-features = false } # brotli compression
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,5 @@
|
||||
// TODO: llmp can be no_std, if we abstract away page creation
|
||||
#[cfg(feature = "std")]
|
||||
pub mod llmp;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod shmem_translated;
|
||||
pub mod shmem;
|
||||
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
@ -10,9 +7,13 @@ use core::time::Duration;
|
||||
use core::{marker::PhantomData, time};
|
||||
#[cfg(feature = "std")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use shmem::AflShmem;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use self::llmp::Tag;
|
||||
use self::{
|
||||
llmp::{LlmpClient, Tag},
|
||||
shmem::ShMem,
|
||||
};
|
||||
use crate::corpus::Corpus;
|
||||
use crate::executors::Executor;
|
||||
use crate::feedbacks::FeedbacksTuple;
|
||||
@ -708,8 +709,7 @@ const _LLMP_TAG_EVENT_TO_BROKER: llmp::Tag = 0x2B80438;
|
||||
/// Handle in both
|
||||
const LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub struct LlmpEventManager<C, E, OT, FT, I, R, ST>
|
||||
pub struct LlmpEventManager<C, E, OT, FT, I, R, SH, ST>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
@ -717,16 +717,16 @@ where
|
||||
FT: FeedbacksTuple<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
SH: ShMem,
|
||||
ST: Stats,
|
||||
//CE: CustomEvent<I>,
|
||||
{
|
||||
llmp: llmp::LlmpConnection,
|
||||
llmp: llmp::LlmpConnection<SH>,
|
||||
stats: ST,
|
||||
phantom: PhantomData<(C, E, OT, FT, I, R)>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<C, E, OT, FT, I, R, ST> LlmpEventManager<C, E, OT, FT, I, R, ST>
|
||||
impl<C, E, OT, FT, I, R, ST> LlmpEventManager<C, E, OT, FT, I, R, AflShmem, ST>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
@ -736,25 +736,55 @@ where
|
||||
R: Rand,
|
||||
ST: Stats,
|
||||
{
|
||||
#[cfg(feature = "std")]
|
||||
/// Create llmp on a port
|
||||
/// If the port is not yet bound, it will act as broker
|
||||
/// Else, it will act as client.
|
||||
pub fn new_on_port_std(stats: ST) -> Result<Self, AflError> {
|
||||
Ok(Self {
|
||||
llmp: llmp::LlmpConnection::on_port(port)?,
|
||||
stats: stats,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, E, OT, FT, I, R, SH, ST> LlmpEventManager<C, E, OT, FT, I, R, SH, ST>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
SH: ShMem,
|
||||
ST: Stats,
|
||||
{
|
||||
#[cfg(feature = "std")]
|
||||
/// Create llmp on a port
|
||||
/// If the port is not yet bound, it will act as broker
|
||||
/// Else, it will act as client.
|
||||
pub fn new_on_port(port: u16, stats: ST) -> Result<Self, AflError> {
|
||||
let mgr = Self {
|
||||
Ok(Self {
|
||||
llmp: llmp::LlmpConnection::on_port(port)?,
|
||||
stats: stats,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
Ok(mgr)
|
||||
})
|
||||
}
|
||||
|
||||
/// A client on an existing map
|
||||
pub fn for_client(client: LlmpClient<SH>, stats: ST) -> Self {
|
||||
Self {
|
||||
llmp: llmp::LlmpConnection::IsClient { client },
|
||||
stats,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns if we are the broker
|
||||
pub fn is_broker(&self) -> bool {
|
||||
match self.llmp {
|
||||
llmp::LlmpConnection::IsBroker {
|
||||
broker: _,
|
||||
listener_thread: _,
|
||||
} => true,
|
||||
llmp::LlmpConnection::IsBroker { broker: _ } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -762,10 +792,7 @@ where
|
||||
/// Run forever in the broker
|
||||
pub fn broker_loop(&mut self) -> Result<(), AflError> {
|
||||
match &mut self.llmp {
|
||||
llmp::LlmpConnection::IsBroker {
|
||||
broker,
|
||||
listener_thread: _,
|
||||
} => {
|
||||
llmp::LlmpConnection::IsBroker { broker } => {
|
||||
let stats = &mut self.stats;
|
||||
broker.loop_forever(
|
||||
&mut |sender_id: u32, tag: Tag, msg: &[u8]| {
|
||||
@ -803,8 +830,8 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<C, E, OT, FT, I, R, ST> EventManager<C, E, OT, FT, I, R>
|
||||
for LlmpEventManager<C, E, OT, FT, I, R, ST>
|
||||
impl<C, E, OT, FT, I, R, SH, ST> EventManager<C, E, OT, FT, I, R>
|
||||
for LlmpEventManager<C, E, OT, FT, I, R, SH, ST>
|
||||
where
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
@ -812,6 +839,7 @@ where
|
||||
OT: ObserversTuple,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
SH: ShMem,
|
||||
ST: Stats,
|
||||
//CE: CustomEvent<I>,
|
||||
{
|
||||
|
@ -1,18 +1,30 @@
|
||||
//! A generic sharememory region to be used by any functions (queues or feedbacks
|
||||
// too.)
|
||||
|
||||
use alloc::string::String;
|
||||
#[cfg(feature = "std")]
|
||||
use core::{mem::size_of, slice};
|
||||
#[cfg(feature = "std")]
|
||||
use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_ushort, c_void};
|
||||
use std::{ffi::CStr, mem::size_of};
|
||||
#[cfg(feature = "std")]
|
||||
use std::{env, ffi::CStr};
|
||||
|
||||
use crate::AflError;
|
||||
|
||||
extern "C" {
|
||||
#[cfg(feature = "std")]
|
||||
fn snprintf(_: *mut c_char, _: c_ulong, _: *const c_char, _: ...) -> c_int;
|
||||
#[cfg(feature = "std")]
|
||||
fn strncpy(_: *mut c_char, _: *const c_char, _: c_ulong) -> *mut c_char;
|
||||
//fn strlen(_: *const c_char) -> c_ulong;
|
||||
#[cfg(feature = "std")]
|
||||
fn shmctl(__shmid: c_int, __cmd: c_int, __buf: *mut shmid_ds) -> c_int;
|
||||
#[cfg(feature = "std")]
|
||||
fn shmget(__key: c_int, __size: c_ulong, __shmflg: c_int) -> c_int;
|
||||
#[cfg(feature = "std")]
|
||||
fn shmat(__shmid: c_int, __shmaddr: *const c_void, __shmflg: c_int) -> *mut c_void;
|
||||
//fn strtol(_: *const c_char, _: *mut *mut c_char, _: c_int) -> c_long;
|
||||
fn setenv(__name: *const c_char, __value: *const c_char, __replace: c_int) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
struct ipc_perm {
|
||||
@ -29,6 +41,7 @@ struct ipc_perm {
|
||||
pub __glibc_reserved2: c_ulong,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
struct shmid_ds {
|
||||
@ -43,22 +56,102 @@ struct shmid_ds {
|
||||
pub __glibc_reserved4: c_ulong,
|
||||
pub __glibc_reserved5: c_ulong,
|
||||
}
|
||||
const AFL_RET_ERRNO: c_uint = 12;
|
||||
const AFL_RET_NULL_PTR: c_uint = 11;
|
||||
const AFL_RET_SUCCESS: c_uint = 0;
|
||||
|
||||
// A generic sharememory region to be used by any functions (queues or feedbacks
|
||||
// too.)
|
||||
/// A Shared map
|
||||
pub trait ShMem: Sized {
|
||||
/// Creates a nes variable with the given name, strigified to 20 bytes.
|
||||
fn existing_from_shm_slice(map_str_bytes: &[u8; 20], map_size: usize)
|
||||
-> Result<Self, AflError>;
|
||||
|
||||
/// Initialize from a shm_str with fixed len of 20
|
||||
fn existing_from_shm_str(shm_str: &str, map_size: usize) -> Result<Self, AflError> {
|
||||
let mut slice: [u8; 20] = [0; 20];
|
||||
for (i, val) in shm_str.as_bytes().iter().enumerate() {
|
||||
slice[i] = *val;
|
||||
}
|
||||
Self::existing_from_shm_slice(&slice, map_size)
|
||||
}
|
||||
|
||||
/// Creates a new map with the given size
|
||||
fn new_map(map_size: usize) -> Result<Self, AflError>;
|
||||
|
||||
/// The string to identify this shm
|
||||
fn shm_str(&self) -> String {
|
||||
let bytes = self.shm_slice();
|
||||
let eof_pos = bytes.iter().position(|&c| c == 0).unwrap();
|
||||
alloc::str::from_utf8(&bytes[..eof_pos])
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Let's just fix this to a large enough buf
|
||||
fn shm_slice(&self) -> &[u8; 20];
|
||||
|
||||
/// The actual shared map, in memory
|
||||
fn map(&self) -> &[u8];
|
||||
|
||||
/// The actual shared map, mutable
|
||||
fn map_mut(&mut self) -> &mut [u8];
|
||||
|
||||
/// Write this map's config to env
|
||||
#[cfg(feature = "std")]
|
||||
fn write_to_env(&self, env_name: &str) -> Result<(), AflError> {
|
||||
let map_size = self.map().len();
|
||||
let map_size_env = format!("{}_SIZE", env_name);
|
||||
env::set_var(env_name, self.shm_str());
|
||||
env::set_var(map_size_env, format!("{}", map_size));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reads an existing map config from env vars, then maps it
|
||||
#[cfg(feature = "std")]
|
||||
fn existing_from_env(env_name: &str) -> Result<Self, AflError> {
|
||||
let map_shm_str = env::var(env_name)?;
|
||||
let map_size = str::parse::<usize>(&env::var(format!("{}_SIZE", env_name))?)?;
|
||||
Self::existing_from_shm_str(&map_shm_str, map_size)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AflShmem {
|
||||
pub shm_str: [u8; 20],
|
||||
pub shm_id: c_int,
|
||||
pub map: *mut c_uchar,
|
||||
pub map: *mut u8,
|
||||
pub map_size: usize,
|
||||
}
|
||||
|
||||
/// Deinit on drop
|
||||
#[cfg(feature = "std")]
|
||||
impl ShMem for AflShmem {
|
||||
fn existing_from_shm_slice(
|
||||
map_str_bytes: &[u8; 20],
|
||||
map_size: usize,
|
||||
) -> Result<Self, AflError> {
|
||||
unsafe {
|
||||
let str_bytes = map_str_bytes as *const [u8; 20] as *const libc::c_char;
|
||||
Self::from_str(CStr::from_ptr(str_bytes), map_size)
|
||||
}
|
||||
}
|
||||
|
||||
fn new_map(map_size: usize) -> Result<Self, AflError> {
|
||||
Self::new(map_size)
|
||||
}
|
||||
|
||||
fn shm_slice(&self) -> &[u8; 20] {
|
||||
&self.shm_str
|
||||
}
|
||||
|
||||
fn map(&self) -> &[u8] {
|
||||
unsafe { slice::from_raw_parts(self.map, self.map_size) }
|
||||
}
|
||||
|
||||
fn map_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Deinit sharedmaps on drop
|
||||
impl Drop for AflShmem {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
@ -67,6 +160,7 @@ impl Drop for AflShmem {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Create an uninitialized shmap
|
||||
const fn afl_shmem_unitialized() -> AflShmem {
|
||||
AflShmem {
|
||||
@ -77,6 +171,7 @@ const fn afl_shmem_unitialized() -> AflShmem {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl AflShmem {
|
||||
pub fn from_str(shm_str: &CStr, map_size: usize) -> Result<Self, AflError> {
|
||||
let mut ret = afl_shmem_unitialized();
|
||||
@ -91,14 +186,6 @@ impl AflShmem {
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a shared map with a fixed byte array of 20
|
||||
pub fn from_name_slice(shm_str: &[u8; 20], map_size: usize) -> Result<Self, AflError> {
|
||||
unsafe {
|
||||
let str_bytes = shm_str as *const [u8; 20] as *const libc::c_char;
|
||||
Self::from_str(CStr::from_ptr(str_bytes), map_size)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(map_size: usize) -> Result<Self, AflError> {
|
||||
let mut ret = afl_shmem_unitialized();
|
||||
let map = unsafe { afl_shmem_init(&mut ret, map_size) };
|
||||
@ -111,21 +198,9 @@ impl AflShmem {
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets this shm id as env variable with the given name
|
||||
/// Also write the map size as name#_SIZE env
|
||||
pub fn to_env_var(&self, env_name: &CStr) -> Result<(), AflError> {
|
||||
if unsafe { afl_shmem_to_env_var(&self, env_name) } == AFL_RET_SUCCESS {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AflError::Unknown(format!(
|
||||
"Could not set env variable {:?}",
|
||||
env_name
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Deinitialize this shmem instance
|
||||
unsafe fn afl_shmem_deinit(shm: *mut AflShmem) {
|
||||
if shm.is_null() || (*shm).map.is_null() {
|
||||
@ -138,6 +213,7 @@ unsafe fn afl_shmem_deinit(shm: *mut AflShmem) {
|
||||
(*shm).map = 0 as *mut c_uchar;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Functions to create Shared memory region, for observation channels and
|
||||
/// opening inputs and stuff.
|
||||
unsafe fn afl_shmem_init(shm: *mut AflShmem, map_size: usize) -> *mut c_uchar {
|
||||
@ -171,6 +247,7 @@ unsafe fn afl_shmem_init(shm: *mut AflShmem, map_size: usize) -> *mut c_uchar {
|
||||
return (*shm).map;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Uses a shmap id string to open a shared map
|
||||
unsafe fn afl_shmem_by_str(shm: *mut AflShmem, shm_str: &CStr, map_size: usize) -> *mut c_uchar {
|
||||
if shm.is_null() || shm_str.to_bytes().len() == 0 || map_size == 0 {
|
||||
@ -198,43 +275,24 @@ unsafe fn afl_shmem_by_str(shm: *mut AflShmem, shm_str: &CStr, map_size: usize)
|
||||
return (*shm).map;
|
||||
}
|
||||
|
||||
/// Write sharedmap as env var and the size as name#_SIZE
|
||||
unsafe fn afl_shmem_to_env_var(shmem: &AflShmem, env_name: &CStr) -> c_uint {
|
||||
let env_len = env_name.to_bytes().len();
|
||||
if env_len == 0 || env_len > 200 || (*shmem).shm_str[0 as c_int as usize] == 0 {
|
||||
return AFL_RET_NULL_PTR;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{AflShmem, ShMem};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_str_conversions() {
|
||||
let mut shm_str: [u8; 20] = [0; 20];
|
||||
shm_str[0] = 'A' as u8;
|
||||
shm_str[1] = 'B' as u8;
|
||||
shm_str[2] = 'C' as u8;
|
||||
let faux_shmem = AflShmem {
|
||||
shm_id: 0,
|
||||
shm_str,
|
||||
map: 0 as *mut u8,
|
||||
map_size: 20,
|
||||
};
|
||||
let str = faux_shmem.shm_str();
|
||||
assert_eq!(str, "ABC");
|
||||
}
|
||||
let mut shm_str: [c_char; 256] = [0; 256];
|
||||
snprintf(
|
||||
shm_str.as_mut_ptr(),
|
||||
size_of::<[c_char; 256]>() as c_ulong,
|
||||
b"%d\x00" as *const u8 as *const c_char,
|
||||
(*shmem).shm_id,
|
||||
);
|
||||
if setenv(
|
||||
env_name.as_ptr() as *const c_char,
|
||||
shm_str.as_mut_ptr(),
|
||||
1 as c_int,
|
||||
) < 0 as c_int
|
||||
{
|
||||
return AFL_RET_ERRNO;
|
||||
}
|
||||
/* Write the size to env, too */
|
||||
let mut size_env_name: [c_char; 256] = [0; 256];
|
||||
snprintf(
|
||||
size_env_name.as_mut_ptr(),
|
||||
size_of::<[c_char; 256]>() as c_ulong,
|
||||
b"%s_SIZE\x00" as *const u8 as *const c_char,
|
||||
env_name,
|
||||
);
|
||||
snprintf(
|
||||
shm_str.as_mut_ptr(),
|
||||
size_of::<[c_char; 256]>() as c_ulong,
|
||||
b"%d\x00" as *const u8 as *const c_char,
|
||||
(*shmem).shm_id,
|
||||
);
|
||||
if setenv(size_env_name.as_mut_ptr(), shm_str.as_mut_ptr(), 1 as c_int) < 0 as c_int {
|
||||
return AFL_RET_ERRNO;
|
||||
}
|
||||
return AFL_RET_SUCCESS;
|
||||
}
|
@ -7,9 +7,9 @@ use crate::observers::ObserversTuple;
|
||||
use crate::tuples::Named;
|
||||
use crate::AflError;
|
||||
|
||||
/// The (unsafe) pointer to the current inmem executor, for the current run.
|
||||
/// The (unsafe) pointer to the current inmem input, for the current run.
|
||||
/// This is neede for certain non-rust side effects, as well as unix signal handling.
|
||||
static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null();
|
||||
static mut CURRENT_INPUT_PTR: *const c_void = ptr::null();
|
||||
|
||||
/// The inmem executor harness
|
||||
type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
|
||||
@ -34,11 +34,11 @@ where
|
||||
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> {
|
||||
let bytes = input.target_bytes();
|
||||
unsafe {
|
||||
CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor<I, OT> as *const c_void;
|
||||
CURRENT_INPUT_PTR = input as *const _ as *const c_void;
|
||||
}
|
||||
let ret = (self.harness)(self, bytes.as_slice());
|
||||
unsafe {
|
||||
CURRENT_INMEMORY_EXECUTOR_PTR = ptr::null();
|
||||
CURRENT_INPUT_PTR = ptr::null();
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
@ -76,10 +76,6 @@ where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
pub fn new(name: &'static str, harness_fn: HarnessFunction<I>, observers: OT) -> Self {
|
||||
#[cfg(feature = "std")]
|
||||
unsafe {
|
||||
os_signals::setup_crash_handlers::<I>();
|
||||
}
|
||||
Self {
|
||||
harness: harness_fn,
|
||||
observers: observers,
|
||||
@ -101,23 +97,35 @@ pub mod unix_signals {
|
||||
use std::io::{stdout, Write}; // Write brings flush() into scope
|
||||
use std::{mem, process, ptr};
|
||||
|
||||
use crate::executors::inmemory::CURRENT_INMEMORY_EXECUTOR_PTR;
|
||||
use crate::corpus::Corpus;
|
||||
use crate::events::EventManager;
|
||||
use crate::executors::inmemory::CURRENT_INPUT_PTR;
|
||||
use crate::executors::Executor;
|
||||
use crate::feedbacks::FeedbacksTuple;
|
||||
use crate::inputs::Input;
|
||||
use crate::observers::ObserversTuple;
|
||||
use crate::utils::Rand;
|
||||
|
||||
pub extern "C" fn libaflrs_executor_inmem_handle_crash<I>(
|
||||
static mut EVENT_MANAGER_PTR: *mut c_void = ptr::null_mut();
|
||||
|
||||
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_crash<EM, C, E, OT, FT, I, R>(
|
||||
_sig: c_int,
|
||||
info: siginfo_t,
|
||||
_void: c_void,
|
||||
) where
|
||||
EM: EventManager<C, E, OT, FT, I, R>,
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
unsafe {
|
||||
if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() {
|
||||
println!(
|
||||
"We died accessing addr {}, but are not in client...",
|
||||
info.si_addr() as usize
|
||||
);
|
||||
}
|
||||
if CURRENT_INPUT_PTR == ptr::null() {
|
||||
println!(
|
||||
"We died accessing addr {}, but are not in client...",
|
||||
info.si_addr() as usize
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@ -125,39 +133,63 @@ pub mod unix_signals {
|
||||
#[cfg(feature = "std")]
|
||||
let _ = stdout().flush();
|
||||
|
||||
// TODO: LLMP
|
||||
let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap();
|
||||
let manager = (EVENT_MANAGER_PTR as *mut EM).as_mut().unwrap();
|
||||
|
||||
manager.crash(input).expect("Error in sending Crash event");
|
||||
|
||||
std::process::exit(139);
|
||||
}
|
||||
|
||||
pub extern "C" fn libaflrs_executor_inmem_handle_timeout<I>(
|
||||
pub unsafe extern "C" fn libaflrs_executor_inmem_handle_timeout<EM, C, E, OT, FT, I, R>(
|
||||
_sig: c_int,
|
||||
_info: siginfo_t,
|
||||
_void: c_void,
|
||||
) where
|
||||
EM: EventManager<C, E, OT, FT, I, R>,
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
dbg!("TIMEOUT/SIGUSR2 received");
|
||||
unsafe {
|
||||
if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() {
|
||||
dbg!("TIMEOUT or SIGUSR2 happened, but currently not fuzzing.");
|
||||
return;
|
||||
}
|
||||
if CURRENT_INPUT_PTR == ptr::null() {
|
||||
dbg!("TIMEOUT or SIGUSR2 happened, but currently not fuzzing.");
|
||||
return;
|
||||
}
|
||||
|
||||
let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap();
|
||||
let manager = (EVENT_MANAGER_PTR as *mut EM).as_mut().unwrap();
|
||||
|
||||
manager
|
||||
.timeout(input)
|
||||
.expect("Error in sending Timeout event");
|
||||
|
||||
// TODO: send LLMP.
|
||||
println!("Timeout in fuzz run.");
|
||||
let _ = stdout().flush();
|
||||
process::abort();
|
||||
}
|
||||
|
||||
pub unsafe fn setup_crash_handlers<I>()
|
||||
// TODO clearly state that manager should be static (maybe put the 'static lifetime?)
|
||||
pub unsafe fn setup_crash_handlers<EM, C, E, OT, FT, I, R>(manager: &mut EM)
|
||||
where
|
||||
EM: EventManager<C, E, OT, FT, I, R>,
|
||||
C: Corpus<I, R>,
|
||||
E: Executor<I>,
|
||||
OT: ObserversTuple,
|
||||
FT: FeedbacksTuple<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
{
|
||||
EVENT_MANAGER_PTR = manager as *mut _ as *mut c_void;
|
||||
|
||||
let mut sa: sigaction = mem::zeroed();
|
||||
libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
|
||||
sa.sa_flags = SA_NODEFER | SA_SIGINFO;
|
||||
sa.sa_sigaction = libaflrs_executor_inmem_handle_crash::<I> as usize;
|
||||
sa.sa_sigaction = libaflrs_executor_inmem_handle_crash::<EM, C, E, OT, FT, I, R> as usize;
|
||||
for (sig, msg) in &[
|
||||
(SIGSEGV, "segfault"),
|
||||
(SIGBUS, "sigbus"),
|
||||
@ -171,19 +203,19 @@ pub mod unix_signals {
|
||||
}
|
||||
}
|
||||
|
||||
sa.sa_sigaction = libaflrs_executor_inmem_handle_timeout::<I> as usize;
|
||||
sa.sa_sigaction = libaflrs_executor_inmem_handle_timeout::<EM, C, E, OT, FT, I, R> as usize;
|
||||
if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 {
|
||||
panic!("Could not set up sigusr2 handler for timeouts");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(unix)]
|
||||
use unix_signals as os_signals;
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(not(unix))]
|
||||
compile_error!("InMemoryExecutor not yet supported on this OS");
|
||||
//#[cfg(feature = "std")]
|
||||
//#[cfg(unix)]
|
||||
//use unix_signals as os_signals;
|
||||
//#[cfg(feature = "std")]
|
||||
//#[cfg(not(unix))]
|
||||
//compile_error!("InMemoryExecutor not yet supported on this OS");
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -190,7 +190,7 @@ where
|
||||
let mut interesting = 0;
|
||||
// TODO optimize
|
||||
let observer = observers.match_name_type::<O>(&self.name).unwrap();
|
||||
let size = observer.map().len();
|
||||
let size = observer.usable_count();
|
||||
for i in 0..size {
|
||||
let history = self.history_map[i];
|
||||
let item = observer.map()[i];
|
||||
|
@ -6,7 +6,6 @@ Welcome to libAFL
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
|
||||
@ -28,7 +27,7 @@ pub mod utils;
|
||||
use alloc::string::String;
|
||||
use core::fmt;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io;
|
||||
use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error};
|
||||
|
||||
/// Main error struct for AFL
|
||||
#[derive(Debug)]
|
||||
@ -50,6 +49,8 @@ pub enum AflError {
|
||||
NotImplemented(String),
|
||||
/// You're holding it wrong
|
||||
IllegalState(String),
|
||||
/// The argument passed to this method or function is not valid
|
||||
IllegalArgument(String),
|
||||
/// Something else happened
|
||||
Unknown(String),
|
||||
}
|
||||
@ -68,6 +69,7 @@ impl fmt::Display for AflError {
|
||||
}
|
||||
Self::NotImplemented(s) => write!(f, "Not implemented: {0}", &s),
|
||||
Self::IllegalState(s) => write!(f, "Illegal state: {0}", &s),
|
||||
Self::IllegalArgument(s) => write!(f, "Illegal argument: {0}", &s),
|
||||
Self::Unknown(s) => write!(f, "Unknown error: {0}", &s),
|
||||
}
|
||||
}
|
||||
@ -88,10 +90,23 @@ impl From<io::Error> for AflError {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
#[cfg(feature = "std")]
|
||||
impl From<FromUtf8Error> for AflError {
|
||||
fn from(err: FromUtf8Error) -> Self {
|
||||
Self::Unknown(format!("Could not convert byte to utf-8: {:?}", err))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<VarError> for AflError {
|
||||
fn from(err: VarError) -> Self {
|
||||
Self::Empty(format!("Could not get env var: {:?}", err))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<ParseIntError> for AflError {
|
||||
fn from(err: ParseIntError) -> Self {
|
||||
Self::Unknown(format!("Failed to parse Int: {:?}", err))
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::serde_anymap::ArrayMut;
|
||||
use crate::serde_anymap::{ArrayMut, Cptr};
|
||||
use crate::tuples::{MatchNameAndType, MatchType, Named, TupleList};
|
||||
use crate::AflError;
|
||||
|
||||
@ -94,6 +94,11 @@ where
|
||||
/// Get the map (mutable)
|
||||
fn map_mut(&mut self) -> &mut [T];
|
||||
|
||||
/// Get the number of usable entries in the map (all by default)
|
||||
fn usable_count(&self) -> usize {
|
||||
self.map().len()
|
||||
}
|
||||
|
||||
/// Get the initial value for reset()
|
||||
fn initial(&self) -> T;
|
||||
|
||||
@ -108,7 +113,8 @@ where
|
||||
fn reset_map(&mut self) -> Result<(), AflError> {
|
||||
// Normal memset, see https://rust.godbolt.org/z/Trs5hv
|
||||
let initial = self.initial();
|
||||
for i in self.map_mut().iter_mut() {
|
||||
let cnt = self.usable_count();
|
||||
for i in self.map_mut()[0..cnt].iter_mut() {
|
||||
*i = initial;
|
||||
}
|
||||
Ok(())
|
||||
@ -206,6 +212,107 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||
pub struct VariableMapObserver<T>
|
||||
where
|
||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
map: ArrayMut<T>,
|
||||
size: Cptr<usize>,
|
||||
initial: T,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl<T> Observer for VariableMapObserver<T>
|
||||
where
|
||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
#[inline]
|
||||
fn reset(&mut self) -> Result<(), AflError> {
|
||||
self.reset_map()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Named for VariableMapObserver<T>
|
||||
where
|
||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
#[inline]
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MapObserver<T> for VariableMapObserver<T>
|
||||
where
|
||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
#[inline]
|
||||
fn map(&self) -> &[T] {
|
||||
self.map.as_slice()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn map_mut(&mut self) -> &mut [T] {
|
||||
self.map.as_mut_slice()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn usable_count(&self) -> usize {
|
||||
*self.size.as_ref()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn initial(&self) -> T {
|
||||
self.initial
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn initial_mut(&mut self) -> &mut T {
|
||||
&mut self.initial
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_initial(&mut self, initial: T) {
|
||||
self.initial = initial
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VariableMapObserver<T>
|
||||
where
|
||||
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
/// Creates a new MapObserver
|
||||
pub fn new(name: &'static str, map: &'static mut [T], size: &usize) -> Self {
|
||||
let initial = if map.len() > 0 { map[0] } else { T::default() };
|
||||
Self {
|
||||
map: ArrayMut::Cptr((map.as_mut_ptr(), map.len())),
|
||||
size: Cptr::Cptr(size as *const _),
|
||||
name: name.into(),
|
||||
initial,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new MapObserver from a raw pointer
|
||||
pub fn new_from_ptr(
|
||||
name: &'static str,
|
||||
map_ptr: *mut T,
|
||||
max_len: usize,
|
||||
size_ptr: *const usize,
|
||||
) -> Self {
|
||||
unsafe {
|
||||
let initial = if max_len > 0 { *map_ptr } else { T::default() };
|
||||
VariableMapObserver {
|
||||
map: ArrayMut::Cptr((map_ptr, max_len)),
|
||||
size: Cptr::Cptr(size_ptr),
|
||||
name: name.into(),
|
||||
initial,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(test)]
|
||||
|
@ -629,7 +629,84 @@ impl<'a, T: Sized> SliceMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Array<T: Sized + serde::Serialize> {
|
||||
pub enum Cptr<T: Sized> {
|
||||
Cptr(*const T),
|
||||
Owned(Box<T>),
|
||||
}
|
||||
|
||||
impl<T: Sized + serde::Serialize> serde::Serialize for Cptr<T> {
|
||||
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.as_ref().serialize(se)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T: Sized + serde::de::DeserializeOwned> Deserialize<'de> for Cptr<T>
|
||||
where
|
||||
Vec<T>: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(de: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Deserialize::deserialize(de).map(Cptr::Owned)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sized> Cptr<T> {
|
||||
pub fn as_ref(&self) -> &T {
|
||||
match self {
|
||||
Cptr::Cptr(p) => unsafe { p.as_ref().unwrap() },
|
||||
Cptr::Owned(v) => v.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CptrMut<T: Sized> {
|
||||
Cptr(*mut T),
|
||||
Owned(Box<T>),
|
||||
}
|
||||
|
||||
impl<T: Sized + serde::Serialize> serde::Serialize for CptrMut<T> {
|
||||
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.as_ref().serialize(se)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T: Sized + serde::de::DeserializeOwned> Deserialize<'de> for CptrMut<T>
|
||||
where
|
||||
Vec<T>: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(de: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Deserialize::deserialize(de).map(CptrMut::Owned)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sized> CptrMut<T> {
|
||||
pub fn as_ref(&self) -> &T {
|
||||
match self {
|
||||
CptrMut::Cptr(p) => unsafe { p.as_ref().unwrap() },
|
||||
CptrMut::Owned(b) => b.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut(&mut self) -> &mut T {
|
||||
match self {
|
||||
CptrMut::Cptr(p) => unsafe { p.as_mut().unwrap() },
|
||||
CptrMut::Owned(b) => b.as_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Array<T: Sized> {
|
||||
Cptr((*const T, usize)),
|
||||
Owned(Vec<T>),
|
||||
}
|
||||
@ -655,7 +732,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sized + serde::Serialize> Array<T> {
|
||||
impl<T: Sized> Array<T> {
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
match self {
|
||||
Array::Cptr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) },
|
||||
@ -664,7 +741,7 @@ impl<T: Sized + serde::Serialize> Array<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ArrayMut<T: Sized + serde::Serialize> {
|
||||
pub enum ArrayMut<T: Sized> {
|
||||
Cptr((*mut T, usize)),
|
||||
Owned(Vec<T>),
|
||||
}
|
||||
@ -690,7 +767,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Sized + serde::Serialize> ArrayMut<T> {
|
||||
impl<T: Sized> ArrayMut<T> {
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
match self {
|
||||
ArrayMut::Cptr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) },
|
||||
|
@ -14,6 +14,7 @@ use afl::engines::Engine;
|
||||
use afl::engines::Fuzzer;
|
||||
use afl::engines::State;
|
||||
use afl::engines::StdFuzzer;
|
||||
use afl::events::shmem::AflShmem;
|
||||
use afl::events::{LlmpEventManager, SimpleStats};
|
||||
use afl::executors::inmemory::InMemoryExecutor;
|
||||
use afl::executors::{Executor, ExitKind};
|
||||
@ -110,12 +111,13 @@ pub extern "C" fn afl_libfuzzer_main() {
|
||||
let mut corpus = InMemoryCorpus::new();
|
||||
let mut generator = RandPrintablesGenerator::new(32);
|
||||
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||
let mut mgr = LlmpEventManager::new_on_port(broker_port, stats).unwrap();
|
||||
let mut mgr = LlmpEventManager::new_on_port_std(broker_port, stats).unwrap();
|
||||
|
||||
if mgr.is_broker() {
|
||||
println!("Doing broker things.");
|
||||
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
|
||||
mgr.broker_loop().unwrap();
|
||||
}
|
||||
|
||||
println!("We're a client, let's fuzz :)");
|
||||
|
||||
let edges_observer =
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
cargo build --release
|
||||
|
||||
cd qemu
|
||||
git pull
|
||||
cd qemu-fuzz
|
||||
|
||||
git submodule update
|
||||
|
||||
./build_qemu_fuzz.sh ../target/release/libqemufuzzer.a
|
||||
|
1
fuzzers/qemufuzzer/qemu-fuzz
Submodule
1
fuzzers/qemufuzzer/qemu-fuzz
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 6f719f6aedc9c199d7b99ef42c532a9a20605ff3
|
@ -14,7 +14,7 @@ use afl::feedbacks::MaxMapFeedback;
|
||||
use afl::generators::RandPrintablesGenerator;
|
||||
use afl::mutators::scheduled::HavocBytesMutator;
|
||||
use afl::mutators::HasMaxSize;
|
||||
use afl::observers::StdMapObserver;
|
||||
use afl::observers::VariableMapObserver;
|
||||
use afl::stages::mutational::StdMutationalStage;
|
||||
use afl::tuples::tuple_list;
|
||||
use afl::utils::StdRand;
|
||||
@ -66,11 +66,10 @@ pub extern "C" fn fuzz_main_loop() {
|
||||
}
|
||||
println!("We're a client, let's fuzz :)");
|
||||
|
||||
let edges_observer = StdMapObserver::new_from_ptr(
|
||||
&NAME_COV_MAP,
|
||||
unsafe { fuzz_hitcounts_map.as_mut_ptr() },
|
||||
unsafe { fuzz_edges_id },
|
||||
);
|
||||
let edges_observer =
|
||||
VariableMapObserver::new(&NAME_COV_MAP, unsafe { &mut fuzz_hitcounts_map }, unsafe {
|
||||
&fuzz_edges_id
|
||||
});
|
||||
let edges_feedback = MaxMapFeedback::new_with_observer(&NAME_COV_MAP, &edges_observer);
|
||||
|
||||
let executor = InMemoryExecutor::new("QEMUFuzzer", harness, tuple_list!(edges_observer));
|
||||
|
Loading…
x
Reference in New Issue
Block a user