serde input

This commit is contained in:
Andrea Fioraldi 2020-12-10 15:26:47 +01:00
parent 0d3e374f17
commit 0365bdac7a
7 changed files with 48 additions and 45 deletions

View File

@ -34,4 +34,5 @@ num = "*"
xxhash-rust = { version = "0.8.0", features = ["xxh3"] } # xxh3 hashing for rust xxhash-rust = { version = "0.8.0", features = ["xxh3"] } # xxh3 hashing for rust
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
erased-serde = "0.3.12" erased-serde = "0.3.12"
postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat
bincode = "1.3.1"

View File

@ -45,6 +45,7 @@ impl TestcaseMetadataContainer {
/// An entry in the Testcase Corpus /// An entry in the Testcase Corpus
#[derive(Default, Serialize, Deserialize)] #[derive(Default, Serialize, Deserialize)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct Testcase<I> pub struct Testcase<I>
where where
I: Input, I: Input,

View File

@ -68,6 +68,7 @@ where
/// Events sent around in the library /// Events sent around in the library
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub enum Event<'a, C, E, I, R> pub enum Event<'a, C, E, I, R>
where where
C: Corpus<I, R>, C: Corpus<I, R>,

View File

@ -2,7 +2,7 @@ use core::ffi::c_void;
use core::ptr; use core::ptr;
use crate::executors::{Executor, ExitKind}; use crate::executors::{Executor, ExitKind};
use crate::inputs::Input; use crate::inputs::{HasTargetBytes, Input};
use crate::observers::observer_serde::NamedSerdeAnyMap; use crate::observers::observer_serde::NamedSerdeAnyMap;
use crate::AflError; use crate::AflError;
@ -16,7 +16,7 @@ type HarnessFunction<I> = fn(&dyn Executor<I>, &[u8]) -> ExitKind;
/// The inmem executor simply calls a target function, then returns afterwards. /// The inmem executor simply calls a target function, then returns afterwards.
pub struct InMemoryExecutor<I> pub struct InMemoryExecutor<I>
where where
I: Input, I: Input + HasTargetBytes,
{ {
harness: HarnessFunction<I>, harness: HarnessFunction<I>,
observers: NamedSerdeAnyMap, observers: NamedSerdeAnyMap,
@ -24,14 +24,14 @@ where
impl<I> Executor<I> for InMemoryExecutor<I> impl<I> Executor<I> for InMemoryExecutor<I>
where where
I: Input, I: Input + HasTargetBytes,
{ {
fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> { fn run_target(&mut self, input: &I) -> Result<ExitKind, AflError> {
let bytes = input.serialize()?; let bytes = input.target_bytes();
unsafe { unsafe {
CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor<I> as *const c_void; CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor<I> as *const c_void;
} }
let ret = (self.harness)(self, bytes); let ret = (self.harness)(self, bytes.as_slice());
unsafe { unsafe {
CURRENT_INMEMORY_EXECUTOR_PTR = ptr::null(); CURRENT_INMEMORY_EXECUTOR_PTR = ptr::null();
} }
@ -49,7 +49,7 @@ where
impl<I> InMemoryExecutor<I> impl<I> InMemoryExecutor<I>
where where
I: Input, I: Input + HasTargetBytes,
{ {
pub fn new(harness_fn: HarnessFunction<I>) -> Self { pub fn new(harness_fn: HarnessFunction<I>) -> Self {
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -165,17 +165,17 @@ mod tests {
use crate::executors::inmemory::InMemoryExecutor; use crate::executors::inmemory::InMemoryExecutor;
use crate::executors::{Executor, ExitKind}; use crate::executors::{Executor, ExitKind};
use crate::inputs::Input; use crate::inputs::{HasTargetBytes, Input, TargetBytes};
use crate::AflError; use crate::AflError;
#[derive(Clone)] use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize)]
struct NopInput {} struct NopInput {}
impl Input for NopInput { impl Input for NopInput {}
fn serialize(&self) -> Result<&[u8], AflError> { impl HasTargetBytes for NopInput {
Ok("NOP".as_bytes()) fn target_bytes(&self) -> TargetBytes {
} TargetBytes::Owned(vec![0])
fn deserialize(_buf: &[u8]) -> Result<Self, AflError> {
Ok(Self {})
} }
} }

View File

@ -3,27 +3,17 @@ use alloc::rc::Rc;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::cell::RefCell; use core::cell::RefCell;
use core::convert::From; use core::convert::From;
use serde::{Deserialize, Serialize};
use crate::inputs::{HasBytesVec, HasTargetBytes, Input}; use crate::inputs::{HasBytesVec, HasTargetBytes, Input, TargetBytes};
use crate::AflError;
/// A bytes input is the basic input /// A bytes input is the basic input
#[derive(Clone, Debug, Default)] #[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct BytesInput { pub struct BytesInput {
bytes: Vec<u8>, bytes: Vec<u8>,
} }
impl Input for BytesInput { impl Input for BytesInput {}
fn serialize(&self) -> Result<&[u8], AflError> {
Ok(&self.bytes)
}
fn deserialize(buf: &[u8]) -> Result<Self, AflError> {
Ok(Self {
bytes: buf.to_owned(),
})
}
}
/// Rc Ref-cell from Input /// Rc Ref-cell from Input
impl Into<Rc<RefCell<Self>>> for BytesInput { impl Into<Rc<RefCell<Self>>> for BytesInput {
@ -42,8 +32,8 @@ impl HasBytesVec for BytesInput {
} }
impl HasTargetBytes for BytesInput { impl HasTargetBytes for BytesInput {
fn target_bytes(&self) -> &[u8] { fn target_bytes(&self) -> TargetBytes {
&self.bytes TargetBytes::Ref(&self.bytes)
} }
} }

View File

@ -14,7 +14,7 @@ use std::path::Path;
use crate::AflError; use crate::AflError;
/// An input for the target /// An input for the target
pub trait Input: Clone { pub trait Input: Clone + serde::Serialize + serde::de::DeserializeOwned {
#[cfg(feature = "std")] #[cfg(feature = "std")]
/// Write this input to the file /// Write this input to the file
fn to_file<P>(&self, path: P) -> Result<(), AflError> fn to_file<P>(&self, path: P) -> Result<(), AflError>
@ -22,7 +22,9 @@ pub trait Input: Clone {
P: AsRef<Path>, P: AsRef<Path>,
{ {
let mut file = File::create(path)?; let mut file = File::create(path)?;
file.write_all(self.serialize()?)?; let v = bincode::serialize(&self)
.map_err(|_| AflError::Unknown("cannot serialize".to_string()))?;
file.write_all(v.as_slice())?;
Ok(()) Ok(())
} }
@ -42,7 +44,8 @@ where {
let mut file = File::open(path).map_err(AflError::File)?; let mut file = File::open(path).map_err(AflError::File)?;
let mut bytes: Vec<u8> = vec![]; let mut bytes: Vec<u8> = vec![];
file.read_to_end(&mut bytes).map_err(AflError::File)?; file.read_to_end(&mut bytes).map_err(AflError::File)?;
Self::deserialize(&bytes) bincode::deserialize::<Self>(&bytes)
.map_err(|_| AflError::Unknown("cannot deserialize".to_string()))
} }
/// Write this input to the file /// Write this input to the file
@ -51,22 +54,28 @@ where {
where { where {
Err(AflError::NotImplemented("Not suppored in no_std".into())) Err(AflError::NotImplemented("Not suppored in no_std".into()))
} }
/// Serialize this input, for later deserialization.
/// This is not necessarily the representation to be used by the target
/// Instead, to get bytes for a target, use [HasTargetBytes](afl::inputs::HasTargetBytes).
fn serialize(&self) -> Result<&[u8], AflError>;
/// Deserialize this input, using the bytes serialized before.
fn deserialize(buf: &[u8]) -> Result<Self, AflError>;
} }
/// Can be serialized to a bytes representation pub enum TargetBytes<'a> {
Ref(&'a [u8]),
Owned(Vec<u8>),
}
impl<'a> TargetBytes<'a> {
pub fn as_slice(&self) -> &[u8] {
match self {
TargetBytes::Ref(r) => r,
TargetBytes::Owned(v) => v.as_slice(),
}
}
}
/// Can be represented with a vector of bytes
/// This representation is not necessarily deserializable /// This representation is not necessarily deserializable
/// Instead, it can be used as bytes input for a target /// Instead, it can be used as bytes input for a target
pub trait HasTargetBytes { pub trait HasTargetBytes {
/// Target bytes, that can be written to a target /// Target bytes, that can be written to a target
fn target_bytes(&self) -> &[u8]; fn target_bytes(&self) -> TargetBytes;
} }
/// Contains an internal bytes Vector /// Contains an internal bytes Vector

View File

@ -160,7 +160,8 @@ mod tests {
#[test] #[test]
fn test_observer_serde() { fn test_observer_serde() {
let o: Box<dyn Observer> = Box::new(StdMapObserver::<u32>::new("test", unsafe { &mut MAP })); let o: Box<dyn Observer> =
Box::new(StdMapObserver::<u32>::new("test", unsafe { &mut MAP }));
let s = serde_json::to_string(&o).unwrap(); let s = serde_json::to_string(&o).unwrap();
println!("{}", s); println!("{}", s);
let d: Box<dyn Observer> = serde_json::from_str(&s).unwrap(); let d: Box<dyn Observer> = serde_json::from_str(&s).unwrap();