Fix frida ASAN incompatibility with mac m1 (#917)

Add MAP_JIT, and extract the writable portion of generate_instrumentation_blobs into AsanRuntime
This commit is contained in:
omergreen 2022-12-04 19:55:45 +02:00 committed by GitHub
parent 2a2e70a636
commit c879a0a8d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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<ModuleMap>,
suppressed_addresses: Vec<usize>,
shadow_check_func: Option<extern "C" fn(*const c_void, usize) -> 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, <report
; adr x0, >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
; 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
; .dword 0x1d0c4c00
; .dword 0x9d029e10u32 as i32
; .dword 0x04
0x1d0c4c00, 0x9d029e10, 0x4,
// empty next FDE:
; .dword 0x0
; .dword 0x0
);
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));