diff --git a/libafl/src/bolts/core_affinity.rs b/libafl/src/bolts/core_affinity.rs index d285387f68..ef9962b01d 100644 --- a/libafl/src/bolts/core_affinity.rs +++ b/libafl/src/bolts/core_affinity.rs @@ -16,7 +16,7 @@ //! let handles = core_ids.into_iter().map(|id| { //! thread::spawn(move || { //! // Pin this thread to a single CPU core. -//! core_affinity::set_for_current(id); +//! id.set_affinity(); //! // Do more work after this. //! }) //! }).collect::>(); @@ -43,16 +43,6 @@ pub fn get_core_ids() -> Result, Error> { get_core_ids_helper() } -/// This function tries to pin the current -/// thread to the specified core. -/// -/// # Arguments -/// -/// * `core_id` - `ID` of the core to pin -pub fn set_for_current(core_id: CoreId) -> Result<(), Error> { - set_for_current_helper(core_id) -} - /// This represents a CPU core. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct CoreId { @@ -62,8 +52,21 @@ pub struct CoreId { impl CoreId { /// Set the affinity of the current process to this [`CoreId`] + /// + /// Note: This will *_not_* fail if the target platform does not support core affinity. + /// (only on error cases for supported platforms) + /// If you really need to fail for unsupported platforms (like `aarch64` on `macOS`), use [`CoreId::set_affinity_forced`] instead. + /// pub fn set_affinity(&self) -> Result<(), Error> { - set_for_current(*self) + match set_for_current_helper(*self) { + Ok(_) | Err(Error::Unsupported(_, _)) => Ok(()), + Err(e) => Err(e), + } + } + + /// Set the affinity of the current process to this [`CoreId`] + pub fn set_affinity_forced(&self) -> Result<(), Error> { + set_for_current_helper(*self) } } @@ -274,8 +277,6 @@ mod linux { #[cfg(test)] mod tests { - use num_cpus; - use super::*; #[test] @@ -283,19 +284,13 @@ mod linux { get_affinity_mask().unwrap(); } - #[test] - fn test_linux_get_core_ids() { - let set = get_core_ids().unwrap(); - assert_eq!(set.len(), num_cpus::get()); - } - #[test] fn test_linux_set_for_current() { let ids = get_core_ids().unwrap(); assert!(!ids.is_empty()); - set_for_current(ids[0]).unwrap(); + ids[0].set_affinity().unwrap(); // Ensure that the system pinned the current thread // to the specified core. @@ -542,28 +537,6 @@ mod windows { Some(n_logical_procs) } - - #[cfg(test)] - mod tests { - use num_cpus; - - use super::*; - - #[test] - fn test_apple_get_core_ids() { - let set = get_core_ids().unwrap(); - assert_eq!(set.len(), num_cpus::get()); - } - - #[test] - fn test_apple_set_for_current() { - let ids = get_core_ids().unwrap(); - - assert!(!ids.is_empty()); - - set_for_current(ids[0]).unwrap(); - } - } } // Apple Section @@ -590,8 +563,8 @@ mod apple { use alloc::vec::Vec; use libc::{ integer_t, kern_return_t, mach_msg_type_number_t, pthread_mach_thread_np, pthread_self, - thread_policy_flavor_t, thread_policy_t, thread_t, THREAD_AFFINITY_POLICY, - THREAD_AFFINITY_POLICY_COUNT, + thread_policy_flavor_t, thread_policy_t, thread_t, KERN_NOT_SUPPORTED, KERN_SUCCESS, + THREAD_AFFINITY_POLICY, THREAD_AFFINITY_POLICY_COUNT, }; use num_cpus; @@ -632,9 +605,18 @@ mod apple { ); // 0 == KERN_SUCCESS - - if result == 0 { + if result == KERN_SUCCESS { Ok(()) + } else if result == KERN_NOT_SUPPORTED { + // 46 == KERN_NOT_SUPPORTED + // Seting a core affinity is not supported on aarch64 apple... + // We won't report this as an error to the user, a there's nothing they could do about it. + // Error codes, see + //|| (cfg!(all(target_vendor = "apple", target_arch = "aarch64")) + // && result == KERN_NOT_SUPPORTED) + Err(Error::unsupported( + "Setting a core affinity is not supported on this platform (KERN_NOT_SUPPORTED)", + )) } else { Err(Error::unknown(format!( "Failed to set_for_current {:?}", @@ -643,28 +625,6 @@ mod apple { } } } - - #[cfg(test)] - mod tests { - use num_cpus; - - use super::*; - - #[test] - fn test_windows_get_core_ids() { - let set = get_core_ids().unwrap(); - assert_eq!(set.len(), num_cpus::get()); - } - - #[test] - fn test_windows_set_for_current() { - let ids = get_core_ids().unwrap(); - - assert!(!ids.is_empty()); - - set_for_current(ids[0]).unwrap(); - } - } } #[cfg(test)] @@ -684,11 +644,11 @@ mod tests { } #[test] - fn test_set_for_current() { + fn test_set_affinity() { let ids = get_core_ids().unwrap(); assert!(!ids.is_empty()); - set_for_current(ids[0]).unwrap(); + ids[0].set_affinity().unwrap(); } } diff --git a/libafl/src/bolts/llmp.rs b/libafl/src/bolts/llmp.rs index 9876d3dca1..e89c70eaf0 100644 --- a/libafl/src/bolts/llmp.rs +++ b/libafl/src/bolts/llmp.rs @@ -2745,7 +2745,7 @@ mod tests { #[test] #[serial] - pub fn llmp_connection() { + pub fn test_llmp_connection() { #[allow(unused_variables)] let shmem_provider = StdShMemProvider::new().unwrap(); let mut broker = match LlmpConnection::on_port(shmem_provider.clone(), 1337).unwrap() { diff --git a/libafl/src/bolts/minibsod.rs b/libafl/src/bolts/minibsod.rs index 231d57b0e8..e5a100df76 100644 --- a/libafl/src/bolts/minibsod.rs +++ b/libafl/src/bolts/minibsod.rs @@ -103,7 +103,7 @@ pub fn dump_registers( writer: &mut BufWriter, ucontext: &ucontext_t, ) -> Result<(), std::io::Error> { - let mcontext = unsafe { *ucontext.uc_mcontext }; + let mcontext = unsafe { &*ucontext.uc_mcontext }; for reg in 0..29_u8 { writeln!( writer, @@ -225,7 +225,7 @@ fn write_crash( signal: Signal, ucontext: &ucontext_t, ) -> Result<(), std::io::Error> { - let mcontext = unsafe { *ucontext.uc_mcontext }; + let mcontext = unsafe { &*ucontext.uc_mcontext }; writeln!( writer, "Received signal {} at 0x{:016x}, fault address: 0x{:016x}", diff --git a/libafl/src/bolts/os/unix_shmem_server.rs b/libafl/src/bolts/os/unix_shmem_server.rs index 1986128f2c..6c9d325f9b 100644 --- a/libafl/src/bolts/os/unix_shmem_server.rs +++ b/libafl/src/bolts/os/unix_shmem_server.rs @@ -190,6 +190,7 @@ where res.id = id; Ok(res) } + fn new_shmem(&mut self, map_size: usize) -> Result { let (server_fd, client_fd) = self.send_receive(ServedShMemRequest::NewMap(map_size))?; @@ -718,3 +719,25 @@ where } } } + +/* +TODO: Fix test + +#[cfg(test)] +mod tests { + use serial_test::serial; + + use crate::bolts::{ + os::unix_shmem_server::ServedShMemProvider, + shmem::{ShMem, ShMemProvider, UnixShMemProvider}, + }; + + #[test] + #[serial] + fn test_shmem_server_connection() { + let mut sp = ServedShMemProvider::::new().unwrap(); + let map = sp.new_shmem(2 << 14).unwrap(); + assert!(map.is_empty()); + } +} +*/ diff --git a/libafl/src/bolts/os/unix_signals.rs b/libafl/src/bolts/os/unix_signals.rs index 815fa25152..1dd39649a2 100644 --- a/libafl/src/bolts/os/unix_signals.rs +++ b/libafl/src/bolts/os/unix_signals.rs @@ -67,8 +67,8 @@ pub struct mcontext_t { pub fault_address: c_ulong, } -/// User Context Struct -#[cfg(target_arch = "arm")] +/// User Context Struct on `arm` `linux` +#[cfg(all(target_os = "linux", target_arch = "arm"))] #[derive(Debug)] #[allow(non_camel_case_types)] #[repr(C)] @@ -85,9 +85,165 @@ pub struct ucontext_t { pub uc_sigmask: libc::sigset_t, } -#[cfg(not(target_arch = "arm"))] +/// # Internal representation +/// +/// ```c +/// _STRUCT_ARM_EXCEPTION_STATE64 +/// { +/// __uint64_t far; /* Virtual Fault Address */ +/// __uint32_t esr; /* Exception syndrome */ +/// __uint32_t exception; /* number of arm exception taken */ +/// }; +/// ``` +#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] +#[derive(Debug)] +#[repr(C)] +pub struct arm_exception_state64 { + /// Virtual Fault Address + pub __far: u64, + /// Exception syndrome + pub __esr: u32, + /// number of arm exception taken + pub __exception: u32, +} + +/// ```c +/// _STRUCT_ARM_THREAD_STATE64 +/// { +/// __uint64_t __x[29]; /* General purpose registers x0-x28 */ +/// __uint64_t __fp; /* Frame pointer x29 */ +/// __uint64_t __lr; /* Link register x30 */ +/// __uint64_t __sp; /* Stack pointer x31 */ +/// __uint64_t __pc; /* Program counter */ +/// __uint32_t __cpsr; /* Current program status register */ +/// __uint32_t __pad; /* Same size for 32-bit or 64-bit clients */ +/// }; +/// ``` +#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] +#[derive(Debug)] +#[repr(C)] +pub struct arm_thread_state64 { + /// General purpose registers x0-x28 + pub __x: [u64; 29], + /// Frame pointer x29 + pub __fp: u64, + /// Link register x30 + pub __lr: u64, + /// Stack pointer x31 + pub __sp: u64, + /// Program counter + pub __pc: u64, + /// Current program status register + pub __cpsr: u32, + /// Same size for 32-bit or 64-bit clients + pub __pad: u32, +} + +/// ```c +/// _STRUCT_ARM_NEON_STATE64 +/// { +/// char opaque[(32 * 16) + (2 * sizeof(__uint32_t))]; +/// } __attribute__((aligned(16))); +/// ```` +#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] +#[derive(Debug)] +#[allow(non_camel_case_types)] +#[repr(C, align(16))] +//#[repr(align(16))] +pub struct arm_neon_state64 { + /// opaque + pub opaque: [u8; (32 * 16) + (2 * mem::size_of::())], +} + +/// ```c +/// _STRUCT_MCONTEXT64 +/// { +/// _STRUCT_ARM_EXCEPTION_STATE64 es; +/// _STRUCT_ARM_THREAD_STATE64 ss; +/// _STRUCT_ARM_NEON_STATE64 ns; +///}; +/// ``` +#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] +#[allow(non_camel_case_types)] +#[derive(Debug)] +#[repr(C)] +pub struct mcontext64 { + /// _STRUCT_ARM_EXCEPTION_STATE64 + pub __es: arm_exception_state64, + /// _STRUCT_ARM_THREAD_STATE64 + pub __ss: arm_thread_state64, + /// _STRUCT_ARM_NEON_STATE64 + pub __ns: arm_neon_state64, +} + +/// ```c +/// _STRUCT_SIGALTSTACK +/// { +/// void *ss_sp; /* signal stack base */ +/// __darwin_size_t ss_size; /* signal stack length */ +/// int ss_flags; /* SA_DISABLE and/or SA_ONSTACK */ +/// }; +/// ```` +#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] +#[derive(Debug)] +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct sigaltstack { + /// signal stack base + pub ss_sp: *mut c_void, + /// signal stack length + pub ss_size: libc::size_t, + /// SA_DISABLE and/or SA_ONSTACK + pub ss_flags: c_int, +} + +/// User Context Struct on apple `aarch64` +/// +/// ```c +/// _STRUCT_UCONTEXT +/// { +/// int uc_onstack; +/// __darwin_sigset_t uc_sigmask; /* signal mask used by this context */ +/// _STRUCT_SIGALTSTACK uc_stack; /* stack used by this context */ +/// _STRUCT_UCONTEXT *uc_link; /* pointer to resuming context */ +/// __darwin_size_t uc_mcsize; /* size of the machine context passed in */ +/// _STRUCT_MCONTEXT *uc_mcontext; /* pointer to machine specific context */ +/// #ifdef _XOPEN_SOURCE +/// _STRUCT_MCONTEXT __mcontext_data; +/// #endif /* _XOPEN_SOURCE */ +/// }; +/// ``` +#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] +#[derive(Debug)] +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct ucontext_t { + /// onstack + pub uc_onstack: c_int, + /// signal mask used by this context + pub uc_sigmask: u32, + /// stack used by this context + pub uc_stack: sigaltstack, + /// pointer to resuming context + pub uc_link: *mut c_void, + /// size of the machine context passed in + pub uc_mcsize: ssize_t, + /// pointer to machine specific context + pub uc_mcontext: *mut mcontext64, + /// The mcontext data in multiple steps. + pub mcontext_data: mcontext64, +} + +pub use libc::{c_void, siginfo_t}; + +#[cfg(not(any( + all(target_os = "linux", target_arch = "arm"), + all(target_vendor = "apple", target_arch = "aarch64") +)))] pub use libc::ucontext_t; +#[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] +use libc::ssize_t; use libc::{ c_int, malloc, sigaction, sigaddset, sigaltstack, sigemptyset, stack_t, SA_NODEFER, SA_ONSTACK, SA_SIGINFO, SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, SIGPIPE, @@ -97,17 +253,10 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; use crate::Error; -pub use libc::{c_void, siginfo_t}; - extern "C" { /// The `libc` `getcontext` + /// For some reason, it's not available on MacOS. /// - /// # Notes - /// - /// Somehow, `MacOS` on `aarch64` claims this type uses a 128 bit `int` - /// (@`rustc` 1.59.0) - /// Not much we can about it, for now. - #[allow(improper_ctypes)] fn getcontext(ucp: *mut ucontext_t) -> c_int; } diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index aafc8c102c..52d0116b6a 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -12,10 +12,7 @@ use crate::bolts::{ llmp::{LLMP_FLAG_COMPRESSED, LLMP_FLAG_INITIALIZED}, }; #[cfg(feature = "std")] -use crate::bolts::{ - core_affinity::set_for_current, llmp::LlmpConnection, shmem::StdShMemProvider, - staterestore::StateRestorer, -}; +use crate::bolts::{llmp::LlmpConnection, shmem::StdShMemProvider, staterestore::StateRestorer}; use crate::{ bolts::{ llmp::{self, Flags, LlmpClient, LlmpClientDescription, Tag}, @@ -825,8 +822,9 @@ where }; if let Some(core_id) = core_id { + let core_id: CoreId = core_id; println!("Setting core affinity to {:?}", core_id); - set_for_current(core_id)?; + core_id.set_affinity()?; } // We are the fuzzer respawner in a llmp client @@ -894,7 +892,8 @@ where }; if let Some(core_id) = core_id { - set_for_current(core_id)?; + let core_id: CoreId = core_id; + core_id.set_affinity()?; } // If we're restarting, deserialize the old state. diff --git a/libafl/src/executors/command.rs b/libafl/src/executors/command.rs index 7b0ad8d341..4549a7d6ff 100644 --- a/libafl/src/executors/command.rs +++ b/libafl/src/executors/command.rs @@ -41,8 +41,8 @@ use super::HasObservers; /// `StdIn`: The traget reads from stdin /// `File`: The target reads from the specified [`InputFile`] #[derive(Debug, Clone, PartialEq, Eq)] -enum InputLocation { - /// Mutate a commandline argument to deliver an input +pub enum InputLocation { + /// Mutate a command line argument to deliver an input Arg { /// The offset of the argument to mutate argnum: usize, diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index b728b8cfe3..c5ae8a20fe 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -1624,6 +1624,7 @@ pub mod child_signal_handlers { #[cfg(test)] mod tests { use core::marker::PhantomData; + use serial_test::serial; #[cfg(all(feature = "std", feature = "fork", unix))] use crate::{ @@ -1653,6 +1654,7 @@ mod tests { } #[test] + #[serial] #[cfg(all(feature = "std", feature = "fork", unix))] fn test_inprocessfork_exec() { use crate::executors::inprocess::InChildProcessHandlers; diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index 1b27ecc1fa..ca64edd213 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -161,6 +161,8 @@ pub enum Error { IllegalState(String, ErrorBacktrace), /// The argument passed to this method or function is not valid IllegalArgument(String, ErrorBacktrace), + /// The performed action is not supported on the current platform + Unsupported(String, ErrorBacktrace), /// Shutting down, not really an error. ShuttingDown, /// Something else happened @@ -249,6 +251,14 @@ impl Error { pub fn shutting_down() -> Self { Error::ShuttingDown } + /// This operation is not supported on the current architecture or platform + #[must_use] + pub fn unsupported(arg: S) -> Self + where + S: Into, + { + Error::Unsupported(arg.into(), ErrorBacktrace::new()) + } /// Something else happened #[must_use] pub fn unknown(arg: S) -> Self @@ -304,6 +314,14 @@ impl fmt::Display for Error { write!(f, "Illegal argument: {0}", &s)?; display_error_backtrace(f, b) } + Self::Unsupported(s, b) => { + write!( + f, + "The operation is not supported on the current platform: {0}", + &s + )?; + display_error_backtrace(f, b) + } Self::ShuttingDown => write!(f, "Shutting down!"), Self::Unknown(s, b) => { write!(f, "Unknown error: {0}", &s)?;