diff --git a/libafl_frida/src/asan/asan_rt.rs b/libafl_frida/src/asan/asan_rt.rs index f177ed9fa7..b24b79d70b 100644 --- a/libafl_frida/src/asan/asan_rt.rs +++ b/libafl_frida/src/asan/asan_rt.rs @@ -103,6 +103,13 @@ pub const ASAN_SAVE_REGISTER_NAMES: [&str; ASAN_SAVE_REGISTER_COUNT] = [ #[cfg(target_arch = "aarch64")] pub const ASAN_SAVE_REGISTER_COUNT: usize = 32; +#[cfg(target_arch = "aarch64")] +const ASAN_EH_FRAME_DWORD_COUNT: usize = 14; +#[cfg(target_arch = "aarch64")] +const ASAN_EH_FRAME_FDE_OFFSET: u32 = 20; +#[cfg(target_arch = "aarch64")] +const ASAN_EH_FRAME_FDE_ADDRESS_OFFSET: u32 = 28; + /// The frida address sanitizer runtime, providing address sanitization. /// When executing in `ASAN`, each memory access will get checked, using frida stalker under the hood. /// The runtime can report memory errors that occurred during execution, @@ -131,6 +138,9 @@ pub struct AsanRuntime { module_map: Option, suppressed_addresses: Vec, shadow_check_func: Option bool>, + + #[cfg(target_arch = "aarch64")] + eh_frame: [u32; ASAN_EH_FRAME_DWORD_COUNT], } impl Debug for AsanRuntime { @@ -304,6 +314,9 @@ impl AsanRuntime { module_map: None, suppressed_addresses: Vec::new(), shadow_check_func: None, + + #[cfg(target_arch = "aarch64")] + eh_frame: [0; ASAN_EH_FRAME_DWORD_COUNT], } } @@ -1641,18 +1654,33 @@ impl AsanRuntime { ); let blob = ops.finalize().unwrap(); + let mut map_flags = MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE; + + // apple aarch64 requires MAP_JIT to allocates WX pages + #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] + map_flags |= MapFlags::MAP_JIT; + unsafe { let mapping = mmap( std::ptr::null_mut(), 0x1000, ProtFlags::all(), - MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, + map_flags, -1, 0, ) .unwrap(); + + // on apple aarch64, WX pages can't be both writable and executable at the same time. + // pthread_jit_write_protect_np flips them from executable (1) to writable (0) + #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] + libc::pthread_jit_write_protect_np(0); + blob.as_ptr() .copy_to_nonoverlapping(mapping as *mut u8, blob.len()); + + #[cfg(all(target_vendor = "apple", target_arch = "aarch64"))] + libc::pthread_jit_write_protect_np(1); self.shadow_check_func = Some(std::mem::transmute(mapping as *mut u8)); } } @@ -1967,8 +1995,10 @@ impl AsanRuntime { ; stp x0, x1, [x28] ; adr x25, eh_frame_fde - ; adr x27, >fde_address + ; adr x15, >eh_frame_cie_addr + ; ldr x15, [x15] + ; add x0, x15, ASAN_EH_FRAME_FDE_OFFSET // eh_frame_fde + ; add x27, x15, ASAN_EH_FRAME_FDE_ADDRESS_OFFSET // fde_address ; ldr w26, [x27] ; cmp w26, #0x0 ; b.ne >skip_register @@ -2013,29 +2043,25 @@ impl AsanRuntime { ; .qword AsanRuntime::handle_trap as *mut c_void as i64 ; register_frame_func: ; .qword __register_frame as *mut c_void as i64 - ; eh_frame_cie: - ; .dword 0x14 - ; .dword 0x00 - ; .dword 0x00527a01 - ; .dword 0x011e7c01 - ; .dword 0x001f0c1b - ; eh_frame_fde: - ; .dword 0x14 - ; .dword 0x18 - ; fde_address: - ; .dword 0x0 // <-- address offset goes here - ; .dword 0x104 - //advance_loc 12 - //def_cfa r29 (x29) at offset 16 - //offset r30 (x30) at cfa-8 - //offset r29 (x29) at cfa-16 - ; .dword 0x1d0c4c00 - ; .dword 0x9d029e10u32 as i32 - ; .dword 0x04 - // empty next FDE: - ; .dword 0x0 - ; .dword 0x0 + ; eh_frame_cie_addr: + ; .qword addr_of_mut!(self.eh_frame) as i64 ); + self.eh_frame = [ + 0x14, 0, 0x00527a01, 0x011e7c01, 0x001f0c1b, + // eh_frame_fde + 0x14, 0x18, + // fde_address + 0, // <-- address offset goes here + 0x104, + // advance_loc 12 + // def_cfa r29 (x29) at offset 16 + // offset r30 (x30) at cfa-8 + // offset r29 (x29) at cfa-16 + 0x1d0c4c00, 0x9d029e10, 0x4, + // empty next FDE: + 0, 0 + ]; + self.blob_report = Some(ops_report.finalize().unwrap().into_boxed_slice()); self.blob_check_mem_byte = Some(self.generate_shadow_check_blob(0));