diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 2008ab070b..644c2a8557 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -61,6 +61,9 @@ handle_sigpipe = [] ## Enables `TcpEventManager`, a simple EventManager proxying everything via TCP. This uses `tokio`. tcp_manager = ["tokio", "std"] +## Enables compression for the TCP manager +tcp_compression = ["tcp_manager", "libafl_bolts/gzip"] + ## Enables the `NaiveTokenizer` and `StacktraceObserver` regex = ["std", "dep:regex"] diff --git a/libafl/build.rs b/libafl/build.rs index 33156a1c05..c5d5e43f71 100644 --- a/libafl/build.rs +++ b/libafl/build.rs @@ -1,20 +1,20 @@ -use std::error::Error; +#![forbid(unexpected_cfgs)] #[rustversion::nightly] -#[allow(clippy::unnecessary_wraps)] -fn main() -> Result<(), Box> { - println!("cargo:rerun-if-changed=build.rs"); +fn nightly() { println!("cargo:rustc-cfg=nightly"); - Ok(()) } #[rustversion::not(nightly)] -#[allow(clippy::unnecessary_wraps)] -fn main() -> Result<(), Box> { - println!("cargo:rerun-if-changed=build.rs"); +fn nightly() { assert!( cfg!(all(not(docrs), not(feature = "nautilus"))), "The 'nautilus' feature of libafl requires a nightly compiler" ); - Ok(()) +} + +fn main() { + println!("cargo:rustc-check-cfg=cfg(nightly)"); + println!("cargo:rerun-if-changed=build.rs"); + nightly(); } diff --git a/libafl/src/corpus/inmemory_ondisk.rs b/libafl/src/corpus/inmemory_ondisk.rs index ccd3c49cc4..90a7d170a5 100644 --- a/libafl/src/corpus/inmemory_ondisk.rs +++ b/libafl/src/corpus/inmemory_ondisk.rs @@ -435,9 +435,9 @@ where OnDiskMetadataFormat::Json => serde_json::to_vec(&ondisk_meta)?, OnDiskMetadataFormat::JsonPretty => serde_json::to_vec_pretty(&ondisk_meta)?, #[cfg(feature = "gzip")] - OnDiskMetadataFormat::JsonGzip => GzipCompressor::new(0) - .compress(&serde_json::to_vec_pretty(&ondisk_meta)?)? - .unwrap(), + OnDiskMetadataFormat::JsonGzip => { + GzipCompressor::new().compress(&serde_json::to_vec_pretty(&ondisk_meta)?) + } }; tmpfile.write_all(&serialized)?; fs::rename(&tmpfile_path, &metafile_path)?; diff --git a/libafl/src/events/centralized.rs b/libafl/src/events/centralized.rs index 547c751f93..a47658f935 100644 --- a/libafl/src/events/centralized.rs +++ b/libafl/src/events/centralized.rs @@ -86,7 +86,7 @@ where Ok(Self { llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), phantom: PhantomData, }) } @@ -100,7 +100,7 @@ where // TODO switch to false after solving the bug llmp: LlmpBroker::with_keep_pages_attach_to_tcp(shmem_provider, port, true)?, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), phantom: PhantomData, }) } @@ -475,7 +475,7 @@ where inner, client, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), is_main, }) } @@ -492,7 +492,7 @@ where inner, client, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), time_ref: time_obs.handle(), is_main, }) @@ -509,7 +509,7 @@ where inner, client, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), is_main, }) } @@ -531,7 +531,7 @@ where inner, client, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), time_ref: time_obs.handle(), is_main, }) @@ -550,7 +550,7 @@ where inner, client: LlmpClient::on_existing_from_env(shmem_provider, env_name)?, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), is_main, }) } @@ -569,7 +569,7 @@ where inner, client: LlmpClient::on_existing_from_env(shmem_provider, env_name)?, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), time_ref: time_obs.handle(), is_main, }) @@ -587,7 +587,7 @@ where inner, client: LlmpClient::existing_client_from_description(shmem_provider, description)?, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), is_main, }) } @@ -605,7 +605,7 @@ where inner, client: LlmpClient::existing_client_from_description(shmem_provider, description)?, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), time_ref: time_obs.handle(), is_main, }) @@ -642,7 +642,7 @@ where let serialized = postcard::to_allocvec(event)?; let flags = LLMP_FLAG_INITIALIZED; - match self.compressor.compress(&serialized)? { + match self.compressor.maybe_compress(&serialized) { Some(comp_buf) => { self.client.send_buf_with_flags( _LLMP_TAG_TO_MAIN, diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index e3df2f8179..983990ae1b 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -81,7 +81,7 @@ const _LLMP_TAG_RESTART: Tag = Tag(0x8357A87); const _LLMP_TAG_NO_RESTART: Tag = Tag(0x57A7EE71); /// The minimum buffer size at which to compress LLMP IPC messages. -#[cfg(feature = "llmp_compression")] +#[cfg(any(feature = "llmp_compression", feature = "tcp_compression"))] pub const COMPRESS_THRESHOLD: usize = 1024; /// An LLMP-backed event manager for scalable multi-processed fuzzing @@ -112,7 +112,7 @@ where monitor, llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), phantom: PhantomData, }) } @@ -126,7 +126,7 @@ where monitor, llmp: llmp::LlmpBroker::create_attach_to_tcp(shmem_provider, port)?, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), phantom: PhantomData, }) } @@ -451,7 +451,7 @@ where hooks: tuple_list!(), llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), configuration, phantom: PhantomData, custom_buf_handlers: vec![], @@ -506,7 +506,7 @@ where hooks: tuple_list!(), llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), configuration, serialization_time: Duration::ZERO, deserialization_time: Duration::ZERO, @@ -575,7 +575,7 @@ where hooks, llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), configuration, phantom: PhantomData, custom_buf_handlers: vec![], @@ -636,7 +636,7 @@ where hooks, llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), configuration, serialization_time: Duration::ZERO, deserialization_time: Duration::ZERO, @@ -855,7 +855,7 @@ where let serialized = postcard::to_allocvec(&event)?; let flags = LLMP_FLAG_INITIALIZED; - match self.compressor.compress(&serialized)? { + match self.compressor.maybe_compress(&serialized) { Some(comp_buf) => { self.llmp.send_buf_with_flags( LLMP_TAG_EVENT_TO_BOTH, @@ -1761,7 +1761,7 @@ where Ok(Self { llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), converter, converter_back, phantom: PhantomData, @@ -1781,7 +1781,7 @@ where Ok(Self { llmp, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), converter, converter_back, phantom: PhantomData, @@ -1800,7 +1800,7 @@ where Ok(Self { llmp: LlmpClient::on_existing_from_env(shmem_provider, env_name)?, #[cfg(feature = "llmp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::with_threshold(COMPRESS_THRESHOLD), phantom: PhantomData, converter, converter_back, @@ -1997,7 +1997,7 @@ where let serialized = postcard::to_allocvec(&converted_event)?; let flags = LLMP_FLAG_INITIALIZED; - match self.compressor.compress(&serialized)? { + match self.compressor.maybe_compress(&serialized) { Some(comp_buf) => { self.llmp.send_buf_with_flags( LLMP_TAG_EVENT_TO_BOTH, diff --git a/libafl/src/events/tcp.rs b/libafl/src/events/tcp.rs index 7c7e723128..09d9efbaf8 100644 --- a/libafl/src/events/tcp.rs +++ b/libafl/src/events/tcp.rs @@ -15,6 +15,8 @@ use std::{ sync::Arc, }; +#[cfg(feature = "tcp_compression")] +use libafl_bolts::compress::GzipCompressor; #[cfg(feature = "std")] use libafl_bolts::core_affinity::CoreId; #[cfg(all(feature = "std", any(windows, not(feature = "fork"))))] @@ -182,8 +184,7 @@ where // we forward the sender id as well, so we add 4 bytes to the message length len += 4; - #[cfg(feature = "tcp_debug")] - println!("len +4 = {len:?}"); + log::debug!("TCP Manager - len +4 = {len:?}"); let mut buf = vec![0; len as usize]; @@ -198,8 +199,7 @@ where return; } - #[cfg(feature = "tcp_debug")] - println!("len: {len:?} - {buf:?}"); + log::debug!("TCP Manager - len: {len:?} - {buf:?}"); tx_inner.send(buf).await.expect("Could not send"); } }; @@ -232,8 +232,7 @@ where _ => panic!("Could not receive"), }; - #[cfg(feature = "tcp_debug")] - println!("{buf:?}"); + log::debug!("TCP Manager - {buf:?}"); if buf.len() <= 4 { log::warn!("We got no contents (or only the length) in a broadcast"); @@ -241,9 +240,7 @@ where } if buf[..4] == this_client_id_bytes { - #[cfg(feature = "tcp_debug")] - eprintln!( - "Not forwarding message from this very client ({this_client_id:?})." + log::debug!("TCP Manager - Not forwarding message from this very client ({this_client_id:?})." ); continue; } @@ -287,8 +284,12 @@ where // cut off the ID. let event_bytes = &buf[4..]; - let event: Event = postcard::from_bytes(event_bytes).unwrap(); - match Self::handle_in_broker(&mut self.monitor, client_id, &event).unwrap() { + #[cfg(feature = "tcp_compression")] + let event_bytes = GzipCompressor::new().decompress(event_bytes)?; + + #[allow(clippy::needless_borrow)] // make decompressed vec and slice compatible + let event: Event = postcard::from_bytes(&event_bytes)?; + match Self::handle_in_broker(&mut self.monitor, client_id, &event)? { BrokerEventResult::Forward => { tx_bc.send(buf).expect("Could not send"); } @@ -300,9 +301,7 @@ where break; } } - - #[cfg(feature = "tcp_debug")] - println!("The last client quit. Exiting."); + log::info!("TCP Manager - The last client quit. Exiting."); Err(Error::shutting_down()) } @@ -551,7 +550,7 @@ where tcp, client_id, #[cfg(feature = "tcp_compression")] - compressor: GzipCompressor::new(COMPRESS_THRESHOLD), + compressor: GzipCompressor::new(), configuration, phantom: PhantomData, custom_buf_handlers: vec![], @@ -712,38 +711,17 @@ where EMH: EventManagerHooksTuple, S: State, { - #[cfg(feature = "tcp_compression")] fn fire( &mut self, _state: &mut Self::State, event: Event<::Input>, ) -> Result<(), Error> { let serialized = postcard::to_allocvec(&event)?; - let flags = TCP_FLAG_INITIALIZED; - match self.compressor.compress(&serialized)? { - Some(comp_buf) => { - self.tcp.send_buf_with_flags( - TCP_TAG_EVENT_TO_BOTH, - flags | TCP_FLAG_COMPRESSED, - &comp_buf, - )?; - } - None => { - self.tcp.send_buf(TCP_TAG_EVENT_TO_BOTH, &serialized)?; - } - } - Ok(()) - } + #[cfg(feature = "tcp_compression")] + let serialized = self.compressor.compress(&serialized); - #[cfg(not(feature = "tcp_compression"))] - fn fire( - &mut self, - _state: &mut Self::State, - event: Event<::Input>, - ) -> Result<(), Error> { - let serialized = postcard::to_allocvec(&event)?; - let size = u32::try_from(serialized.len()).unwrap(); + let size = u32::try_from(serialized.len())?; self.tcp.write_all(&size.to_le_bytes())?; self.tcp.write_all(&self.client_id.0.to_le_bytes())?; self.tcp.write_all(&serialized)?; @@ -796,7 +774,7 @@ where self.tcp.set_nonblocking(false).expect("set to blocking"); let len = u32::from_le_bytes(len_buf); let mut buf = vec![0_u8; len as usize + 4_usize]; - self.tcp.read_exact(&mut buf).unwrap(); + self.tcp.read_exact(&mut buf)?; let mut client_id_buf = [0_u8; 4]; client_id_buf.copy_from_slice(&buf[..4]); @@ -809,7 +787,14 @@ where } else { log::info!("{self_id:?} (from {other_client_id:?}) Received: {buf:?}"); - let event = postcard::from_bytes(&buf[4..])?; + let buf = &buf[4..]; + #[cfg(feature = "tcp_compression")] + let buf = self.compressor.decompress(buf)?; + + // make decompressed vec and slice compatible + #[allow(clippy::needless_borrow)] + let event = postcard::from_bytes(&buf)?; + self.handle_in_client(fuzzer, executor, state, other_client_id, event)?; count += 1; } diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index 9ad2d543fa..8bab35bdc9 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -4,6 +4,7 @@ Welcome to `LibAFL` #![doc = include_str!("../README.md")] /*! */ #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![forbid(unexpected_cfgs)] #![allow(incomplete_features)] #![no_std] // For `type_eq` diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 093f45f422..6401baaf29 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -26,7 +26,7 @@ use core::{fmt::Debug, time::Duration}; #[cfg(feature = "std")] use std::time::Instant; -#[cfg(feature = "no_std")] +#[cfg(not(feature = "std"))] use libafl_bolts::current_time; use libafl_bolts::{tuples::MatchName, Named}; pub use list::*; @@ -406,7 +406,7 @@ pub struct TimeObserver { #[serde(with = "instant_serializer")] start_time: Instant, - #[cfg(feature = "no_std")] + #[cfg(not(feature = "std"))] start_time: Duration, last_runtime: Option, @@ -448,7 +448,7 @@ impl TimeObserver { #[cfg(feature = "std")] start_time: Instant::now(), - #[cfg(feature = "no_std")] + #[cfg(not(feature = "std"))] start_time: Duration::from_secs(0), last_runtime: None, @@ -473,7 +473,7 @@ where Ok(()) } - #[cfg(feature = "no_std")] + #[cfg(not(feature = "std"))] fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.last_runtime = None; self.start_time = current_time(); @@ -491,7 +491,7 @@ where Ok(()) } - #[cfg(feature = "no_std")] + #[cfg(not(feature = "std"))] fn post_exec( &mut self, _state: &mut S, @@ -499,6 +499,7 @@ where _exit_kind: &ExitKind, ) -> Result<(), Error> { self.last_runtime = current_time().checked_sub(self.start_time); + Ok(()) } } diff --git a/libafl_bolts/build.rs b/libafl_bolts/build.rs index 0ed1270dc4..5253398d1a 100644 --- a/libafl_bolts/build.rs +++ b/libafl_bolts/build.rs @@ -1,14 +1,15 @@ #[rustversion::nightly] -fn main() { - println!("cargo:rerun-if-changed=build.rs"); +fn nightly() { println!("cargo:rustc-cfg=nightly"); - #[cfg(target_env = "musl")] - println!("cargo:rustc-link-lib=ucontext"); } #[rustversion::not(nightly)] +fn nightly() {} + fn main() { println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rustc-check-cfg=cfg(nightly)"); + nightly(); #[cfg(target_env = "musl")] println!("cargo:rustc-link-lib=ucontext"); } diff --git a/libafl_bolts/src/compress.rs b/libafl_bolts/src/compress.rs index 30a50b5a08..74a9a18327 100644 --- a/libafl_bolts/src/compress.rs +++ b/libafl_bolts/src/compress.rs @@ -22,27 +22,45 @@ impl GzipCompressor { /// If the buffer is at least larger as large as the `threshold` value, we compress the buffer. /// When given a `threshold` of `0`, the `GzipCompressor` will always compress. #[must_use] - pub fn new(threshold: usize) -> Self { + pub fn with_threshold(threshold: usize) -> Self { Self { threshold } } + + /// Create a [`GzipCompressor`] that will always compress + #[must_use] + pub fn new() -> Self { + Self { threshold: 0 } + } +} + +impl Default for GzipCompressor { + fn default() -> Self { + Self::new() + } } impl GzipCompressor { /// Compression. /// If the buffer is smaller than the threshold of this compressor, `None` will be returned. /// Else, the buffer is compressed. - pub fn compress(&self, buf: &[u8]) -> Result>, Error> { + #[must_use] + pub fn maybe_compress(&self, buf: &[u8]) -> Option> { if buf.len() >= self.threshold { //compress if the buffer is large enough - let compressed = compress_to_vec(buf, CompressionLevel::BestSpeed as u8); - Ok(Some(compressed)) + Some(self.compress(buf)) } else { - Ok(None) + None } } + /// Force compression. + /// Will ignore the preset threshold, and always compress. + #[must_use] + pub fn compress(&self, buf: &[u8]) -> Vec { + compress_to_vec(buf, CompressionLevel::BestSpeed as u8) + } + /// Decompression. - /// Flag is used to indicate if it's compressed or not #[allow(clippy::unused_self)] pub fn decompress(&self, buf: &[u8]) -> Result, Error> { let decompressed = decompress_to_vec(buf); @@ -60,10 +78,10 @@ mod tests { #[test] fn test_compression() { - let compressor = GzipCompressor::new(1); + let compressor = GzipCompressor::with_threshold(1); assert!( compressor - .decompress(&compressor.compress(&[1u8; 1024]).unwrap().unwrap()) + .decompress(&compressor.maybe_compress(&[1u8; 1024]).unwrap()) .unwrap() == vec![1u8; 1024] ); @@ -71,8 +89,8 @@ mod tests { #[test] fn test_threshold() { - let compressor = GzipCompressor::new(1024); - assert!(compressor.compress(&[1u8; 1023]).unwrap().is_none()); - assert!(compressor.compress(&[1u8; 1024]).unwrap().is_some()); + let compressor = GzipCompressor::with_threshold(1024); + assert!(compressor.maybe_compress(&[1u8; 1023]).is_none()); + assert!(compressor.maybe_compress(&[1u8; 1024]).is_some()); } } diff --git a/libafl_bolts/src/cpu.rs b/libafl_bolts/src/cpu.rs index 318011c549..0235c05d4f 100644 --- a/libafl_bolts/src/cpu.rs +++ b/libafl_bolts/src/cpu.rs @@ -9,7 +9,7 @@ use core::arch::asm; target_arch = "aarch64", target_arch = "arm", target_arch = "riscv64", - target_arsch = "riscv32" + target_arch = "riscv32" )))] use crate::current_nanos; diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 6d8b7220c6..98ae33be5d 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -4,6 +4,7 @@ #![doc = include_str!("../README.md")] /*! */ #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![forbid(unexpected_cfgs)] #![allow(incomplete_features)] #![no_std] // For `type_eq` diff --git a/libafl_bolts/src/llmp.rs b/libafl_bolts/src/llmp.rs index 1ff9ecc5ee..8ebef1dd03 100644 --- a/libafl_bolts/src/llmp.rs +++ b/libafl_bolts/src/llmp.rs @@ -2543,7 +2543,7 @@ where // Crete a new ShMemProvider for this background thread let shmem_provider_bg = SP::new().unwrap(); - #[cfg(fature = "llmp_debug")] + #[cfg(feature = "llmp_debug")] log::info!("B2b: Spawned proxy thread"); // The background thread blocks on the incoming connection for 15 seconds (if no data is available), then checks if it should forward own messages, then blocks some more. diff --git a/libafl_bolts/src/minibsod.rs b/libafl_bolts/src/minibsod.rs index 63596a8fed..792f2766f8 100644 --- a/libafl_bolts/src/minibsod.rs +++ b/libafl_bolts/src/minibsod.rs @@ -130,7 +130,7 @@ pub fn dump_registers( } /// Write the content of all important registers -#[cfg(all(target_vendor = "freebsd", target_arch = "aarch64"))] +#[cfg(all(target_os = "freebsd", target_arch = "aarch64"))] #[allow(clippy::similar_names)] pub fn dump_registers( writer: &mut BufWriter, @@ -776,7 +776,7 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er libc::VM_PROC, libc::VM_PROC_MAP, -1, - std::mem::size_of::() + size_of::() .try_into() .expect("Invalid libc::kinfo_vmentry size"), ]; @@ -809,7 +809,7 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er .try_into() .expect("invalid kve_structsize value"); #[cfg(target_os = "netbsd")] - let sz = std::mem::size_of::(); + let sz = size_of::(); if sz == 0 { break; } @@ -838,7 +838,7 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er #[cfg(target_os = "openbsd")] fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Error> { let mut pentry = std::mem::MaybeUninit::::uninit(); - let mut s = std::mem::size_of::(); + let mut s = size_of::(); let arr = &[libc::CTL_KERN, libc::KERN_PROC_VMMAP, unsafe { libc::getpid() }]; @@ -887,6 +887,8 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er #[cfg(target_vendor = "apple")] #[allow(non_camel_case_types)] fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Error> { + use core::mem::size_of; + type vm_region_recurse_info_t = *mut libc::c_int; type mach_vm_address_t = u64; type mach_vm_size_t = u64; @@ -944,8 +946,10 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er loop { let mut pvminfo = std::mem::MaybeUninit::::uninit(); - _cnt = (std::mem::size_of::() / std::mem::size_of::()) - as mach_msg_type_number_t; + _cnt = mach_msg_type_number_t::try_from( + size_of::() / size_of::(), + ) + .unwrap(); r = unsafe { mach_vm_region_recurse( task, @@ -964,9 +968,9 @@ fn write_minibsod(writer: &mut BufWriter) -> Result<(), std::io::Er // We are only interested by the first level of the maps if vminfo.is_submap == 0 { let i = format!("{}-{}\n", addr, addr + sz); - writer.write(&i.into_bytes())?; + writer.write_all(&i.into_bytes())?; } - addr = addr + sz; + addr += sz; } Ok(()) diff --git a/libafl_cc/src/lib.rs b/libafl_cc/src/lib.rs index b0c013dc83..7a13081a74 100644 --- a/libafl_cc/src/lib.rs +++ b/libafl_cc/src/lib.rs @@ -3,6 +3,7 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(clippy::all)] #![deny(clippy::pedantic)] +#![forbid(unexpected_cfgs)] #![allow( clippy::unreadable_literal, clippy::type_repetition_in_bounds, diff --git a/libafl_concolic/symcc_libafl/src/lib.rs b/libafl_concolic/symcc_libafl/src/lib.rs index 1583f8af82..dfe3df9569 100644 --- a/libafl_concolic/symcc_libafl/src/lib.rs +++ b/libafl_concolic/symcc_libafl/src/lib.rs @@ -1,6 +1,7 @@ //! This is a 'meta-package' for libafl that exposes a consistent URL and commit hash for the //! [`SymCC` fork](https://github.com/AFLplusplus/symcc). #![allow(clippy::module_name_repetitions)] +#![forbid(unexpected_cfgs)] /// The URL of the `LibAFL` `SymCC` fork. pub const SYMCC_REPO_URL: &str = "https://github.com/AFLplusplus/symcc.git"; diff --git a/libafl_concolic/symcc_runtime/src/lib.rs b/libafl_concolic/symcc_runtime/src/lib.rs index 1d59a9fd26..f5baf640da 100644 --- a/libafl_concolic/symcc_runtime/src/lib.rs +++ b/libafl_concolic/symcc_runtime/src/lib.rs @@ -32,6 +32,7 @@ clippy::missing_panics_doc, clippy::pub_underscore_fields )] +#![forbid(unexpected_cfgs)] pub mod filter; pub mod tracing; diff --git a/libafl_concolic/test/dump_constraints/src/main.rs b/libafl_concolic/test/dump_constraints/src/main.rs index 34d12b6322..51b02ae988 100644 --- a/libafl_concolic/test/dump_constraints/src/main.rs +++ b/libafl_concolic/test/dump_constraints/src/main.rs @@ -1,6 +1,7 @@ //! This is a straight-forward command line utility that can dump constraints written by a tracing runtime. //! It achieves this by running an instrumented target program with the necessary environment variables set. //! When the program has finished executing, it dumps the traced constraints to a file. +#![forbid(unexpected_cfgs)] use std::{ ffi::OsString, diff --git a/libafl_concolic/test/runtime_test/src/lib.rs b/libafl_concolic/test/runtime_test/src/lib.rs index 976fbf29d5..56c1ce003c 100644 --- a/libafl_concolic/test/runtime_test/src/lib.rs +++ b/libafl_concolic/test/runtime_test/src/lib.rs @@ -1,5 +1,6 @@ // this is required to be allowed to call the final executable what we want (and need) in Cargo.toml #![allow(non_snake_case)] +#![forbid(unexpected_cfgs)] //! Just a small runtime to be used in the smoke test. use symcc_runtime::{ diff --git a/libafl_derive/src/lib.rs b/libafl_derive/src/lib.rs index d10489dde8..a6f1522085 100644 --- a/libafl_derive/src/lib.rs +++ b/libafl_derive/src/lib.rs @@ -1,6 +1,7 @@ //! Derives for `LibAFL` #![no_std] +#![forbid(unexpected_cfgs)] #![deny(rustdoc::broken_intra_doc_links)] #![deny(clippy::all)] #![deny(clippy::pedantic)] diff --git a/libafl_frida/build.rs b/libafl_frida/build.rs index 3080616299..5d23b239fb 100644 --- a/libafl_frida/build.rs +++ b/libafl_frida/build.rs @@ -1,4 +1,5 @@ // build.rs +#![forbid(unexpected_cfgs)] fn main() { let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 54b50e0b83..f284e4853c 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -5,6 +5,7 @@ It can report coverage and, on supported architectures, even reports memory acce Additional documentation is available in [the `LibAFL` book](https://aflplus.plus/libafl-book/advanced_features/frida.html). */ +#![forbid(unexpected_cfgs)] #![deny(rustdoc::broken_intra_doc_links)] #![deny(clippy::all)] #![deny(clippy::pedantic)] diff --git a/libafl_libfuzzer/Cargo.toml b/libafl_libfuzzer/Cargo.toml index c358480692..762c9d04db 100644 --- a/libafl_libfuzzer/Cargo.toml +++ b/libafl_libfuzzer/Cargo.toml @@ -10,11 +10,11 @@ edition = "2021" categories = ["development-tools::testing", "fuzzing"] include = [ - "/src", - "/Cargo.toml", - "/build.rs", - "/libafl_libfuzzer_runtime", - "!/libafl_libfuzzer_runtime/target", + "/src", + "/Cargo.toml", + "/build.rs", + "/libafl_libfuzzer_runtime", + "!/libafl_libfuzzer_runtime/target", ] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,12 +24,20 @@ cc = "1.0" rustversion = "1.0" [features] +default = ["fork"] +document-features = ["dep:document-features"] + #! ## Feature Flags ## Enables the derive macros for the arbitrary dependency, transparently forwarded from libfuzzer-sys arbitrary-derive = ["libfuzzer-sys/arbitrary-derive"] + ## Enables fuzzer introspection with LibAFL's `introspection` feature introspection = [] + +## Enables forking in the fuzzer runtime for restarting managers for Unix systems (on by default) +fork = [] + ## Embeds the built libafl_libfuzzer_runtime library into the crate with include_bytes! for use ## in downstream cases like libafl_cc linking the runtime with: ## `-fsanitize=fuzzer-no-link -l:libafl_libfuzzer_runtime.a` @@ -40,7 +48,7 @@ rabbit = [] [dependencies] libfuzzer-sys = { version = "0.4.7", default-features = false } -document-features = { version = "0.2" } +document-features = { version = "0.2", optional = true } [package.metadata.docs.rs] features = ["document-features"] diff --git a/libafl_libfuzzer/build.rs b/libafl_libfuzzer/build.rs index de4e7bbdc1..20c9bdc96b 100644 --- a/libafl_libfuzzer/build.rs +++ b/libafl_libfuzzer/build.rs @@ -13,7 +13,7 @@ const NAMESPACE_LEN: usize = NAMESPACE.as_bytes().len(); #[allow(clippy::too_many_lines)] fn main() { - if cfg!(any(feature = "cargo-clippy", docsrs)) { + if cfg!(any(clippy, docsrs)) { return; // skip when clippy or docs is running } diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs index 9e465bab4c..99ce60019e 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs @@ -1,74 +1,7 @@ //! The `LibAFL` `LibFuzzer` runtime, exposing the same functions as the original [`LibFuzzer`](https://llvm.org/docs/LibFuzzer.html). -#![allow(incomplete_features)] -// For `type_eq` -#![cfg_attr(unstable_feature, feature(specialization))] -// For `type_id` and owned things -#![cfg_attr(unstable_feature, feature(intrinsics))] -// For `std::simd` -#![cfg_attr(unstable_feature, feature(portable_simd))] -#![warn(clippy::cargo)] -#![allow(ambiguous_glob_reexports)] -#![deny(clippy::cargo_common_metadata)] -#![deny(rustdoc::broken_intra_doc_links)] -#![deny(clippy::all)] -#![deny(clippy::pedantic)] -#![allow( - clippy::unreadable_literal, - clippy::type_repetition_in_bounds, - clippy::missing_errors_doc, - clippy::cast_possible_truncation, - clippy::used_underscore_binding, - clippy::ptr_as_ptr, - clippy::missing_panics_doc, - clippy::missing_docs_in_private_items, - clippy::module_name_repetitions, - clippy::ptr_cast_constness, - clippy::unsafe_derive_deserialize -)] -#![cfg_attr(not(test), warn( - missing_debug_implementations, - missing_docs, - //trivial_casts, - trivial_numeric_casts, - unused_extern_crates, - unused_import_braces, - unused_qualifications, - //unused_results -))] -#![cfg_attr(test, deny( - missing_debug_implementations, - missing_docs, - //trivial_casts, - trivial_numeric_casts, - unused_extern_crates, - unused_import_braces, - unused_qualifications, - unused_must_use, - //unused_results -))] -#![cfg_attr( - test, - deny( - bad_style, - dead_code, - improper_ctypes, - non_shorthand_field_patterns, - no_mangle_generic_items, - overflowing_literals, - path_statements, - patterns_in_fns_without_body, - unconditional_recursion, - unused, - unused_allocation, - unused_comparisons, - unused_parens, - while_true - ) -)] -// Till they fix this buggy lint in clippy -#![allow(clippy::borrow_as_ptr)] -#![allow(clippy::borrow_deref_ref)] +#![forbid(unexpected_cfgs)] +#![allow(clippy::unsafe_derive_deserialize)] use core::ffi::{c_char, c_int, CStr}; use std::{fs::File, io::stderr, os::fd::RawFd}; @@ -110,11 +43,6 @@ mod harness_wrap { } pub(crate) use harness_wrap::libafl_libfuzzer_test_one_input; -#[cfg(feature = "mimalloc")] -use mimalloc::MiMalloc; -#[global_allocator] -#[cfg(feature = "mimalloc")] -static GLOBAL: MiMalloc = MiMalloc; #[allow(clippy::struct_excessive_bools)] struct CustomMutationStatus { diff --git a/libafl_libfuzzer/src/lib.rs b/libafl_libfuzzer/src/lib.rs index b995ece126..f7f483db18 100644 --- a/libafl_libfuzzer/src/lib.rs +++ b/libafl_libfuzzer/src/lib.rs @@ -75,6 +75,7 @@ //! to the runtime (e.g., to prevent coverage being collected on the runtime). //! #![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![forbid(unexpected_cfgs)] use std::ffi::{c_char, c_int}; diff --git a/libafl_nyx/src/lib.rs b/libafl_nyx/src/lib.rs index 069d556f60..33c3cdce38 100644 --- a/libafl_nyx/src/lib.rs +++ b/libafl_nyx/src/lib.rs @@ -1,4 +1,6 @@ #![allow(clippy::module_name_repetitions, clippy::missing_panics_doc)] +#![forbid(unexpected_cfgs)] + #[cfg(target_os = "linux")] pub mod executor; #[cfg(target_os = "linux")] diff --git a/libafl_qemu/build.rs b/libafl_qemu/build.rs index 904fabb106..5346298ba4 100644 --- a/libafl_qemu/build.rs +++ b/libafl_qemu/build.rs @@ -9,14 +9,15 @@ mod host_specific { } #[rustversion::nightly] -fn main() { +fn nightly() { println!("cargo:rustc-cfg=nightly"); - println!("cargo::rustc-check-cfg=cfg(nightly)"); - host_specific::build(); } #[rustversion::not(nightly)] +fn nightly() {} + fn main() { - println!("cargo::rustc-check-cfg=cfg(nightly)"); + println!("cargo:rustc-check-cfg=cfg(nightly)"); + nightly(); host_specific::build(); } diff --git a/libafl_qemu/build_linux.rs b/libafl_qemu/build_linux.rs index 69d3359011..bca4fd97c0 100644 --- a/libafl_qemu/build_linux.rs +++ b/libafl_qemu/build_linux.rs @@ -1,17 +1,23 @@ -use std::{env, fs, path::{Path, PathBuf}, process::Command}; +use std::{ + env, fs, + path::{Path, PathBuf}, + process::Command, +}; #[allow(clippy::too_many_lines)] pub fn build() { // Note: Unique features are checked in libafl_qemu_sys + println!(r#"cargo::rustc-check-cfg=cfg(emulation_mode, values("usermode", "systemmode"))"#); + println!( + r#"cargo::rustc-check-cfg=cfg(cpu_target, values("arm", "aarch64", "hexagon", "i386", "mips", "ppc", "x86_64"))"# + ); let emulation_mode = if cfg!(feature = "usermode") { "usermode".to_string() } else if cfg!(feature = "systemmode") { "systemmode".to_string() } else { - env::var("EMULATION_MODE").unwrap_or_else(|_| { - "usermode".to_string() - }) + env::var("EMULATION_MODE").unwrap_or_else(|_| "usermode".to_string()) }; let src_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); @@ -60,9 +66,7 @@ pub fn build() { } else if cfg!(feature = "hexagon") { "hexagon".to_string() } else { - env::var("CPU_TARGET").unwrap_or_else(|_| { - "x86_64".to_string() - }) + env::var("CPU_TARGET").unwrap_or_else(|_| "x86_64".to_string()) }; println!("cargo:rerun-if-env-changed=CPU_TARGET"); println!("cargo:rustc-cfg=cpu_target=\"{cpu_target}\""); @@ -82,13 +86,18 @@ pub fn build() { }; if env::var("DOCS_RS").is_ok() || cfg!(feature = "clippy") { - fs::copy(&stub_runtime_bindings_file, &runtime_bindings_file).expect("Could not copy stub bindings file"); + fs::copy(&stub_runtime_bindings_file, &runtime_bindings_file) + .expect("Could not copy stub bindings file"); return; // only build when we're not generating docs } fs::create_dir_all(&include_dir).expect("Could not create include dir"); - fs::copy(libafl_qemu_hdr.clone(), include_dir.join(libafl_qemu_hdr_name)).expect("Could not copy libafl_qemu.h to out directory."); + fs::copy( + libafl_qemu_hdr.clone(), + include_dir.join(libafl_qemu_hdr_name), + ) + .expect("Could not copy libafl_qemu.h to out directory."); bindgen::Builder::default() .derive_debug(true) @@ -105,7 +114,12 @@ pub fn build() { .write_to_file(&runtime_bindings_file) .expect("Could not write bindings."); - libafl_qemu_build::store_generated_content_if_different(&stub_runtime_bindings_file, fs::read(&runtime_bindings_file).expect("Could not read generated bindings file").as_slice()); + libafl_qemu_build::store_generated_content_if_different( + &stub_runtime_bindings_file, + fs::read(&runtime_bindings_file) + .expect("Could not read generated bindings file") + .as_slice(), + ); if (emulation_mode == "usermode") && (qemu_asan || qemu_asan_guest) { let qasan_dir = Path::new("libqasan"); diff --git a/libafl_qemu/libafl_qemu_build/src/lib.rs b/libafl_qemu/libafl_qemu_build/src/lib.rs index 0bb58d9443..bb013f1d23 100644 --- a/libafl_qemu/libafl_qemu_build/src/lib.rs +++ b/libafl_qemu/libafl_qemu_build/src/lib.rs @@ -1,4 +1,6 @@ +#![forbid(unexpected_cfgs)] #![allow(clippy::missing_panics_doc)] + use std::{ collections::hash_map, env, fs, diff --git a/libafl_qemu/libafl_qemu_build/src/main.rs b/libafl_qemu/libafl_qemu_build/src/main.rs index c3edd79883..f37cd52a25 100644 --- a/libafl_qemu/libafl_qemu_build/src/main.rs +++ b/libafl_qemu/libafl_qemu_build/src/main.rs @@ -1,3 +1,5 @@ +#![forbid(unexpected_cfgs)] + use std::path::PathBuf; use libafl_qemu_build::build_with_bindings; diff --git a/libafl_qemu/libafl_qemu_sys/build.rs b/libafl_qemu/libafl_qemu_sys/build.rs index 7fa109f2e4..b6cd28a0b2 100644 --- a/libafl_qemu/libafl_qemu_sys/build.rs +++ b/libafl_qemu/libafl_qemu_sys/build.rs @@ -1,3 +1,5 @@ +#![forbid(unexpected_cfgs)] + mod host_specific { #[cfg(target_os = "linux")] include!("build_linux.rs"); @@ -9,14 +11,15 @@ mod host_specific { } #[rustversion::nightly] -fn main() { +fn nightly() { println!("cargo:rustc-cfg=nightly"); - println!("cargo::rustc-check-cfg=cfg(nightly)"); - host_specific::build(); } #[rustversion::not(nightly)] +fn nightly() {} + fn main() { - println!("cargo::rustc-check-cfg=cfg(nightly)"); + println!("cargo:rustc-check-cfg=cfg(nightly)"); + nightly(); host_specific::build(); } diff --git a/libafl_qemu/libafl_qemu_sys/build_linux.rs b/libafl_qemu/libafl_qemu_sys/build_linux.rs index 9a6218ce68..0a312462e9 100644 --- a/libafl_qemu/libafl_qemu_sys/build_linux.rs +++ b/libafl_qemu/libafl_qemu_sys/build_linux.rs @@ -1,9 +1,8 @@ +#[rustversion::nightly] +use std::fs; use std::{env, fs::copy, path::PathBuf}; use libafl_qemu_build::build_with_bindings; - -#[rustversion::nightly] -use std::fs; #[rustversion::nightly] use libafl_qemu_build::store_generated_content_if_different; @@ -20,18 +19,37 @@ macro_rules! assert_unique_feature { } #[rustversion::nightly] -fn maybe_generate_stub_bindings(cpu_target: &str, emulation_mode: &str, stub_bindings_file: &PathBuf, bindings_file: &PathBuf) { +fn maybe_generate_stub_bindings( + cpu_target: &str, + emulation_mode: &str, + stub_bindings_file: &PathBuf, + bindings_file: &PathBuf, +) { if cpu_target == "x86_64" && emulation_mode == "usermode" { - store_generated_content_if_different(stub_bindings_file, fs::read(bindings_file).expect("Could not read generated bindings file").as_slice()); + store_generated_content_if_different( + stub_bindings_file, + fs::read(bindings_file) + .expect("Could not read generated bindings file") + .as_slice(), + ); } } #[rustversion::not(nightly)] -fn maybe_generate_stub_bindings(_cpu_target: &str, _emulation_mode: &str, _stub_bindings_file: &PathBuf, _bindings_file: &PathBuf) { +fn maybe_generate_stub_bindings( + _cpu_target: &str, + _emulation_mode: &str, + _stub_bindings_file: &PathBuf, + _bindings_file: &PathBuf, +) { // Do nothing } pub fn build() { + println!(r#"cargo::rustc-check-cfg=cfg(emulation_mode, values("usermode", "systemmode"))"#); + println!( + r#"cargo::rustc-check-cfg=cfg(cpu_target, values("arm", "aarch64", "hexagon", "i386", "mips", "ppc", "x86_64"))"# + ); // Make sure that exactly one qemu mode is set assert_unique_feature!("usermode", "systemmode"); let emulation_mode = if cfg!(feature = "usermode") { @@ -76,7 +94,7 @@ pub fn build() { } else { env::var("CPU_TARGET").unwrap_or_else(|_| { println!( - "cargo:warning=No architecture feature enabled or CPU_TARGET env specified for libafl_qemu, supported: arm, aarch64, i386, x86_64 - defaulting to x86_64" + "cargo:warning=No architecture feature enabled or CPU_TARGET env specified for libafl_qemu, supported: arm, aarch64, hexagon, i386, mips, ppc, x86_64 - defaulting to x86_64" ); "x86_64".to_string() }) @@ -92,7 +110,7 @@ pub fn build() { let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = PathBuf::from(out_dir); let bindings_file = out_dir.join("bindings.rs"); - + let src_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let src_dir = PathBuf::from(src_dir); let stub_bindings_file = src_dir.join("src/x86_64_stub_bindings.rs"); @@ -114,5 +132,10 @@ pub fn build() { println!("cargo:rerun-if-changed={}", stub_bindings_file.display()); // If the bindings are built and differ from the current stub, replace it with the freshly generated bindings - maybe_generate_stub_bindings(&cpu_target, &emulation_mode, &stub_bindings_file, &bindings_file); -} \ No newline at end of file + maybe_generate_stub_bindings( + &cpu_target, + &emulation_mode, + &stub_bindings_file, + &bindings_file, + ); +} diff --git a/libafl_qemu/libafl_qemu_sys/src/lib.rs b/libafl_qemu/libafl_qemu_sys/src/lib.rs index ebe2891be9..ab2bcb917a 100644 --- a/libafl_qemu/libafl_qemu_sys/src/lib.rs +++ b/libafl_qemu/libafl_qemu_sys/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(nightly, feature(used_with_arg))] /*! `libafl_qemu_sys` is the crate exporting C symbols from QEMU. Have a look at `libafl_qemu` for higher-level abstractions. @@ -6,6 +5,7 @@ Have a look at `libafl_qemu` for higher-level abstractions. __Warning__: The documentation is built by default for `x86_64` in `usermode`. To access the documentation of other architectures or systemmode, the documentation must be rebuilt with the right features. */ +#![forbid(unexpected_cfgs)] #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] @@ -13,6 +13,11 @@ __Warning__: The documentation is built by default for `x86_64` in `usermode`. T #![allow(unused_mut)] #![allow(clippy::all)] #![allow(clippy::pedantic)] +#![cfg_attr(nightly, feature(used_with_arg))] + +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use paste::paste; +use strum_macros::EnumIter; #[cfg(all(not(feature = "clippy"), target_os = "linux"))] mod bindings { @@ -32,9 +37,6 @@ pub use usermode::*; #[cfg(emulation_mode = "systemmode")] mod systemmode; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use paste::paste; -use strum_macros::EnumIter; #[cfg(emulation_mode = "systemmode")] pub use systemmode::*; diff --git a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs index 22f43e20da..8e1cd142f4 100644 --- a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs +++ b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs @@ -2340,6 +2340,7 @@ pub type DeviceReset = ::std::option::Option