From 4271790cb50d8b390abe7d1d82ddd88f7e70c0d2 Mon Sep 17 00:00:00 2001 From: s1341 Date: Tue, 8 Jun 2021 10:54:38 +0300 Subject: [PATCH] Add unique_name() to Input. Use it to generate filename in OnDiskCorpus (#152) * Add unique_name() to Input. Use unique_name to generate filename in OnDiskCorpus * updated duplicate ahash * nostd fixes * fmt * rename unique_name to generate_name Co-authored-by: Dominik Maier --- fuzzers/frida_libpng/Cargo.toml | 1 - libafl/Cargo.toml | 3 ++- libafl/src/corpus/ondisk.rs | 8 +++++++- libafl/src/inputs/bytes.rs | 12 +++++++++++- libafl/src/inputs/mod.rs | 14 ++++++++++++-- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index c6b48feeb1..589c202717 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -30,7 +30,6 @@ libc = "0.2" libloading = "0.7.0" num-traits = "0.2.14" rangemap = "0.1.10" -seahash = "4.1.0" clap = "2.33" serde = "1.0" diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 1cfa0b0796..9a5585d503 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -16,7 +16,7 @@ rustc_version = "0.3.3" [dev-dependencies] criterion = "0.3" # Benchmarking -ahash = "0.6.1" # another hash +ahash = "0.7" # another hash fxhash = "0.2.1" # yet another hash xxhash-rust = { version = "0.8.2", features = ["xxh3"] } # xxh3 hashing for rust serde_json = "1.0.60" @@ -68,6 +68,7 @@ core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity num_enum = "0.5.1" hostname = "^0.3" # Is there really no gethostname in the stdlib? typed-builder = "0.9.0" +ahash ="0.7" [target.'cfg(target_os = "android")'.dependencies] backtrace = { version = "0.3", optional = true, default-features = false, features = ["std", "libbacktrace"] } # for llmp_debug diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 15d7cbc277..8e9503846d 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -50,7 +50,13 @@ where fn add(&mut self, mut testcase: Testcase) -> Result { if testcase.filename().is_none() { // TODO walk entry metadata to ask for pices of filename (e.g. :havoc in AFL) - let filename = self.dir_path.join(format!("id_{}", &self.entries.len())); + let filename = self.dir_path.join( + testcase + .input() + .as_ref() + .unwrap() + .generate_name(self.entries.len()), + ); let filename_str = filename.to_str().expect("Invalid Path"); testcase.set_filename(filename_str.into()); }; diff --git a/libafl/src/inputs/bytes.rs b/libafl/src/inputs/bytes.rs index 2eb97a7e15..c07c2b509d 100644 --- a/libafl/src/inputs/bytes.rs +++ b/libafl/src/inputs/bytes.rs @@ -1,7 +1,10 @@ //! The `BytesInput` is the "normal" input, a map of bytes, that can be sent directly to the client //! (As opposed to other, more abstract, imputs, like an Grammar-Based AST Input) -use alloc::{borrow::ToOwned, rc::Rc, vec::Vec}; +use ahash::AHasher; +use core::hash::Hasher; + +use alloc::{borrow::ToOwned, rc::Rc, string::String, vec::Vec}; use core::{cell::RefCell, convert::From}; use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] @@ -48,6 +51,13 @@ impl Input for BytesInput { file.read_to_end(&mut bytes)?; Ok(BytesInput::new(bytes)) } + + /// Generate a name for this input + fn generate_name(&self, _idx: usize) -> String { + let mut hasher = AHasher::new_with_keys(0, 0); + hasher.write(self.bytes()); + format!("{:016x}", hasher.finish()) + } } /// Rc Ref-cell from Input diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 831ab8fa9f..d8448f9e63 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -3,7 +3,10 @@ pub mod bytes; pub use bytes::BytesInput; -use alloc::vec::Vec; +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; use core::{clone::Clone, fmt::Debug}; #[cfg(feature = "std")] use std::{ @@ -53,12 +56,19 @@ pub trait Input: Clone + serde::Serialize + serde::de::DeserializeOwned + Debug fn from_file

(_path: P) -> Result { Err(Error::NotImplemented("Not supprted in no_std".into())) } + + /// Generate a name for this input + fn generate_name(&self, idx: usize) -> String; } /// An input for tests, mainly. There is no real use much else. #[derive(Copy, Clone, Serialize, Deserialize, Debug)] pub struct NopInput {} -impl Input for NopInput {} +impl Input for NopInput { + fn generate_name(&self, _idx: usize) -> String { + "nop-input".to_string() + } +} impl HasTargetBytes for NopInput { fn target_bytes(&self) -> OwnedSlice { OwnedSlice::Owned(vec![0])