diff --git a/afl/Cargo.toml b/afl/Cargo.toml index 81e5d8741c..df2b36dca5 100644 --- a/afl/Cargo.toml +++ b/afl/Cargo.toml @@ -34,4 +34,5 @@ num = "*" xxhash-rust = { version = "0.8.0", features = ["xxh3"] } # xxh3 hashing for rust serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib erased-serde = "0.3.12" -postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat \ No newline at end of file +postcard = { version = "0.5.1", features = ["alloc"] } # no_std compatible serde serialization fromat +bincode = "1.3.1" \ No newline at end of file diff --git a/afl/src/corpus/testcase.rs b/afl/src/corpus/testcase.rs index a30d45e262..bf1925e26e 100644 --- a/afl/src/corpus/testcase.rs +++ b/afl/src/corpus/testcase.rs @@ -45,6 +45,7 @@ impl TestcaseMetadataContainer { /// An entry in the Testcase Corpus #[derive(Default, Serialize, Deserialize)] +#[serde(bound = "I: serde::de::DeserializeOwned")] pub struct Testcase where I: Input, diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index 9d9c3a352e..2bc4ecfa73 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -68,6 +68,7 @@ where /// Events sent around in the library #[derive(Serialize, Deserialize)] +#[serde(bound = "I: serde::de::DeserializeOwned")] pub enum Event<'a, C, E, I, R> where C: Corpus, diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index de68ad85a7..539e4cdbcb 100644 --- a/afl/src/executors/inmemory.rs +++ b/afl/src/executors/inmemory.rs @@ -2,7 +2,7 @@ use core::ffi::c_void; use core::ptr; use crate::executors::{Executor, ExitKind}; -use crate::inputs::Input; +use crate::inputs::{HasTargetBytes, Input}; use crate::observers::observer_serde::NamedSerdeAnyMap; use crate::AflError; @@ -16,7 +16,7 @@ type HarnessFunction = fn(&dyn Executor, &[u8]) -> ExitKind; /// The inmem executor simply calls a target function, then returns afterwards. pub struct InMemoryExecutor where - I: Input, + I: Input + HasTargetBytes, { harness: HarnessFunction, observers: NamedSerdeAnyMap, @@ -24,14 +24,14 @@ where impl Executor for InMemoryExecutor where - I: Input, + I: Input + HasTargetBytes, { fn run_target(&mut self, input: &I) -> Result { - let bytes = input.serialize()?; + let bytes = input.target_bytes(); unsafe { CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor as *const c_void; } - let ret = (self.harness)(self, bytes); + let ret = (self.harness)(self, bytes.as_slice()); unsafe { CURRENT_INMEMORY_EXECUTOR_PTR = ptr::null(); } @@ -49,7 +49,7 @@ where impl InMemoryExecutor where - I: Input, + I: Input + HasTargetBytes, { pub fn new(harness_fn: HarnessFunction) -> Self { #[cfg(feature = "std")] @@ -165,17 +165,17 @@ mod tests { use crate::executors::inmemory::InMemoryExecutor; use crate::executors::{Executor, ExitKind}; - use crate::inputs::Input; + use crate::inputs::{HasTargetBytes, Input, TargetBytes}; use crate::AflError; - #[derive(Clone)] + use serde::{Deserialize, Serialize}; + + #[derive(Clone, Serialize, Deserialize)] struct NopInput {} - impl Input for NopInput { - fn serialize(&self) -> Result<&[u8], AflError> { - Ok("NOP".as_bytes()) - } - fn deserialize(_buf: &[u8]) -> Result { - Ok(Self {}) + impl Input for NopInput {} + impl HasTargetBytes for NopInput { + fn target_bytes(&self) -> TargetBytes { + TargetBytes::Owned(vec![0]) } } diff --git a/afl/src/inputs/bytes.rs b/afl/src/inputs/bytes.rs index da8258a6ab..a220b362a5 100644 --- a/afl/src/inputs/bytes.rs +++ b/afl/src/inputs/bytes.rs @@ -3,27 +3,17 @@ use alloc::rc::Rc; use alloc::vec::Vec; use core::cell::RefCell; use core::convert::From; +use serde::{Deserialize, Serialize}; -use crate::inputs::{HasBytesVec, HasTargetBytes, Input}; -use crate::AflError; +use crate::inputs::{HasBytesVec, HasTargetBytes, Input, TargetBytes}; /// A bytes input is the basic input -#[derive(Clone, Debug, Default)] +#[derive(Serialize, Deserialize, Clone, Debug, Default)] pub struct BytesInput { bytes: Vec, } -impl Input for BytesInput { - fn serialize(&self) -> Result<&[u8], AflError> { - Ok(&self.bytes) - } - - fn deserialize(buf: &[u8]) -> Result { - Ok(Self { - bytes: buf.to_owned(), - }) - } -} +impl Input for BytesInput {} /// Rc Ref-cell from Input impl Into>> for BytesInput { @@ -42,8 +32,8 @@ impl HasBytesVec for BytesInput { } impl HasTargetBytes for BytesInput { - fn target_bytes(&self) -> &[u8] { - &self.bytes + fn target_bytes(&self) -> TargetBytes { + TargetBytes::Ref(&self.bytes) } } diff --git a/afl/src/inputs/mod.rs b/afl/src/inputs/mod.rs index 34c8633183..5533052a92 100644 --- a/afl/src/inputs/mod.rs +++ b/afl/src/inputs/mod.rs @@ -14,7 +14,7 @@ use std::path::Path; use crate::AflError; /// An input for the target -pub trait Input: Clone { +pub trait Input: Clone + serde::Serialize + serde::de::DeserializeOwned { #[cfg(feature = "std")] /// Write this input to the file fn to_file

(&self, path: P) -> Result<(), AflError> @@ -22,7 +22,9 @@ pub trait Input: Clone { P: AsRef, { 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(()) } @@ -42,7 +44,8 @@ where { let mut file = File::open(path).map_err(AflError::File)?; let mut bytes: Vec = vec![]; file.read_to_end(&mut bytes).map_err(AflError::File)?; - Self::deserialize(&bytes) + bincode::deserialize::(&bytes) + .map_err(|_| AflError::Unknown("cannot deserialize".to_string())) } /// Write this input to the file @@ -51,22 +54,28 @@ where { where { 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; } -/// Can be serialized to a bytes representation +pub enum TargetBytes<'a> { + Ref(&'a [u8]), + Owned(Vec), +} + +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 /// Instead, it can be used as bytes input for a target pub trait HasTargetBytes { /// Target bytes, that can be written to a target - fn target_bytes(&self) -> &[u8]; + fn target_bytes(&self) -> TargetBytes; } /// Contains an internal bytes Vector diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index 9c46799f91..9acb5e68e3 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -160,7 +160,8 @@ mod tests { #[test] fn test_observer_serde() { - let o: Box = Box::new(StdMapObserver::::new("test", unsafe { &mut MAP })); + let o: Box = + Box::new(StdMapObserver::::new("test", unsafe { &mut MAP })); let s = serde_json::to_string(&o).unwrap(); println!("{}", s); let d: Box = serde_json::from_str(&s).unwrap();