Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apple aarch64 fixes #660

Merged
merged 10 commits into from
Jun 4, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 31 additions & 71 deletions libafl/src/bolts/core_affinity.rs
Original file line number Diff line number Diff line change
@@ -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::<Vec<_>>();
@@ -43,16 +43,6 @@ pub fn get_core_ids() -> Result<Vec<CoreId>, 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,28 +277,20 @@ mod linux {

#[cfg(test)]
mod tests {
use num_cpus;

use super::*;

#[test]
fn test_linux_get_affinity_mask() {
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 <https://opensource.apple.com/source/xnu/xnu-792/osfmk/mach/kern_return.h>
//|| (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();
}
}
2 changes: 1 addition & 1 deletion libafl/src/bolts/llmp.rs
Original file line number Diff line number Diff line change
@@ -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() {
4 changes: 2 additions & 2 deletions libafl/src/bolts/minibsod.rs
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ pub fn dump_registers<W: Write>(
writer: &mut BufWriter<W>,
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<W: Write>(
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}",
23 changes: 23 additions & 0 deletions libafl/src/bolts/os/unix_shmem_server.rs
Original file line number Diff line number Diff line change
@@ -190,6 +190,7 @@ where
res.id = id;
Ok(res)
}

fn new_shmem(&mut self, map_size: usize) -> Result<Self::ShMem, Error> {
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::<UnixShMemProvider>::new().unwrap();
let map = sp.new_shmem(2 << 14).unwrap();
assert!(map.is_empty());
}
}
*/
171 changes: 160 additions & 11 deletions libafl/src/bolts/os/unix_signals.rs
Original file line number Diff line number Diff line change
@@ -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::<u32>())],
}

/// ```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;
}

11 changes: 5 additions & 6 deletions libafl/src/events/llmp.rs
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions libafl/src/executors/command.rs
Original file line number Diff line number Diff line change
@@ -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,
2 changes: 2 additions & 0 deletions libafl/src/executors/inprocess.rs
Original file line number Diff line number Diff line change
@@ -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;
18 changes: 18 additions & 0 deletions libafl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<S>(arg: S) -> Self
where
S: Into<String>,
{
Error::Unsupported(arg.into(), ErrorBacktrace::new())
}
/// Something else happened
#[must_use]
pub fn unknown<S>(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)?;