Add serdeany_autoreg feature flag to allow disabling ctor use (#1398)

* Add  feature flag to allow disabling  use

* fix typo

* undo cargo.toml change

* Fix no_std

* Backticks

* rename register_at_startup to create_register

* fix

* Move Tui_monitor to default instead of std
This commit is contained in:
Dominik Maier 2023-08-04 15:36:48 +02:00 committed by GitHub
parent 83f739f010
commit a0c03fccc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 23 deletions

View File

@ -12,8 +12,8 @@ edition = "2021"
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"] categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
[features] [features]
default = ["std", "derive", "llmp_compression", "llmp_small_maps", "llmp_broker_timeouts", "rand_trait", "fork", "prelude", "gzip", "regex"] default = ["std", "derive", "llmp_compression", "llmp_small_maps", "llmp_broker_timeouts", "rand_trait", "fork", "prelude", "gzip", "regex", "serdeany_autoreg", "tui_monitor"]
std = ["serde_json", "serde_json/std", "nix", "serde/std", "bincode", "wait-timeout", "uuid", "tui_monitor", "ctor", "backtrace", "serial_test", "libafl_bolts/std", "typed-builder"] # print, env, launcher ... support std = ["serde_json", "serde_json/std", "nix", "serde/std", "bincode", "wait-timeout", "uuid", "backtrace", "serial_test", "libafl_bolts/std", "typed-builder"] # print, env, launcher ... support
derive = ["libafl_derive", "libafl_bolts/derive"] # provide derive(SerdeAny) macro. derive = ["libafl_derive", "libafl_bolts/derive"] # provide derive(SerdeAny) macro.
fork = ["libafl_bolts/derive"] # uses the fork() syscall to spawn children, instead of launching a new command, if supported by the OS (has no effect on Windows, no_std). fork = ["libafl_bolts/derive"] # uses the fork() syscall to spawn children, instead of launching a new command, if supported by the OS (has no effect on Windows, no_std).
rand_trait = ["libafl_bolts/rand_trait"] # If set, libafl's rand implementations will implement `rand::Rng` rand_trait = ["libafl_bolts/rand_trait"] # If set, libafl's rand implementations will implement `rand::Rng`
@ -42,6 +42,9 @@ gpl = []
agpl = ["gpl", "nautilus"] agpl = ["gpl", "nautilus"]
nautilus = ["grammartec", "std", "serde_json/std"] nautilus = ["grammartec", "std", "serde_json/std"]
# SerdeAny features
serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"] # Automatically register all `#[derive(SerdeAny)]` types at startup.
# LLMP features # LLMP features
llmp_bind_public = ["libafl_bolts/llmp_bind_public"] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default. llmp_bind_public = ["libafl_bolts/llmp_bind_public"] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default.
llmp_compression = ["libafl_bolts/llmp_compression"] # llmp compression using GZip llmp_compression = ["libafl_bolts/llmp_compression"] # llmp compression using GZip
@ -74,7 +77,6 @@ intervaltree = { version = "0.2.7", default-features = false, features = ["serde
backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver
typed-builder = { version = "0.15.1", optional = true } # Implement the builder pattern at compiletime typed-builder = { version = "0.15.1", optional = true } # Implement the builder pattern at compiletime
ctor = { optional = true, version = "0.2" }
serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] }
nix = { version = "0.26", optional = true } nix = { version = "0.26", optional = true }
regex = { version = "1", optional = true } regex = { version = "1", optional = true }

View File

@ -169,6 +169,8 @@ where
if self.cores.ids.iter().any(|&x| x == id.into()) { if self.cores.ids.iter().any(|&x| x == id.into()) {
index += 1; index += 1;
self.shmem_provider.pre_fork()?; self.shmem_provider.pre_fork()?;
// # Safety
// Fork is safe in general, apart from potential side effects to the OS and other threads
match unsafe { fork() }? { match unsafe { fork() }? {
ForkResult::Parent(child) => { ForkResult::Parent(child) => {
self.shmem_provider.post_fork(false)?; self.shmem_provider.post_fork(false)?;
@ -177,6 +179,8 @@ where
log::info!("child spawned and bound to core {id}"); log::info!("child spawned and bound to core {id}");
} }
ForkResult::Child => { ForkResult::Child => {
// # Safety
// A call to `getpid` is safe.
log::info!("{:?} PostFork", unsafe { libc::getpid() }); log::info!("{:?} PostFork", unsafe { libc::getpid() });
self.shmem_provider.post_fork(true)?; self.shmem_provider.post_fork(true)?;
@ -232,6 +236,8 @@ where
// Broker exited. kill all clients. // Broker exited. kill all clients.
for handle in &handles { for handle in &handles {
// # Safety
// Normal libc call, no dereferences whatsoever
unsafe { unsafe {
libc::kill(*handle, libc::SIGINT); libc::kill(*handle, libc::SIGINT);
} }

View File

@ -79,9 +79,6 @@ extern crate std;
#[macro_use] #[macro_use]
#[doc(hidden)] #[doc(hidden)]
pub extern crate alloc; pub extern crate alloc;
#[cfg(feature = "ctor")]
#[doc(hidden)]
pub use ctor::ctor;
// Re-export derive(SerdeAny) // Re-export derive(SerdeAny)
#[cfg(feature = "derive")] #[cfg(feature = "derive")]

View File

@ -12,8 +12,8 @@ edition = "2021"
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"] categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
[features] [features]
default = ["std", "derive", "llmp_compression", "llmp_small_maps", "rand_trait", "prelude", "gzip"] default = ["std", "derive", "llmp_compression", "llmp_small_maps", "rand_trait", "prelude", "gzip", "serdeany_autoreg"]
std = ["serde_json", "serde_json/std", "hostname", "nix", "serde/std", "once_cell", "uuid", "ctor", "byteorder", "backtrace", "uds", "serial_test"] # print, env, launcher ... support std = ["serde_json", "serde_json/std", "hostname", "nix", "serde/std", "once_cell", "uuid", "byteorder", "backtrace", "uds", "serial_test"] # print, env, launcher ... support
derive = ["libafl_derive"] # provide derive(SerdeAny) macro. derive = ["libafl_derive"] # provide derive(SerdeAny) macro.
rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng` rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng`
python = ["pyo3"] python = ["pyo3"]
@ -24,6 +24,9 @@ frida_cli = ["cli"] # Commandline flags for frida-based fuzzers
errors_backtrace = ["backtrace"] errors_backtrace = ["backtrace"]
gzip = ["miniz_oxide"] # Enables gzip compression in certain parts of the lib gzip = ["miniz_oxide"] # Enables gzip compression in certain parts of the lib
# SerdeAny features
serdeany_autoreg = ["ctor"] # Automatically register all `#[derive(SerdeAny)]` types at startup.
# LLMP features # LLMP features
llmp_bind_public = [] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default. llmp_bind_public = [] # If set, llmp will bind to 0.0.0.0, allowing cross-device communication. Binds to localhost by default.
llmp_compression = ["gzip"] # llmp compression using GZip llmp_compression = ["gzip"] # llmp compression using GZip

View File

@ -143,7 +143,7 @@ macro_rules! create_serde_registry_for_trait {
finalized: false, finalized: false,
}; };
/// This shugar must be used to register all the structs which /// This sugar must be used to register all the structs which
/// have trait objects that can be serialized and deserialized in the program /// have trait objects that can be serialized and deserialized in the program
#[derive(Debug)] #[derive(Debug)]
pub struct RegistryBuilder {} pub struct RegistryBuilder {}
@ -151,7 +151,11 @@ macro_rules! create_serde_registry_for_trait {
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
impl RegistryBuilder { impl RegistryBuilder {
/// Register a given struct type for trait object (de)serialization /// Register a given struct type for trait object (de)serialization
pub fn register<T>() ///
/// # Safety
/// This may never be called concurrently or at the same time as `finalize`.
/// It dereferences the `REGISTRY` hashmap and adds the given type to it.
pub unsafe fn register<T>()
where where
T: $trait_name + Serialize + serde::de::DeserializeOwned, T: $trait_name + Serialize + serde::de::DeserializeOwned,
{ {
@ -161,6 +165,10 @@ macro_rules! create_serde_registry_for_trait {
} }
/// Finalize the registry, no more registrations are allowed after this call /// Finalize the registry, no more registrations are allowed after this call
///
/// # Safety
/// This may never be called concurrently or at the same time as `register`.
/// It dereferences the `REGISTRY` hashmap and adds the given type to it.
pub fn finalize() { pub fn finalize() {
unsafe { unsafe {
REGISTRY.finalize(); REGISTRY.finalize();
@ -603,24 +611,34 @@ create_serde_registry_for_trait!(serdeany_registry, crate::serdeany::SerdeAny);
pub use serdeany_registry::*; pub use serdeany_registry::*;
/// Register a `SerdeAny` type in the [`RegistryBuilder`] /// Register a `SerdeAny` type in the [`RegistryBuilder`]
#[cfg(feature = "std")] ///
/// Do nothing for without the `serdeany_autoreg` feature, you'll have to register it manually
/// in `main()` with [`RegistryBuilder::register`] or using `<T>::register()`.
#[macro_export] #[macro_export]
macro_rules! register_at_startup { macro_rules! create_register {
($struct_type:ty) => { ($struct_type:ty) => {
const _: () = { const _: () = {
#[$crate::ctor] /// Manually register this type at a later point in time
fn constructor() { ///
/// # Safety
/// This may never be called concurrently as it dereferences the `RegistryBuilder` without acquiring a lock.
#[cfg(not(feature = "serdeany_autoreg"))]
pub unsafe fn register() {
$crate::serdeany::RegistryBuilder::register::<$struct_type>(); $crate::serdeany::RegistryBuilder::register::<$struct_type>();
} }
};
};
}
/// Do nothing for `no_std`, you have to register it manually in `main()` with [`RegistryBuilder::register`] /// Automatically register this type
#[cfg(not(feature = "std"))] #[cfg(feature = "serdeany_autoreg")]
#[macro_export] #[$crate::ctor]
macro_rules! register_at_startup { fn register() {
($struct_type:ty) => {}; // # Safety
// This `register` call will always run at startup and never in parallel.
unsafe {
$crate::serdeany::RegistryBuilder::register::<$struct_type>();
}
}
};
};
} }
/// Implement a [`SerdeAny`], registering it in the [`RegistryBuilder`] when on std /// Implement a [`SerdeAny`], registering it in the [`RegistryBuilder`] when on std
@ -648,7 +666,7 @@ macro_rules! impl_serdeany {
} }
$( $(
$crate::register_at_startup!($struct_name < $( $opt ),+ >); $crate::create_register!($struct_name < $( $opt ),+ >);
)* )*
}; };
($struct_name:ident) => ($struct_name:ident) =>
@ -672,6 +690,6 @@ macro_rules! impl_serdeany {
} }
} }
$crate::register_at_startup!($struct_name); $crate::create_register!($struct_name);
}; };
} }