From 7caa7c5f2271f5a8a7a0c12ec53eedb9a8a71dd1 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Thu, 9 Jan 2025 22:57:40 +0530 Subject: [PATCH 01/11] testcase name logic --- libafl/src/corpus/inmemory_ondisk.rs | 10 +++++----- libafl/src/events/mod.rs | 2 +- libafl/src/executors/hooks/unix.rs | 2 +- libafl/src/inputs/encoded.rs | 4 ++-- libafl/src/inputs/gramatron.rs | 4 ++-- libafl/src/inputs/mod.rs | 27 +++++++++++++-------------- libafl/src/inputs/value.rs | 16 ++++------------ libafl/src/stages/dump.rs | 5 +---- 8 files changed, 29 insertions(+), 41 deletions(-) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index 8afccf93cb..60bd4b484f 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -87,7 +87,7 @@ where fn add(&mut self, testcase: Testcase) -> Result { let id = self.inner.add(testcase)?; let testcase = &mut self.get(id).unwrap().borrow_mut(); - self.save_testcase(testcase, id)?; + self.save_testcase(testcase)?; *testcase.input_mut() = None; Ok(id) } @@ -97,7 +97,7 @@ where fn add_disabled(&mut self, testcase: Testcase) -> Result { let id = self.inner.add_disabled(testcase)?; let testcase = &mut self.get_from_all(id).unwrap().borrow_mut(); - self.save_testcase(testcase, id)?; + self.save_testcase(testcase)?; *testcase.input_mut() = None; Ok(id) } @@ -108,7 +108,7 @@ where let entry = self.inner.replace(id, testcase)?; self.remove_testcase(&entry)?; let testcase = &mut self.get(id).unwrap().borrow_mut(); - self.save_testcase(testcase, id)?; + self.save_testcase(testcase)?; *testcase.input_mut() = None; Ok(entry) } @@ -375,13 +375,13 @@ impl InMemoryOnDiskCorpus { } } - fn save_testcase(&self, testcase: &mut Testcase, id: CorpusId) -> Result<(), Error> + fn save_testcase(&self, testcase: &mut Testcase) -> Result<(), Error> where I: Input, { let file_name_orig = testcase.filename_mut().take().unwrap_or_else(|| { // TODO walk entry metadata to ask for pieces of filename (e.g. :havoc in AFL) - testcase.input().as_ref().unwrap().generate_name(Some(id)) + testcase.input().as_ref().unwrap().generate_name() }); // New testcase, we need to save it. diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 93dddc4f07..5adf188bd2 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -379,7 +379,7 @@ where fn name_detailed(&self) -> Cow<'static, str> { match self { Event::NewTestcase { input, .. } => { - Cow::Owned(format!("Testcase {}", input.generate_name(None))) + Cow::Owned(format!("Testcase {}", input.generate_name())) } Event::UpdateExecStats { .. } => Cow::Borrowed("Client Heartbeat"), Event::UpdateUserStats { .. } => Cow::Borrowed("UserStats"), diff --git a/libafl/src/executors/hooks/unix.rs b/libafl/src/executors/hooks/unix.rs index e0f63d91a8..4ff154b468 100644 --- a/libafl/src/executors/hooks/unix.rs +++ b/libafl/src/executors/hooks/unix.rs @@ -216,7 +216,7 @@ pub mod unix_signal_handler { let mut bsod = Vec::new(); { let mut writer = std::io::BufWriter::new(&mut bsod); - let _ = writeln!(writer, "input: {:?}", input.generate_name(None)); + let _ = writeln!(writer, "input: {:?}", input.generate_name()); let bsod = libafl_bolts::minibsod::generate_minibsod( &mut writer, signal, diff --git a/libafl/src/inputs/encoded.rs b/libafl/src/inputs/encoded.rs index b602cd0e94..f5ddf0c971 100644 --- a/libafl/src/inputs/encoded.rs +++ b/libafl/src/inputs/encoded.rs @@ -20,7 +20,7 @@ use libafl_bolts::{Error, HasLen}; use regex::Regex; use serde::{Deserialize, Serialize}; -use crate::{corpus::CorpusId, inputs::Input}; +use crate::inputs::Input; /// Trait to encode bytes to an [`EncodedInput`] using the given [`Tokenizer`] pub trait InputEncoder @@ -202,7 +202,7 @@ pub struct EncodedInput { impl Input for EncodedInput { /// Generate a name for this input #[must_use] - fn generate_name(&self, _id: Option) -> String { + fn generate_name(&self) -> String { let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); for code in &self.codes { hasher.write(&code.to_le_bytes()); diff --git a/libafl/src/inputs/gramatron.rs b/libafl/src/inputs/gramatron.rs index 443ee51ad3..790181e6d4 100644 --- a/libafl/src/inputs/gramatron.rs +++ b/libafl/src/inputs/gramatron.rs @@ -9,7 +9,7 @@ use ahash::RandomState; use libafl_bolts::{Error, HasLen}; use serde::{Deserialize, Serialize}; -use crate::{corpus::CorpusId, inputs::Input}; +use crate::inputs::Input; /// A terminal for gramatron grammar fuzzing #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)] @@ -44,7 +44,7 @@ pub struct GramatronInput { impl Input for GramatronInput { /// Generate a name for this input #[must_use] - fn generate_name(&self, _id: Option) -> String { + fn generate_name(&self) -> String { let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); for term in &self.terms { hasher.write(term.symbol.as_bytes()); diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 91aac35652..4a3658280c 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -28,21 +28,23 @@ pub mod nautilus; use alloc::{ boxed::Box, - string::{String, ToString}, + string::String, vec::{Drain, Splice, Vec}, }; use core::{ clone::Clone, fmt::Debug, + hash::Hash, marker::PhantomData, ops::{DerefMut, RangeBounds}, }; #[cfg(feature = "std")] -use std::{fs::File, hash::Hash, io::Read, path::Path}; +use std::{fs::File, io::Read, path::Path}; #[cfg(feature = "std")] use libafl_bolts::fs::write_file_atomic; use libafl_bolts::{ + generic_hash_std, ownedref::{OwnedMutSlice, OwnedSlice}, subrange::{SubRangeMutSlice, SubRangeSlice}, Error, HasLen, @@ -51,11 +53,9 @@ use libafl_bolts::{ pub use nautilus::*; use serde::{Deserialize, Serialize}; -use crate::corpus::CorpusId; - /// An input for the target #[cfg(not(feature = "std"))] -pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { +pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash { /// Write this input to the file fn to_file

(&self, _path: P) -> Result<(), Error> { Err(Error::not_implemented("Not supported in no_std")) @@ -67,12 +67,14 @@ pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { } /// Generate a name for this input - fn generate_name(&self, id: Option) -> String; + fn generate_name(&self) -> String { + format!("{:016x}", generic_hash_std(self)) + } } /// An input for the target #[cfg(feature = "std")] -pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { +pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash { /// Write this input to the file fn to_file

(&self, path: P) -> Result<(), Error> where @@ -93,7 +95,9 @@ pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { } /// Generate a name for this input, the user is responsible for making each name of testcase unique. - fn generate_name(&self, id: Option) -> String; + fn generate_name(&self) -> String { + format!("{:016x}", generic_hash_std(self)) + } } /// Convert between two input types with a state @@ -127,12 +131,7 @@ impl NopInput { } } -impl Input for NopInput { - fn generate_name(&self, _id: Option) -> String { - "nop-input".to_string() - } -} - +impl Input for NopInput {} impl HasTargetBytes for NopInput { fn target_bytes(&self) -> OwnedSlice { OwnedSlice::from(vec![0]) diff --git a/libafl/src/inputs/value.rs b/libafl/src/inputs/value.rs index f2db679831..4948112431 100644 --- a/libafl/src/inputs/value.rs +++ b/libafl/src/inputs/value.rs @@ -1,9 +1,9 @@ //! Newtype pattern style wrapper for [`super::Input`]s -use alloc::{string::String, vec::Vec}; +use alloc::vec::Vec; use core::{fmt::Debug, hash::Hash}; -use libafl_bolts::{generic_hash_std, rands::Rand}; +use libafl_bolts::rands::Rand; use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] use { @@ -12,7 +12,7 @@ use { }; use super::Input; -use crate::{corpus::CorpusId, mutators::numeric::Numeric}; +use crate::mutators::numeric::Numeric; /// Newtype pattern wrapper around an underlying structure to implement inputs /// @@ -56,11 +56,7 @@ impl Copy for ValueInput {} macro_rules! impl_input_for_value_input { ($($t:ty => $name:ident),+ $(,)?) => { $( - impl Input for ValueInput<$t> { - fn generate_name(&self, _id: Option) -> String { - format!("{:016x}", generic_hash_std(self)) - } - } + impl Input for ValueInput<$t> {} /// Input wrapping a <$t> pub type $name = ValueInput<$t>; @@ -86,10 +82,6 @@ impl_input_for_value_input!( /// manually implemented because files can be written more efficiently impl Input for ValueInput> { - fn generate_name(&self, _id: Option) -> String { - format!("{:016x}", generic_hash_std(self)) - } - /// Write this input to the file #[cfg(feature = "std")] fn to_file

(&self, path: P) -> Result<(), Error> diff --git a/libafl/src/stages/dump.rs b/libafl/src/stages/dump.rs index 32d8365d88..070c5e7a57 100644 --- a/libafl/src/stages/dump.rs +++ b/libafl/src/stages/dump.rs @@ -106,10 +106,7 @@ where [ Some(id.0.to_string()), testcase.filename().clone(), - testcase - .input() - .as_ref() - .map(|t| t.generate_name(Some(*id))), + testcase.input().as_ref().map(|t| t.generate_name()), ] .iter() .flatten() From 2185d401cf03722fc246e0c114d6b42b891acf98 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Thu, 9 Jan 2025 23:28:34 +0530 Subject: [PATCH 02/11] implement locking --- Cargo.toml | 2 +- libafl/Cargo.toml | 2 ++ libafl/src/corpus/inmemory_ondisk.rs | 45 ++++++++++++++++------------ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 66cd22bc30..1e9b45279c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,7 +123,7 @@ uuid = { version = "1.10.0", features = ["serde", "v4"] } which = "6.0.3" windows = "0.59.0" z3 = "0.12.1" - +fs2 = "0.4.3" [workspace.lints.rust] # Forbid diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index cc929939a1..db23b45ce5 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -39,6 +39,7 @@ default = [ "regex", "serdeany_autoreg", "libafl_bolts/xxh3", + "fs2" ] document-features = ["dep:document-features"] @@ -296,6 +297,7 @@ clap = { workspace = true, optional = true } num_enum = { workspace = true, optional = true } libipt = { workspace = true, optional = true } fastbloom = { workspace = true, optional = true } +fs2 = { workspace = true, optional = true } [lints] workspace = true diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index 60bd4b484f..ea321890fa 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -4,7 +4,7 @@ //! For a lower memory footprint, consider using [`crate::corpus::CachedOnDiskCorpus`] //! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner. -use alloc::string::String; +use alloc::string::{String, ToString}; use core::cell::RefCell; use std::{ fs, @@ -14,6 +14,7 @@ use std::{ path::{Path, PathBuf}, }; +use fs2::FileExt; #[cfg(feature = "gzip")] use libafl_bolts::compress::GzipCompressor; use serde::{Deserialize, Serialize}; @@ -379,30 +380,28 @@ impl InMemoryOnDiskCorpus { where I: Input, { - let file_name_orig = testcase.filename_mut().take().unwrap_or_else(|| { + let file_name = testcase.filename_mut().take().unwrap_or_else(|| { // TODO walk entry metadata to ask for pieces of filename (e.g. :havoc in AFL) testcase.input().as_ref().unwrap().generate_name() }); - // New testcase, we need to save it. - let mut file_name = file_name_orig.clone(); + let mut ctr = String::new(); + if self.locking { + let lockfile_name = format!(".{file_name}"); + let lockfile_path = self.dir_path.join(lockfile_name); - let mut ctr = 2; - let file_name = if self.locking { - loop { - let lockfile_name = format!(".{file_name}.lafl_lock"); - let lockfile_path = self.dir_path.join(lockfile_name); + let lockfile = try_create_new(&lockfile_path)?.unwrap_or(File::create(&lockfile_path)?); + lockfile.lock_exclusive()?; - if try_create_new(lockfile_path)?.is_some() { - break file_name; - } - - file_name = format!("{file_name_orig}-{ctr}"); - ctr += 1; + ctr = fs::read_to_string(&lockfile_path)?; + if ctr.is_empty() { + ctr = String::from("1"); + } else { + ctr = (ctr.parse::()? + 1).to_string(); } - } else { - file_name - }; + + fs::write(lockfile_path, &ctr)?; + } if testcase.file_path().is_none() { *testcase.file_path_mut() = Some(self.dir_path.join(&file_name)); @@ -410,7 +409,15 @@ impl InMemoryOnDiskCorpus { *testcase.filename_mut() = Some(file_name); if self.meta_format.is_some() { - let metafile_name = format!(".{}.metadata", testcase.filename().as_ref().unwrap()); + let metafile_name = if self.locking { + format!( + ".{}_{}.metadata", + testcase.filename().as_ref().unwrap(), + ctr + ) + } else { + format!(".{}.metadata", testcase.filename().as_ref().unwrap()) + }; let metafile_path = self.dir_path.join(&metafile_name); let mut tmpfile_path = metafile_path.clone(); tmpfile_path.set_file_name(format!(".{metafile_name}.tmp",)); From 622a773efc71a14c7e0ad62b0e59b452388025a8 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Thu, 9 Jan 2025 23:35:34 +0530 Subject: [PATCH 03/11] implement logic for removing testcase --- libafl/src/corpus/inmemory_ondisk.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index ea321890fa..f59f3da670 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -460,15 +460,27 @@ impl InMemoryOnDiskCorpus { fn remove_testcase(&self, testcase: &Testcase) -> Result<(), Error> { if let Some(filename) = testcase.filename() { + if self.locking { + let lockfile_path = self.dir_path.join(format!(".{filename}")); + let lockfile = File::open(&lockfile_path)?; + + lockfile.lock_exclusive()?; + let ctr = fs::read_to_string(&lockfile_path)?; + + if ctr == "1" { + lockfile.unlock()?; + drop(fs::remove_file(lockfile_path)); + } else { + let n: u32 = ctr.parse()?; + fs::write(lockfile_path, (n - 1).to_string())?; + return Ok(()); + } + } + fs::remove_file(self.dir_path.join(filename))?; if self.meta_format.is_some() { fs::remove_file(self.dir_path.join(format!(".{filename}.metadata")))?; } - // also try to remove the corresponding `.lafl_lock` file if it still exists - // (even though it shouldn't exist anymore, at this point in time) - drop(fs::remove_file( - self.dir_path.join(format!(".{filename}.lafl_lock")), - )); } Ok(()) } From ce7379cf8274af4bfbfbb25d3d36c2e758f86502 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Sat, 11 Jan 2025 17:14:41 +0530 Subject: [PATCH 04/11] minor modifications --- libafl/src/corpus/inmemory_ondisk.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index f59f3da670..042606f713 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -390,10 +390,11 @@ impl InMemoryOnDiskCorpus { let lockfile_name = format!(".{file_name}"); let lockfile_path = self.dir_path.join(lockfile_name); - let lockfile = try_create_new(&lockfile_path)?.unwrap_or(File::create(&lockfile_path)?); + let lockfile = try_create_new(&lockfile_path)? + .unwrap_or(OpenOptions::new().write(true).open(&lockfile_path)?); lockfile.lock_exclusive()?; - ctr = fs::read_to_string(&lockfile_path)?; + ctr = fs::read_to_string(&lockfile_path)?.trim().to_string(); if ctr.is_empty() { ctr = String::from("1"); } else { From f06ed973525da46040d296df19338bce99f18708 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Sat, 11 Jan 2025 17:20:14 +0530 Subject: [PATCH 05/11] minor modifications to remove_testcase() --- libafl/src/corpus/inmemory_ondisk.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index 042606f713..988b9475e3 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -463,7 +463,7 @@ impl InMemoryOnDiskCorpus { if let Some(filename) = testcase.filename() { if self.locking { let lockfile_path = self.dir_path.join(format!(".{filename}")); - let lockfile = File::open(&lockfile_path)?; + let lockfile = OpenOptions::new().write(true).open(&lockfile_path)?; lockfile.lock_exclusive()?; let ctr = fs::read_to_string(&lockfile_path)?; @@ -472,8 +472,7 @@ impl InMemoryOnDiskCorpus { lockfile.unlock()?; drop(fs::remove_file(lockfile_path)); } else { - let n: u32 = ctr.parse()?; - fs::write(lockfile_path, (n - 1).to_string())?; + fs::write(lockfile_path, (ctr.parse::()? - 1).to_string())?; return Ok(()); } } From 9e217be2810a8c33970846cdd380f542975cc05b Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Sun, 12 Jan 2025 21:06:34 +0530 Subject: [PATCH 06/11] extract generate_name() from trait Input (broken) --- libafl/src/corpus/cached.rs | 8 ++++---- libafl/src/corpus/inmemory_ondisk.rs | 14 +++++++------- libafl/src/corpus/ondisk.rs | 5 +++-- libafl/src/events/broker_hooks/centralized.rs | 4 ++-- libafl/src/events/broker_hooks/mod.rs | 4 ++-- libafl/src/events/centralized.rs | 4 ++-- libafl/src/events/llmp/mod.rs | 4 ++-- libafl/src/events/mod.rs | 10 +++++----- libafl/src/executors/hooks/inprocess.rs | 3 ++- libafl/src/executors/hooks/unix.rs | 6 +++--- libafl/src/executors/hooks/windows.rs | 2 +- libafl/src/executors/inprocess/mod.rs | 1 + libafl/src/feedbacks/map.rs | 2 ++ libafl/src/fuzzer/mod.rs | 10 ++++------ libafl/src/inputs/encoded.rs | 18 ++---------------- libafl/src/inputs/gramatron.rs | 18 ++---------------- libafl/src/inputs/mod.rs | 17 ++++++----------- libafl/src/stages/calibrate.rs | 4 ++-- libafl/src/stages/dump.rs | 4 ++-- libafl/src/stages/sync.rs | 6 +++--- libafl/src/state/mod.rs | 7 ++++--- 21 files changed, 61 insertions(+), 90 deletions(-) diff --git a/libafl/src/corpus/cached.rs b/libafl/src/corpus/cached.rs index 2e21fee65c..37802425ce 100644 --- a/libafl/src/corpus/cached.rs +++ b/libafl/src/corpus/cached.rs @@ -1,7 +1,7 @@ //! The [`CachedOnDiskCorpus`] stores [`Testcase`]s to disk, keeping a subset of them in memory/cache, evicting in a FIFO manner. use alloc::{collections::vec_deque::VecDeque, string::String}; -use core::cell::RefCell; +use core::{cell::RefCell, hash::Hash}; use std::path::Path; use serde::{Deserialize, Serialize}; @@ -27,7 +27,7 @@ pub struct CachedOnDiskCorpus { impl CachedOnDiskCorpus where - I: Input, + I: Input + Hash, { fn cache_testcase<'a>( &'a self, @@ -57,7 +57,7 @@ where } impl Corpus for CachedOnDiskCorpus where - I: Input, + I: Input + Hash, { type Input = I; @@ -181,7 +181,7 @@ where impl HasTestcase for CachedOnDiskCorpus where - I: Input, + I: Input + Hash, { fn testcase(&self, id: CorpusId) -> Result>, Error> { Ok(self.get(id)?.borrow()) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index 988b9475e3..31cd13e4cf 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -5,7 +5,7 @@ //! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner. use alloc::string::{String, ToString}; -use core::cell::RefCell; +use core::{cell::RefCell, hash::Hash}; use std::{ fs, fs::{File, OpenOptions}, @@ -25,7 +25,7 @@ use super::{ }; use crate::{ corpus::{Corpus, CorpusId, InMemoryCorpus, Testcase}, - inputs::Input, + inputs::{generate_name, Input}, Error, HasMetadata, }; @@ -62,7 +62,7 @@ pub struct InMemoryOnDiskCorpus { impl Corpus for InMemoryOnDiskCorpus where - I: Input, + I: Input + Hash, { type Input = I; @@ -214,7 +214,7 @@ where impl HasTestcase for InMemoryOnDiskCorpus where - I: Input, + I: Input + Hash, { fn testcase( &self, @@ -378,11 +378,11 @@ impl InMemoryOnDiskCorpus { fn save_testcase(&self, testcase: &mut Testcase) -> Result<(), Error> where - I: Input, + I: Input + Hash, { let file_name = testcase.filename_mut().take().unwrap_or_else(|| { // TODO walk entry metadata to ask for pieces of filename (e.g. :havoc in AFL) - testcase.input().as_ref().unwrap().generate_name() + generate_name(testcase.input().as_ref().unwrap()) }); let mut ctr = String::new(); @@ -469,7 +469,7 @@ impl InMemoryOnDiskCorpus { let ctr = fs::read_to_string(&lockfile_path)?; if ctr == "1" { - lockfile.unlock()?; + FileExt::unlock(&lockfile)?; drop(fs::remove_file(lockfile_path)); } else { fs::write(lockfile_path, (ctr.parse::()? - 1).to_string())?; diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 5c6569538f..9142926850 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -8,6 +8,7 @@ use alloc::string::String; use core::{ cell::{Ref, RefCell, RefMut}, + hash::Hash, time::Duration, }; use std::path::{Path, PathBuf}; @@ -58,7 +59,7 @@ pub struct OnDiskCorpus { impl Corpus for OnDiskCorpus where - I: Input, + I: Input + Hash, { type Input = I; /// Returns the number of all enabled entries @@ -176,7 +177,7 @@ where impl HasTestcase for OnDiskCorpus where - I: Input, + I: Input + Hash, { fn testcase(&self, id: CorpusId) -> Result>, Error> { Ok(self.get(id)?.borrow()) diff --git a/libafl/src/events/broker_hooks/centralized.rs b/libafl/src/events/broker_hooks/centralized.rs index 831ae29fcb..92f9ea2661 100644 --- a/libafl/src/events/broker_hooks/centralized.rs +++ b/libafl/src/events/broker_hooks/centralized.rs @@ -1,5 +1,5 @@ use alloc::vec::Vec; -use core::{fmt::Debug, marker::PhantomData}; +use core::{fmt::Debug, hash::Hash, marker::PhantomData}; #[cfg(feature = "llmp_compression")] use libafl_bolts::{compress::GzipCompressor, llmp::LLMP_FLAG_COMPRESSED}; @@ -77,7 +77,7 @@ impl Debug for CentralizedLlmpHook { impl CentralizedLlmpHook where - I: Input, + I: Input + Hash, { /// Create an event broker from a raw broker. pub fn new() -> Result { diff --git a/libafl/src/events/broker_hooks/mod.rs b/libafl/src/events/broker_hooks/mod.rs index cc3d470b9d..ad750a20a2 100644 --- a/libafl/src/events/broker_hooks/mod.rs +++ b/libafl/src/events/broker_hooks/mod.rs @@ -1,6 +1,6 @@ //! Hooks called on broker side use alloc::vec::Vec; -use core::marker::PhantomData; +use core::{hash::Hash, marker::PhantomData}; #[cfg(feature = "llmp_compression")] use libafl_bolts::{compress::GzipCompressor, llmp::LLMP_FLAG_COMPRESSED}; @@ -90,7 +90,7 @@ where impl StdLlmpEventHook where - I: Input, + I: Input + Hash, MT: Monitor, { /// Create an event broker from a raw broker. diff --git a/libafl/src/events/centralized.rs b/libafl/src/events/centralized.rs index 9d818e8686..c7fddfa3c5 100644 --- a/libafl/src/events/centralized.rs +++ b/libafl/src/events/centralized.rs @@ -8,7 +8,7 @@ // 4. The "main broker", the gathers the stats from the fuzzer clients and broadcast the newly found testcases from the main evaluator. use alloc::{boxed::Box, string::String, vec::Vec}; -use core::{fmt::Debug, time::Duration}; +use core::{fmt::Debug, hash::Hash, time::Duration}; use std::{marker::PhantomData, process}; #[cfg(feature = "llmp_compression")] @@ -495,7 +495,7 @@ where #[cfg(feature = "llmp_compression")] fn forward_to_main(&mut self, event: &Event) -> Result<(), Error> where - I: Input, + I: Input + Hash, { let serialized = postcard::to_allocvec(event)?; let flags = LLMP_FLAG_INITIALIZED; diff --git a/libafl/src/events/llmp/mod.rs b/libafl/src/events/llmp/mod.rs index 629ff6006a..e952bfb287 100644 --- a/libafl/src/events/llmp/mod.rs +++ b/libafl/src/events/llmp/mod.rs @@ -1,7 +1,7 @@ //! LLMP-backed event manager for scalable multi-processed fuzzing use alloc::{boxed::Box, vec::Vec}; -use core::{marker::PhantomData, time::Duration}; +use core::{hash::Hash, marker::PhantomData, time::Duration}; #[cfg(feature = "llmp_compression")] use libafl_bolts::{ @@ -258,7 +258,7 @@ where SP: ShMemProvider, IC: InputConverter, ICB: InputConverter, - DI: Input, + DI: Input + Hash, { // TODO other new_* routines diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 5adf188bd2..f0ccb32b13 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -22,7 +22,7 @@ pub mod broker_hooks; use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec}; use core::{ fmt, - hash::{BuildHasher, Hasher}, + hash::{BuildHasher, Hash, Hasher}, marker::PhantomData, time::Duration, }; @@ -47,7 +47,7 @@ use uuid::Uuid; use crate::state::HasClientPerfMonitor; use crate::{ executors::ExitKind, - inputs::Input, + inputs::{generate_name, Input}, monitors::UserStats, observers::ObserversTuple, state::{HasExecutions, HasLastReportTime, State}, @@ -266,7 +266,7 @@ where #[serde(bound = "I: serde::de::DeserializeOwned")] pub enum Event where - I: Input, + I: Input + Hash, { // TODO use an ID to keep track of the original index in the sender Corpus // The sender can then use it to send Testcase metadata with CustomEvent @@ -355,7 +355,7 @@ where impl Event where - I: Input, + I: Input + Hash, { /// Event's corresponding name pub fn name(&self) -> &str { @@ -379,7 +379,7 @@ where fn name_detailed(&self) -> Cow<'static, str> { match self { Event::NewTestcase { input, .. } => { - Cow::Owned(format!("Testcase {}", input.generate_name())) + Cow::Owned(format!("Testcase {}", generate_name(input))) } Event::UpdateExecStats { .. } => Cow::Borrowed("Client Heartbeat"), Event::UpdateUserStats { .. } => Cow::Borrowed("UserStats"), diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index 36ec47bbc5..63769ffe7a 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -5,6 +5,7 @@ use core::mem::zeroed; use core::sync::atomic::{compiler_fence, Ordering}; use core::{ ffi::c_void, + hash::Hash, marker::PhantomData, ptr::{self, null_mut}, time::Duration, @@ -236,7 +237,7 @@ where E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me - <<::State as HasCorpus>::Corpus as Corpus>::Input: Clone, //delete me + <<::State as HasCorpus>::Corpus as Corpus>::Input: Clone + Hash, //delete me { // # Safety // We get a pointer to `GLOBAL_STATE` that will be initialized at this point in time. diff --git a/libafl/src/executors/hooks/unix.rs b/libafl/src/executors/hooks/unix.rs index 4ff154b468..316138c58b 100644 --- a/libafl/src/executors/hooks/unix.rs +++ b/libafl/src/executors/hooks/unix.rs @@ -2,7 +2,7 @@ #[cfg(unix)] pub mod unix_signal_handler { use alloc::{boxed::Box, string::String, vec::Vec}; - use core::mem::transmute; + use core::{hash::Hash, mem::transmute}; use std::{io::Write, panic}; use libafl_bolts::os::unix_signals::{ucontext_t, Signal, SignalHandler}; @@ -19,7 +19,7 @@ pub mod unix_signal_handler { }, feedbacks::Feedback, fuzzer::HasObjective, - inputs::{Input, UsesInput}, + inputs::{generate_name, UsesInput}, observers::ObserversTuple, state::{HasCorpus, HasExecutions, HasSolutions, UsesState}, }; @@ -216,7 +216,7 @@ pub mod unix_signal_handler { let mut bsod = Vec::new(); { let mut writer = std::io::BufWriter::new(&mut bsod); - let _ = writeln!(writer, "input: {:?}", input.generate_name()); + // let _ = writeln!(writer, "input: {:?}", generate_name(&input)); let bsod = libafl_bolts::minibsod::generate_minibsod( &mut writer, signal, diff --git a/libafl/src/executors/hooks/windows.rs b/libafl/src/executors/hooks/windows.rs index f0554848e9..a3ae6e7a5a 100644 --- a/libafl/src/executors/hooks/windows.rs +++ b/libafl/src/executors/hooks/windows.rs @@ -417,7 +417,7 @@ pub mod windows_exception_handler { let mut bsod = Vec::new(); { let mut writer = std::io::BufWriter::new(&mut bsod); - writeln!(writer, "input: {:?}", input.generate_name(None)).unwrap(); + writeln!(writer, "input: {:?}", input.generate_name()).unwrap(); libafl_bolts::minibsod::generate_minibsod(&mut writer, exception_pointers) .unwrap(); writer.flush().unwrap(); diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index 0efb911448..28d93b823c 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -7,6 +7,7 @@ use core::{ borrow::BorrowMut, ffi::c_void, fmt::{self, Debug, Formatter}, + hash::Hash, marker::PhantomData, ptr, time::Duration, diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 7e8cb9700a..76a934bbaf 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -5,6 +5,7 @@ use alloc::{borrow::Cow, vec::Vec}; use core::simd::prelude::SimdOrd; use core::{ fmt::Debug, + hash::Hash, marker::PhantomData, ops::{BitAnd, BitOr, Deref, DerefMut}, }; @@ -402,6 +403,7 @@ where OT: MatchName, R: Reducer, S: HasNamedMetadata + UsesInput, // delete me + ::Input: Hash, { #[rustversion::nightly] default fn is_interesting( diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 1b8e41daa6..cc0ce18a21 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -1,9 +1,7 @@ //! The `Fuzzer` is the main struct for a fuzz campaign. use alloc::{string::ToString, vec::Vec}; -use core::{fmt::Debug, time::Duration}; -#[cfg(feature = "std")] -use std::hash::Hash; +use core::{fmt::Debug, hash::Hash, time::Duration}; #[cfg(feature = "std")] use fastbloom::BloomFilter; @@ -317,7 +315,7 @@ where F: Feedback::Input, OT, S>, OF: Feedback::Input, OT, S>, OT: ObserversTuple<::Input, S> + Serialize, - ::Input: Input, + ::Input: Input + Hash, S::Solutions: Corpus::Input>, { fn check_results( @@ -525,7 +523,7 @@ where + UsesInput::Input> + HasExecutions + HasLastFoundTime, - ::Input: Input, + ::Input: Input + Hash, S::Solutions: Corpus::Input>, { /// Process one input, adding to the respective corpora if needed and firing the right events @@ -603,7 +601,7 @@ where + HasLastFoundTime + HasExecutions + UsesInput::Input>, - ::Input: Input, + ::Input: Input + Hash, S::Solutions: Corpus::Input>, IF: InputFilter<::Input>, { diff --git a/libafl/src/inputs/encoded.rs b/libafl/src/inputs/encoded.rs index f5ddf0c971..4f9bc8de91 100644 --- a/libafl/src/inputs/encoded.rs +++ b/libafl/src/inputs/encoded.rs @@ -6,14 +6,10 @@ #[cfg(feature = "regex")] use alloc::string::ToString; use alloc::{borrow::ToOwned, rc::Rc, string::String, vec::Vec}; +use core::cell::RefCell; #[cfg(feature = "regex")] use core::str::from_utf8; -use core::{ - cell::RefCell, - hash::{BuildHasher, Hasher}, -}; -use ahash::RandomState; use hashbrown::HashMap; use libafl_bolts::{Error, HasLen}; #[cfg(feature = "regex")] @@ -199,17 +195,7 @@ pub struct EncodedInput { codes: Vec, } -impl Input for EncodedInput { - /// Generate a name for this input - #[must_use] - fn generate_name(&self) -> String { - let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); - for code in &self.codes { - hasher.write(&code.to_le_bytes()); - } - format!("{:016x}", hasher.finish()) - } -} +impl Input for EncodedInput {} /// Rc Ref-cell from Input impl From for Rc> { diff --git a/libafl/src/inputs/gramatron.rs b/libafl/src/inputs/gramatron.rs index 790181e6d4..c65f925290 100644 --- a/libafl/src/inputs/gramatron.rs +++ b/libafl/src/inputs/gramatron.rs @@ -1,11 +1,7 @@ //! The gramatron grammar fuzzer use alloc::{rc::Rc, string::String, vec::Vec}; -use core::{ - cell::RefCell, - hash::{BuildHasher, Hasher}, -}; +use core::cell::RefCell; -use ahash::RandomState; use libafl_bolts::{Error, HasLen}; use serde::{Deserialize, Serialize}; @@ -41,17 +37,7 @@ pub struct GramatronInput { terms: Vec, } -impl Input for GramatronInput { - /// Generate a name for this input - #[must_use] - fn generate_name(&self) -> String { - let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); - for term in &self.terms { - hasher.write(term.symbol.as_bytes()); - } - format!("{:016x}", hasher.finish()) - } -} +impl Input for GramatronInput {} /// Rc Ref-cell from Input impl From for Rc> { diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 4a3658280c..e369245071 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -55,7 +55,7 @@ use serde::{Deserialize, Serialize}; /// An input for the target #[cfg(not(feature = "std"))] -pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash { +pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { /// Write this input to the file fn to_file

(&self, _path: P) -> Result<(), Error> { Err(Error::not_implemented("Not supported in no_std")) @@ -65,16 +65,11 @@ pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash fn from_file

(_path: P) -> Result { Err(Error::not_implemented("Not supprted in no_std")) } - - /// Generate a name for this input - fn generate_name(&self) -> String { - format!("{:016x}", generic_hash_std(self)) - } } /// An input for the target #[cfg(feature = "std")] -pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash { +pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { /// Write this input to the file fn to_file

(&self, path: P) -> Result<(), Error> where @@ -93,11 +88,11 @@ pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash file.read_to_end(&mut bytes)?; Ok(postcard::from_bytes(&bytes)?) } +} - /// Generate a name for this input, the user is responsible for making each name of testcase unique. - fn generate_name(&self) -> String { - format!("{:016x}", generic_hash_std(self)) - } +// Generate a name for given input +pub fn generate_name(input: I) -> String { + format!("{:016x}", generic_hash_std(&input)) } /// Convert between two input types with a state diff --git a/libafl/src/stages/calibrate.rs b/libafl/src/stages/calibrate.rs index 50c07aeb09..d232356606 100644 --- a/libafl/src/stages/calibrate.rs +++ b/libafl/src/stages/calibrate.rs @@ -5,7 +5,7 @@ use alloc::{ string::ToString, vec::Vec, }; -use core::{fmt::Debug, marker::PhantomData, time::Duration}; +use core::{fmt::Debug, hash::Hash, marker::PhantomData, time::Duration}; use hashbrown::HashSet; use libafl_bolts::{current_time, impl_serdeany, tuples::Handle, AsIter, Named}; @@ -103,7 +103,7 @@ where + HasCurrentCorpusId + UsesInput::Input>, Z: Evaluator::Input, S>, - ::Input: Input, + ::Input: Input + Hash, { #[inline] #[expect(clippy::too_many_lines, clippy::cast_precision_loss)] diff --git a/libafl/src/stages/dump.rs b/libafl/src/stages/dump.rs index 070c5e7a57..f657bc26ec 100644 --- a/libafl/src/stages/dump.rs +++ b/libafl/src/stages/dump.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::{ corpus::{Corpus, CorpusId, Testcase}, - inputs::Input, + inputs::{generate_name, Input}, stages::Stage, state::{HasCorpus, HasRand, HasSolutions}, Error, HasMetadata, @@ -106,7 +106,7 @@ where [ Some(id.0.to_string()), testcase.filename().clone(), - testcase.input().as_ref().map(|t| t.generate_name()), + // testcase.input().as_ref().map(|t| generate_name(&t)), ] .iter() .flatten() diff --git a/libafl/src/stages/sync.rs b/libafl/src/stages/sync.rs index 5d8ecd6c5b..a17e6ecf6b 100644 --- a/libafl/src/stages/sync.rs +++ b/libafl/src/stages/sync.rs @@ -4,7 +4,7 @@ use alloc::{ borrow::{Cow, ToOwned}, vec::Vec, }; -use core::{marker::PhantomData, time::Duration}; +use core::{hash::Hash, marker::PhantomData, time::Duration}; use std::path::{Path, PathBuf}; use libafl_bolts::{current_time, fs::find_new_files_rec, shmem::ShMemProvider, Named}; @@ -249,8 +249,8 @@ where + ExecutionProcessor::Input, E::Observers, S>, IC: InputConverter::Input, To = DI>, ICB: InputConverter::Input>, - DI: Input, - <::Corpus as Corpus>::Input: Input + Clone, + DI: Input + Hash, + <::Corpus as Corpus>::Input: Input + Clone + Hash, { #[inline] fn perform( diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 3e41cd65a4..2d08f4038c 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -6,6 +6,7 @@ use core::{ borrow::BorrowMut, cell::{Ref, RefMut}, fmt::Debug, + hash::Hash, marker::PhantomData, time::Duration, }; @@ -628,7 +629,7 @@ impl HasNestedStageStatus for StdState { #[cfg(feature = "std")] impl StdState where - I: Input, + I: Input + Hash, C: Corpus::Input>, R: Rand, SC: Corpus::Input>, @@ -1078,7 +1079,7 @@ where impl StdState where - I: Input, + I: Input + Hash, C: Corpus::Input>, R: Rand, SC: Corpus::Input>, @@ -1210,7 +1211,7 @@ impl StdState, StdRand, InMemoryCorpus() -> Result, StdRand, InMemoryCorpus>, Error> where - I: Input, + I: Input + Hash, { StdState::new( StdRand::with_seed(0), From 846e19872e77f399fc83e4bb5c582e66c91f6245 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Sun, 12 Jan 2025 22:01:24 +0530 Subject: [PATCH 07/11] Revert "extract generate_name() from trait Input (broken)" This reverts commit 9e217be2810a8c33970846cdd380f542975cc05b. --- libafl/src/corpus/cached.rs | 8 ++++---- libafl/src/corpus/inmemory_ondisk.rs | 14 +++++++------- libafl/src/corpus/ondisk.rs | 5 ++--- libafl/src/events/broker_hooks/centralized.rs | 4 ++-- libafl/src/events/broker_hooks/mod.rs | 4 ++-- libafl/src/events/centralized.rs | 4 ++-- libafl/src/events/llmp/mod.rs | 4 ++-- libafl/src/events/mod.rs | 10 +++++----- libafl/src/executors/hooks/inprocess.rs | 3 +-- libafl/src/executors/hooks/unix.rs | 6 +++--- libafl/src/executors/hooks/windows.rs | 2 +- libafl/src/executors/inprocess/mod.rs | 1 - libafl/src/feedbacks/map.rs | 2 -- libafl/src/fuzzer/mod.rs | 10 ++++++---- libafl/src/inputs/encoded.rs | 18 ++++++++++++++++-- libafl/src/inputs/gramatron.rs | 18 ++++++++++++++++-- libafl/src/inputs/mod.rs | 17 +++++++++++------ libafl/src/stages/calibrate.rs | 4 ++-- libafl/src/stages/dump.rs | 4 ++-- libafl/src/stages/sync.rs | 6 +++--- libafl/src/state/mod.rs | 7 +++---- 21 files changed, 90 insertions(+), 61 deletions(-) diff --git a/libafl/src/corpus/cached.rs b/libafl/src/corpus/cached.rs index 37802425ce..2e21fee65c 100644 --- a/libafl/src/corpus/cached.rs +++ b/libafl/src/corpus/cached.rs @@ -1,7 +1,7 @@ //! The [`CachedOnDiskCorpus`] stores [`Testcase`]s to disk, keeping a subset of them in memory/cache, evicting in a FIFO manner. use alloc::{collections::vec_deque::VecDeque, string::String}; -use core::{cell::RefCell, hash::Hash}; +use core::cell::RefCell; use std::path::Path; use serde::{Deserialize, Serialize}; @@ -27,7 +27,7 @@ pub struct CachedOnDiskCorpus { impl CachedOnDiskCorpus where - I: Input + Hash, + I: Input, { fn cache_testcase<'a>( &'a self, @@ -57,7 +57,7 @@ where } impl Corpus for CachedOnDiskCorpus where - I: Input + Hash, + I: Input, { type Input = I; @@ -181,7 +181,7 @@ where impl HasTestcase for CachedOnDiskCorpus where - I: Input + Hash, + I: Input, { fn testcase(&self, id: CorpusId) -> Result>, Error> { Ok(self.get(id)?.borrow()) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index 31cd13e4cf..988b9475e3 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -5,7 +5,7 @@ //! which only stores a certain number of [`Testcase`]s and removes additional ones in a FIFO manner. use alloc::string::{String, ToString}; -use core::{cell::RefCell, hash::Hash}; +use core::cell::RefCell; use std::{ fs, fs::{File, OpenOptions}, @@ -25,7 +25,7 @@ use super::{ }; use crate::{ corpus::{Corpus, CorpusId, InMemoryCorpus, Testcase}, - inputs::{generate_name, Input}, + inputs::Input, Error, HasMetadata, }; @@ -62,7 +62,7 @@ pub struct InMemoryOnDiskCorpus { impl Corpus for InMemoryOnDiskCorpus where - I: Input + Hash, + I: Input, { type Input = I; @@ -214,7 +214,7 @@ where impl HasTestcase for InMemoryOnDiskCorpus where - I: Input + Hash, + I: Input, { fn testcase( &self, @@ -378,11 +378,11 @@ impl InMemoryOnDiskCorpus { fn save_testcase(&self, testcase: &mut Testcase) -> Result<(), Error> where - I: Input + Hash, + I: Input, { let file_name = testcase.filename_mut().take().unwrap_or_else(|| { // TODO walk entry metadata to ask for pieces of filename (e.g. :havoc in AFL) - generate_name(testcase.input().as_ref().unwrap()) + testcase.input().as_ref().unwrap().generate_name() }); let mut ctr = String::new(); @@ -469,7 +469,7 @@ impl InMemoryOnDiskCorpus { let ctr = fs::read_to_string(&lockfile_path)?; if ctr == "1" { - FileExt::unlock(&lockfile)?; + lockfile.unlock()?; drop(fs::remove_file(lockfile_path)); } else { fs::write(lockfile_path, (ctr.parse::()? - 1).to_string())?; diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 9142926850..5c6569538f 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -8,7 +8,6 @@ use alloc::string::String; use core::{ cell::{Ref, RefCell, RefMut}, - hash::Hash, time::Duration, }; use std::path::{Path, PathBuf}; @@ -59,7 +58,7 @@ pub struct OnDiskCorpus { impl Corpus for OnDiskCorpus where - I: Input + Hash, + I: Input, { type Input = I; /// Returns the number of all enabled entries @@ -177,7 +176,7 @@ where impl HasTestcase for OnDiskCorpus where - I: Input + Hash, + I: Input, { fn testcase(&self, id: CorpusId) -> Result>, Error> { Ok(self.get(id)?.borrow()) diff --git a/libafl/src/events/broker_hooks/centralized.rs b/libafl/src/events/broker_hooks/centralized.rs index 92f9ea2661..831ae29fcb 100644 --- a/libafl/src/events/broker_hooks/centralized.rs +++ b/libafl/src/events/broker_hooks/centralized.rs @@ -1,5 +1,5 @@ use alloc::vec::Vec; -use core::{fmt::Debug, hash::Hash, marker::PhantomData}; +use core::{fmt::Debug, marker::PhantomData}; #[cfg(feature = "llmp_compression")] use libafl_bolts::{compress::GzipCompressor, llmp::LLMP_FLAG_COMPRESSED}; @@ -77,7 +77,7 @@ impl Debug for CentralizedLlmpHook { impl CentralizedLlmpHook where - I: Input + Hash, + I: Input, { /// Create an event broker from a raw broker. pub fn new() -> Result { diff --git a/libafl/src/events/broker_hooks/mod.rs b/libafl/src/events/broker_hooks/mod.rs index ad750a20a2..cc3d470b9d 100644 --- a/libafl/src/events/broker_hooks/mod.rs +++ b/libafl/src/events/broker_hooks/mod.rs @@ -1,6 +1,6 @@ //! Hooks called on broker side use alloc::vec::Vec; -use core::{hash::Hash, marker::PhantomData}; +use core::marker::PhantomData; #[cfg(feature = "llmp_compression")] use libafl_bolts::{compress::GzipCompressor, llmp::LLMP_FLAG_COMPRESSED}; @@ -90,7 +90,7 @@ where impl StdLlmpEventHook where - I: Input + Hash, + I: Input, MT: Monitor, { /// Create an event broker from a raw broker. diff --git a/libafl/src/events/centralized.rs b/libafl/src/events/centralized.rs index c7fddfa3c5..9d818e8686 100644 --- a/libafl/src/events/centralized.rs +++ b/libafl/src/events/centralized.rs @@ -8,7 +8,7 @@ // 4. The "main broker", the gathers the stats from the fuzzer clients and broadcast the newly found testcases from the main evaluator. use alloc::{boxed::Box, string::String, vec::Vec}; -use core::{fmt::Debug, hash::Hash, time::Duration}; +use core::{fmt::Debug, time::Duration}; use std::{marker::PhantomData, process}; #[cfg(feature = "llmp_compression")] @@ -495,7 +495,7 @@ where #[cfg(feature = "llmp_compression")] fn forward_to_main(&mut self, event: &Event) -> Result<(), Error> where - I: Input + Hash, + I: Input, { let serialized = postcard::to_allocvec(event)?; let flags = LLMP_FLAG_INITIALIZED; diff --git a/libafl/src/events/llmp/mod.rs b/libafl/src/events/llmp/mod.rs index e952bfb287..629ff6006a 100644 --- a/libafl/src/events/llmp/mod.rs +++ b/libafl/src/events/llmp/mod.rs @@ -1,7 +1,7 @@ //! LLMP-backed event manager for scalable multi-processed fuzzing use alloc::{boxed::Box, vec::Vec}; -use core::{hash::Hash, marker::PhantomData, time::Duration}; +use core::{marker::PhantomData, time::Duration}; #[cfg(feature = "llmp_compression")] use libafl_bolts::{ @@ -258,7 +258,7 @@ where SP: ShMemProvider, IC: InputConverter, ICB: InputConverter, - DI: Input + Hash, + DI: Input, { // TODO other new_* routines diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index f0ccb32b13..5adf188bd2 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -22,7 +22,7 @@ pub mod broker_hooks; use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec}; use core::{ fmt, - hash::{BuildHasher, Hash, Hasher}, + hash::{BuildHasher, Hasher}, marker::PhantomData, time::Duration, }; @@ -47,7 +47,7 @@ use uuid::Uuid; use crate::state::HasClientPerfMonitor; use crate::{ executors::ExitKind, - inputs::{generate_name, Input}, + inputs::Input, monitors::UserStats, observers::ObserversTuple, state::{HasExecutions, HasLastReportTime, State}, @@ -266,7 +266,7 @@ where #[serde(bound = "I: serde::de::DeserializeOwned")] pub enum Event where - I: Input + Hash, + I: Input, { // TODO use an ID to keep track of the original index in the sender Corpus // The sender can then use it to send Testcase metadata with CustomEvent @@ -355,7 +355,7 @@ where impl Event where - I: Input + Hash, + I: Input, { /// Event's corresponding name pub fn name(&self) -> &str { @@ -379,7 +379,7 @@ where fn name_detailed(&self) -> Cow<'static, str> { match self { Event::NewTestcase { input, .. } => { - Cow::Owned(format!("Testcase {}", generate_name(input))) + Cow::Owned(format!("Testcase {}", input.generate_name())) } Event::UpdateExecStats { .. } => Cow::Borrowed("Client Heartbeat"), Event::UpdateUserStats { .. } => Cow::Borrowed("UserStats"), diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index 63769ffe7a..36ec47bbc5 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -5,7 +5,6 @@ use core::mem::zeroed; use core::sync::atomic::{compiler_fence, Ordering}; use core::{ ffi::c_void, - hash::Hash, marker::PhantomData, ptr::{self, null_mut}, time::Duration, @@ -237,7 +236,7 @@ where E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective, <::State as HasSolutions>::Solutions: Corpus, //delete me - <<::State as HasCorpus>::Corpus as Corpus>::Input: Clone + Hash, //delete me + <<::State as HasCorpus>::Corpus as Corpus>::Input: Clone, //delete me { // # Safety // We get a pointer to `GLOBAL_STATE` that will be initialized at this point in time. diff --git a/libafl/src/executors/hooks/unix.rs b/libafl/src/executors/hooks/unix.rs index 316138c58b..4ff154b468 100644 --- a/libafl/src/executors/hooks/unix.rs +++ b/libafl/src/executors/hooks/unix.rs @@ -2,7 +2,7 @@ #[cfg(unix)] pub mod unix_signal_handler { use alloc::{boxed::Box, string::String, vec::Vec}; - use core::{hash::Hash, mem::transmute}; + use core::mem::transmute; use std::{io::Write, panic}; use libafl_bolts::os::unix_signals::{ucontext_t, Signal, SignalHandler}; @@ -19,7 +19,7 @@ pub mod unix_signal_handler { }, feedbacks::Feedback, fuzzer::HasObjective, - inputs::{generate_name, UsesInput}, + inputs::{Input, UsesInput}, observers::ObserversTuple, state::{HasCorpus, HasExecutions, HasSolutions, UsesState}, }; @@ -216,7 +216,7 @@ pub mod unix_signal_handler { let mut bsod = Vec::new(); { let mut writer = std::io::BufWriter::new(&mut bsod); - // let _ = writeln!(writer, "input: {:?}", generate_name(&input)); + let _ = writeln!(writer, "input: {:?}", input.generate_name()); let bsod = libafl_bolts::minibsod::generate_minibsod( &mut writer, signal, diff --git a/libafl/src/executors/hooks/windows.rs b/libafl/src/executors/hooks/windows.rs index a3ae6e7a5a..f0554848e9 100644 --- a/libafl/src/executors/hooks/windows.rs +++ b/libafl/src/executors/hooks/windows.rs @@ -417,7 +417,7 @@ pub mod windows_exception_handler { let mut bsod = Vec::new(); { let mut writer = std::io::BufWriter::new(&mut bsod); - writeln!(writer, "input: {:?}", input.generate_name()).unwrap(); + writeln!(writer, "input: {:?}", input.generate_name(None)).unwrap(); libafl_bolts::minibsod::generate_minibsod(&mut writer, exception_pointers) .unwrap(); writer.flush().unwrap(); diff --git a/libafl/src/executors/inprocess/mod.rs b/libafl/src/executors/inprocess/mod.rs index 28d93b823c..0efb911448 100644 --- a/libafl/src/executors/inprocess/mod.rs +++ b/libafl/src/executors/inprocess/mod.rs @@ -7,7 +7,6 @@ use core::{ borrow::BorrowMut, ffi::c_void, fmt::{self, Debug, Formatter}, - hash::Hash, marker::PhantomData, ptr, time::Duration, diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 76a934bbaf..7e8cb9700a 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -5,7 +5,6 @@ use alloc::{borrow::Cow, vec::Vec}; use core::simd::prelude::SimdOrd; use core::{ fmt::Debug, - hash::Hash, marker::PhantomData, ops::{BitAnd, BitOr, Deref, DerefMut}, }; @@ -403,7 +402,6 @@ where OT: MatchName, R: Reducer, S: HasNamedMetadata + UsesInput, // delete me - ::Input: Hash, { #[rustversion::nightly] default fn is_interesting( diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index cc0ce18a21..1b8e41daa6 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -1,7 +1,9 @@ //! The `Fuzzer` is the main struct for a fuzz campaign. use alloc::{string::ToString, vec::Vec}; -use core::{fmt::Debug, hash::Hash, time::Duration}; +use core::{fmt::Debug, time::Duration}; +#[cfg(feature = "std")] +use std::hash::Hash; #[cfg(feature = "std")] use fastbloom::BloomFilter; @@ -315,7 +317,7 @@ where F: Feedback::Input, OT, S>, OF: Feedback::Input, OT, S>, OT: ObserversTuple<::Input, S> + Serialize, - ::Input: Input + Hash, + ::Input: Input, S::Solutions: Corpus::Input>, { fn check_results( @@ -523,7 +525,7 @@ where + UsesInput::Input> + HasExecutions + HasLastFoundTime, - ::Input: Input + Hash, + ::Input: Input, S::Solutions: Corpus::Input>, { /// Process one input, adding to the respective corpora if needed and firing the right events @@ -601,7 +603,7 @@ where + HasLastFoundTime + HasExecutions + UsesInput::Input>, - ::Input: Input + Hash, + ::Input: Input, S::Solutions: Corpus::Input>, IF: InputFilter<::Input>, { diff --git a/libafl/src/inputs/encoded.rs b/libafl/src/inputs/encoded.rs index 4f9bc8de91..f5ddf0c971 100644 --- a/libafl/src/inputs/encoded.rs +++ b/libafl/src/inputs/encoded.rs @@ -6,10 +6,14 @@ #[cfg(feature = "regex")] use alloc::string::ToString; use alloc::{borrow::ToOwned, rc::Rc, string::String, vec::Vec}; -use core::cell::RefCell; #[cfg(feature = "regex")] use core::str::from_utf8; +use core::{ + cell::RefCell, + hash::{BuildHasher, Hasher}, +}; +use ahash::RandomState; use hashbrown::HashMap; use libafl_bolts::{Error, HasLen}; #[cfg(feature = "regex")] @@ -195,7 +199,17 @@ pub struct EncodedInput { codes: Vec, } -impl Input for EncodedInput {} +impl Input for EncodedInput { + /// Generate a name for this input + #[must_use] + fn generate_name(&self) -> String { + let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); + for code in &self.codes { + hasher.write(&code.to_le_bytes()); + } + format!("{:016x}", hasher.finish()) + } +} /// Rc Ref-cell from Input impl From for Rc> { diff --git a/libafl/src/inputs/gramatron.rs b/libafl/src/inputs/gramatron.rs index c65f925290..790181e6d4 100644 --- a/libafl/src/inputs/gramatron.rs +++ b/libafl/src/inputs/gramatron.rs @@ -1,7 +1,11 @@ //! The gramatron grammar fuzzer use alloc::{rc::Rc, string::String, vec::Vec}; -use core::cell::RefCell; +use core::{ + cell::RefCell, + hash::{BuildHasher, Hasher}, +}; +use ahash::RandomState; use libafl_bolts::{Error, HasLen}; use serde::{Deserialize, Serialize}; @@ -37,7 +41,17 @@ pub struct GramatronInput { terms: Vec, } -impl Input for GramatronInput {} +impl Input for GramatronInput { + /// Generate a name for this input + #[must_use] + fn generate_name(&self) -> String { + let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); + for term in &self.terms { + hasher.write(term.symbol.as_bytes()); + } + format!("{:016x}", hasher.finish()) + } +} /// Rc Ref-cell from Input impl From for Rc> { diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index e369245071..4a3658280c 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -55,7 +55,7 @@ use serde::{Deserialize, Serialize}; /// An input for the target #[cfg(not(feature = "std"))] -pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { +pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash { /// Write this input to the file fn to_file

(&self, _path: P) -> Result<(), Error> { Err(Error::not_implemented("Not supported in no_std")) @@ -65,11 +65,16 @@ pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { fn from_file

(_path: P) -> Result { Err(Error::not_implemented("Not supprted in no_std")) } + + /// Generate a name for this input + fn generate_name(&self) -> String { + format!("{:016x}", generic_hash_std(self)) + } } /// An input for the target #[cfg(feature = "std")] -pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { +pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug + Hash { /// Write this input to the file fn to_file

(&self, path: P) -> Result<(), Error> where @@ -88,11 +93,11 @@ pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug { file.read_to_end(&mut bytes)?; Ok(postcard::from_bytes(&bytes)?) } -} -// Generate a name for given input -pub fn generate_name(input: I) -> String { - format!("{:016x}", generic_hash_std(&input)) + /// Generate a name for this input, the user is responsible for making each name of testcase unique. + fn generate_name(&self) -> String { + format!("{:016x}", generic_hash_std(self)) + } } /// Convert between two input types with a state diff --git a/libafl/src/stages/calibrate.rs b/libafl/src/stages/calibrate.rs index d232356606..50c07aeb09 100644 --- a/libafl/src/stages/calibrate.rs +++ b/libafl/src/stages/calibrate.rs @@ -5,7 +5,7 @@ use alloc::{ string::ToString, vec::Vec, }; -use core::{fmt::Debug, hash::Hash, marker::PhantomData, time::Duration}; +use core::{fmt::Debug, marker::PhantomData, time::Duration}; use hashbrown::HashSet; use libafl_bolts::{current_time, impl_serdeany, tuples::Handle, AsIter, Named}; @@ -103,7 +103,7 @@ where + HasCurrentCorpusId + UsesInput::Input>, Z: Evaluator::Input, S>, - ::Input: Input + Hash, + ::Input: Input, { #[inline] #[expect(clippy::too_many_lines, clippy::cast_precision_loss)] diff --git a/libafl/src/stages/dump.rs b/libafl/src/stages/dump.rs index f657bc26ec..070c5e7a57 100644 --- a/libafl/src/stages/dump.rs +++ b/libafl/src/stages/dump.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::{ corpus::{Corpus, CorpusId, Testcase}, - inputs::{generate_name, Input}, + inputs::Input, stages::Stage, state::{HasCorpus, HasRand, HasSolutions}, Error, HasMetadata, @@ -106,7 +106,7 @@ where [ Some(id.0.to_string()), testcase.filename().clone(), - // testcase.input().as_ref().map(|t| generate_name(&t)), + testcase.input().as_ref().map(|t| t.generate_name()), ] .iter() .flatten() diff --git a/libafl/src/stages/sync.rs b/libafl/src/stages/sync.rs index a17e6ecf6b..5d8ecd6c5b 100644 --- a/libafl/src/stages/sync.rs +++ b/libafl/src/stages/sync.rs @@ -4,7 +4,7 @@ use alloc::{ borrow::{Cow, ToOwned}, vec::Vec, }; -use core::{hash::Hash, marker::PhantomData, time::Duration}; +use core::{marker::PhantomData, time::Duration}; use std::path::{Path, PathBuf}; use libafl_bolts::{current_time, fs::find_new_files_rec, shmem::ShMemProvider, Named}; @@ -249,8 +249,8 @@ where + ExecutionProcessor::Input, E::Observers, S>, IC: InputConverter::Input, To = DI>, ICB: InputConverter::Input>, - DI: Input + Hash, - <::Corpus as Corpus>::Input: Input + Clone + Hash, + DI: Input, + <::Corpus as Corpus>::Input: Input + Clone, { #[inline] fn perform( diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 2d08f4038c..3e41cd65a4 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -6,7 +6,6 @@ use core::{ borrow::BorrowMut, cell::{Ref, RefMut}, fmt::Debug, - hash::Hash, marker::PhantomData, time::Duration, }; @@ -629,7 +628,7 @@ impl HasNestedStageStatus for StdState { #[cfg(feature = "std")] impl StdState where - I: Input + Hash, + I: Input, C: Corpus::Input>, R: Rand, SC: Corpus::Input>, @@ -1079,7 +1078,7 @@ where impl StdState where - I: Input + Hash, + I: Input, C: Corpus::Input>, R: Rand, SC: Corpus::Input>, @@ -1211,7 +1210,7 @@ impl StdState, StdRand, InMemoryCorpus() -> Result, StdRand, InMemoryCorpus>, Error> where - I: Input + Hash, + I: Input, { StdState::new( StdRand::with_seed(0), From b6f7a3b43c2f283e1d844c2af822fb325823e112 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Mon, 13 Jan 2025 16:23:29 +0530 Subject: [PATCH 08/11] fix ci errors --- Cargo.toml | 2 +- libafl/Cargo.toml | 5 +++-- libafl/src/corpus/inmemory_ondisk.rs | 2 +- libafl/src/executors/hooks/windows.rs | 2 +- libafl/src/inputs/multi.rs | 6 +++--- libafl/src/inputs/nautilus.rs | 21 ++------------------- libafl/src/stages/dump.rs | 2 +- 7 files changed, 12 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e9b45279c..82c84050a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,7 +123,7 @@ uuid = { version = "1.10.0", features = ["serde", "v4"] } which = "6.0.3" windows = "0.59.0" z3 = "0.12.1" -fs2 = "0.4.3" +fs2 = "0.4.3" # Used by OnDisk Corpus for file locking [workspace.lints.rust] # Forbid diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index db23b45ce5..124d670807 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -39,7 +39,6 @@ default = [ "regex", "serdeany_autoreg", "libafl_bolts/xxh3", - "fs2" ] document-features = ["dep:document-features"] @@ -60,6 +59,7 @@ std = [ "libafl_bolts/std", "typed-builder", "fastbloom", + "fs2" ] ## Tracks the Feedbacks and the Objectives that were interesting for a Testcase @@ -285,6 +285,8 @@ const_panic = { version = "0.2.9", default-features = false } # similarly, for f pyo3 = { workspace = true, optional = true } regex-syntax = { version = "0.8.4", optional = true } # For nautilus +fs2 = { workspace = true, optional = true } # used by OnDisk Corpus for file locking + # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) serial_test = { workspace = true, optional = true, default-features = false, features = [ "logging", @@ -297,7 +299,6 @@ clap = { workspace = true, optional = true } num_enum = { workspace = true, optional = true } libipt = { workspace = true, optional = true } fastbloom = { workspace = true, optional = true } -fs2 = { workspace = true, optional = true } [lints] workspace = true diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index 988b9475e3..e110a271f9 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -469,7 +469,7 @@ impl InMemoryOnDiskCorpus { let ctr = fs::read_to_string(&lockfile_path)?; if ctr == "1" { - lockfile.unlock()?; + FileExt::unlock(&lockfile)?; drop(fs::remove_file(lockfile_path)); } else { fs::write(lockfile_path, (ctr.parse::()? - 1).to_string())?; diff --git a/libafl/src/executors/hooks/windows.rs b/libafl/src/executors/hooks/windows.rs index fdcf0b88f5..950d66128e 100644 --- a/libafl/src/executors/hooks/windows.rs +++ b/libafl/src/executors/hooks/windows.rs @@ -433,7 +433,7 @@ pub mod windows_exception_handler { let mut bsod = Vec::new(); { let mut writer = std::io::BufWriter::new(&mut bsod); - writeln!(writer, "input: {:?}", input.generate_name(None)).unwrap(); + writeln!(writer, "input: {:?}", input.generate_name()).unwrap(); libafl_bolts::minibsod::generate_minibsod(&mut writer, exception_pointers) .unwrap(); writer.flush().unwrap(); diff --git a/libafl/src/inputs/multi.rs b/libafl/src/inputs/multi.rs index ce7007de21..c2d632a138 100644 --- a/libafl/src/inputs/multi.rs +++ b/libafl/src/inputs/multi.rs @@ -16,7 +16,7 @@ use crate::{corpus::CorpusId, inputs::Input}; /// An input composed of multiple parts. Use in situations where subcomponents are not necessarily /// related, or represent distinct parts of the input. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, Hash)] pub struct MultipartInput { parts: Vec, names: Vec, @@ -153,14 +153,14 @@ impl Input for MultipartInput where I: Input, { - fn generate_name(&self, id: Option) -> String { + fn generate_name(&self) -> String { if self.names().is_empty() { "empty_multipart_input".to_string() // empty strings cause issues with OnDiskCorpus } else { self.names .iter() .cloned() - .zip(self.parts.iter().map(|i| i.generate_name(id))) + .zip(self.parts.iter().map(|i| i.generate_name())) .map(|(name, generated)| format!("{name}-{generated}")) .collect::>() .join(",") diff --git a/libafl/src/inputs/nautilus.rs b/libafl/src/inputs/nautilus.rs index 2a87a4d2be..2ac73d97b0 100644 --- a/libafl/src/inputs/nautilus.rs +++ b/libafl/src/inputs/nautilus.rs @@ -1,7 +1,7 @@ //! Input for the [`Nautilus`](https://github.com/RUB-SysSec/nautilus) grammar fuzzer methods //! //! -use alloc::{rc::Rc, string::String, vec::Vec}; +use alloc::{rc::Rc, vec::Vec}; use core::cell::RefCell; use std::hash::{Hash, Hasher}; @@ -15,7 +15,6 @@ use crate::{ rule::RuleIdOrCustom, tree::{Tree, TreeLike}, }, - corpus::CorpusId, generators::nautilus::NautilusContext, inputs::{BytesInput, Input, InputConverter}, Error, @@ -28,23 +27,7 @@ pub struct NautilusInput { pub tree: Tree, } -impl Input for NautilusInput { - /// Generate a name for this input - #[must_use] - fn generate_name(&self, id: Option) -> String { - /*let mut hasher = AHasher::new_with_keys(0, 0); - for term in &self.terms { - hasher.write(term.symbol.as_bytes()); - } - format!("{:016x}", hasher.finish())*/ - - if let Some(id) = id { - format!("id_{}", id.0) - } else { - "id_unknown".into() - } - } -} +impl Input for NautilusInput {} /// Rc Ref-cell from Input impl From for Rc> { diff --git a/libafl/src/stages/dump.rs b/libafl/src/stages/dump.rs index 070c5e7a57..a821a9e46a 100644 --- a/libafl/src/stages/dump.rs +++ b/libafl/src/stages/dump.rs @@ -106,7 +106,7 @@ where [ Some(id.0.to_string()), testcase.filename().clone(), - testcase.input().as_ref().map(|t| t.generate_name()), + testcase.input().as_ref().map(Input::generate_name), ] .iter() .flatten() From 85afcf678223288930e44c547931782f7b11c90e Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Mon, 13 Jan 2025 16:51:54 +0530 Subject: [PATCH 09/11] remove CorpusId from generate_name() calls --- fuzzers/baby/tutorial/src/input.rs | 10 +--------- .../baby_fuzzer_custom_input/src/input.rs | 9 ++------- libafl_libfuzzer/runtime/src/corpus.rs | 2 +- libafl_libfuzzer/runtime/src/feedbacks.rs | 2 +- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/fuzzers/baby/tutorial/src/input.rs b/fuzzers/baby/tutorial/src/input.rs index f21eaa4199..3f58a7e24f 100644 --- a/fuzzers/baby/tutorial/src/input.rs +++ b/fuzzers/baby/tutorial/src/input.rs @@ -48,15 +48,7 @@ pub enum PacketType { Reset = 0x2, } -impl Input for PacketData { - fn generate_name(&self, id: Option) -> String { - if let Some(id) = id { - format!("id_{}", id.0) - } else { - "id_unknown".into() - } - } -} +impl Input for PacketData {} impl HasTargetBytes for PacketData { #[inline] diff --git a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs index 184f27f7b3..d531e584ca 100644 --- a/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs +++ b/fuzzers/structure_aware/baby_fuzzer_custom_input/src/input.rs @@ -2,14 +2,13 @@ use core::num::NonZeroUsize; use std::{borrow::Cow, hash::Hash}; use libafl::{ - corpus::CorpusId, generators::{Generator, RandBytesGenerator}, inputs::{BytesInput, HasTargetBytes, Input}, mutators::{MutationResult, Mutator}, state::HasRand, Error, SerdeAny, }; -use libafl_bolts::{generic_hash_std, rands::Rand, Named}; +use libafl_bolts::{rands::Rand, Named}; use serde::{Deserialize, Serialize}; /// The custom [`Input`] type used in this example, consisting of a byte array part, a byte array that is not always present, and a boolean @@ -28,11 +27,7 @@ pub struct CustomInput { } /// Hash-based implementation -impl Input for CustomInput { - fn generate_name(&self, _id: Option) -> String { - format!("{:016x}", generic_hash_std(self)) - } -} +impl Input for CustomInput {} impl CustomInput { /// Returns a mutable reference to the byte array diff --git a/libafl_libfuzzer/runtime/src/corpus.rs b/libafl_libfuzzer/runtime/src/corpus.rs index a5ec612193..17099072dc 100644 --- a/libafl_libfuzzer/runtime/src/corpus.rs +++ b/libafl_libfuzzer/runtime/src/corpus.rs @@ -119,7 +119,7 @@ where "The testcase, when added to the corpus, must have an input present!", ) })?; - let name = input.generate_name(Some(id)); + let name = input.generate_name(); let path = self.corpus_dir.join(&name); match input.to_file(&path) { diff --git a/libafl_libfuzzer/runtime/src/feedbacks.rs b/libafl_libfuzzer/runtime/src/feedbacks.rs index e67b5f8a72..0f2e21b35b 100644 --- a/libafl_libfuzzer/runtime/src/feedbacks.rs +++ b/libafl_libfuzzer/runtime/src/feedbacks.rs @@ -104,7 +104,7 @@ impl LibfuzzerCrashCauseFeedback { let base = if let Some(filename) = testcase.filename() { filename.clone() } else { - let name = testcase.input().as_ref().unwrap().generate_name(None); + let name = testcase.input().as_ref().unwrap().generate_name(); name }; let file_path = self.artifact_prefix.dir().join(format!( From 0025607b9fda86b9166761eb3c0df8789ffe7c38 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Mon, 13 Jan 2025 23:36:04 +0530 Subject: [PATCH 10/11] toml formatting --- fuzzers/baby/tutorial/src/input.rs | 5 +---- libafl/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/fuzzers/baby/tutorial/src/input.rs b/fuzzers/baby/tutorial/src/input.rs index 3f58a7e24f..c46e85d59b 100644 --- a/fuzzers/baby/tutorial/src/input.rs +++ b/fuzzers/baby/tutorial/src/input.rs @@ -2,10 +2,7 @@ use std::hash::Hash; use lain::prelude::*; -use libafl::{ - corpus::CorpusId, - inputs::{HasTargetBytes, Input}, -}; +use libafl::inputs::{HasTargetBytes, Input}; use libafl_bolts::{ownedref::OwnedSlice, HasLen}; use serde::{Deserialize, Serialize}; diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 124d670807..667b101494 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -59,7 +59,7 @@ std = [ "libafl_bolts/std", "typed-builder", "fastbloom", - "fs2" + "fs2", ] ## Tracks the Feedbacks and the Objectives that were interesting for a Testcase From ef6fcc1187303f98c16e8eda27eb0a2449b036f7 Mon Sep 17 00:00:00 2001 From: Dhanvith Nayak Date: Wed, 15 Jan 2025 11:52:39 +0530 Subject: [PATCH 11/11] write from file instead of fs --- libafl/src/corpus/inmemory_ondisk.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index e110a271f9..f1b538846b 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -11,6 +11,7 @@ use std::{ fs::{File, OpenOptions}, io, io::Write, + io::Read, path::{Path, PathBuf}, }; @@ -34,7 +35,7 @@ use crate::{ /// If the create fails for _any_ reason, including, but not limited to, a preexisting existing file of that name, /// it will instead return the respective [`io::Error`]. fn create_new>(path: P) -> Result { - OpenOptions::new().write(true).create_new(true).open(path) + OpenOptions::new().write(true).read(true).create_new(true).open(path) } /// Tries to create the given `path` and returns `None` _only_ if the file already existed. @@ -390,18 +391,19 @@ impl InMemoryOnDiskCorpus { let lockfile_name = format!(".{file_name}"); let lockfile_path = self.dir_path.join(lockfile_name); - let lockfile = try_create_new(&lockfile_path)? - .unwrap_or(OpenOptions::new().write(true).open(&lockfile_path)?); + let mut lockfile = try_create_new(&lockfile_path)? + .unwrap_or(OpenOptions::new().write(true).read(true).open(&lockfile_path)?); lockfile.lock_exclusive()?; - ctr = fs::read_to_string(&lockfile_path)?.trim().to_string(); + lockfile.read_to_string(&mut ctr)?; + ctr = ctr.trim().to_string(); if ctr.is_empty() { ctr = String::from("1"); } else { ctr = (ctr.parse::()? + 1).to_string(); } - fs::write(lockfile_path, &ctr)?; + lockfile.write_all(ctr.as_bytes())?; } if testcase.file_path().is_none() { @@ -463,16 +465,18 @@ impl InMemoryOnDiskCorpus { if let Some(filename) = testcase.filename() { if self.locking { let lockfile_path = self.dir_path.join(format!(".{filename}")); - let lockfile = OpenOptions::new().write(true).open(&lockfile_path)?; + let mut lockfile = OpenOptions::new().write(true).read(true).open(&lockfile_path)?; lockfile.lock_exclusive()?; - let ctr = fs::read_to_string(&lockfile_path)?; + let mut ctr = String::new(); + lockfile.read_to_string(&mut ctr)?; + ctr = ctr.trim().to_string(); if ctr == "1" { FileExt::unlock(&lockfile)?; drop(fs::remove_file(lockfile_path)); } else { - fs::write(lockfile_path, (ctr.parse::()? - 1).to_string())?; + lockfile.write_all(&(ctr.parse::()? - 1).to_le_bytes())?; return Ok(()); } }