Merge branch 'main' into vh

This commit is contained in:
van Hauser 2020-12-20 16:40:41 +01:00 committed by GitHub
commit bd4181e3a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 855 additions and 370 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "fuzzers/qemufuzzer/qemu-fuzz"]
path = fuzzers/qemufuzzer/qemu-fuzz
url = git@github.com:AFLplusplus/qemu-fuzz.git

View File

@ -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

View File

@ -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>,
{

View File

@ -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;
}

View File

@ -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 {

View File

@ -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];

View File

@ -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))
}
}

View File

@ -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)]

View File

@ -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) },

View File

@ -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 =

View File

@ -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

@ -0,0 +1 @@
Subproject commit 6f719f6aedc9c199d7b99ef42c532a9a20605ff3

View File

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