From 533a93ddd6dc3b342762cfaff462970d74970740 Mon Sep 17 00:00:00 2001 From: s1341 Date: Fri, 21 May 2021 14:34:35 +0300 Subject: [PATCH] Various frida/ashmem fixes (#116) * Fix incorrect encoding of and imm: use a register for now * Fix assumption regarding length of ashmem clients list * Make harness less chatty * Fix refcounting in the ashmem server * Always work around the frida allocate-near bug, not just when doing asan. * Add support for ashmem on devices which have a boot secret, but don't use it * Formatting --- fuzzers/frida_libpng/harness.cc | 6 ++-- libafl/src/bolts/os/ashmem_server.rs | 41 ++++++++++++++++------------ libafl/src/bolts/shmem.rs | 8 +++++- libafl_frida/src/asan_rt.rs | 34 ++++------------------- libafl_frida/src/helper.rs | 26 ++++++++++++++++++ 5 files changed, 66 insertions(+), 49 deletions(-) diff --git a/fuzzers/frida_libpng/harness.cc b/fuzzers/frida_libpng/harness.cc index 625ab3b18f..ed74911b58 100644 --- a/fuzzers/frida_libpng/harness.cc +++ b/fuzzers/frida_libpng/harness.cc @@ -87,7 +87,7 @@ extern "C" int afl_libfuzzer_init() { static char * allocation = NULL; __attribute__((noinline)) void func3( char * alloc) { - printf("func3\n"); + //printf("func3\n"); if (random() == 0) { alloc[0x1ff] = 0xde; printf("alloc[0x200]: %d\n", alloc[0x200]); @@ -96,12 +96,12 @@ void func3( char * alloc) { __attribute__((noinline)) void func2() { allocation = (char*)malloc(0xff); - printf("func2\n"); + //printf("func2\n"); func3(allocation); } __attribute__((noinline)) void func1() { - printf("func1\n"); + //printf("func1\n"); func2(); } // Entry point for LibFuzzer. diff --git a/libafl/src/bolts/os/ashmem_server.rs b/libafl/src/bolts/os/ashmem_server.rs index 40d526f779..e3a68b0968 100644 --- a/libafl/src/bolts/os/ashmem_server.rs +++ b/libafl/src/bolts/os/ashmem_server.rs @@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize}; use std::{ cell::RefCell, io::{Read, Write}, - rc::Rc, + rc::{Rc, Weak}, sync::{Arc, Condvar, Mutex}, }; @@ -167,8 +167,8 @@ impl ShMemProvider for ServedShMemProvider { fn release_map(&mut self, map: &mut Self::Mem) { let (refcount, _) = self .send_receive(AshmemRequest::Deregister(map.server_fd)) - .expect("Could not communicate to AshMem server!"); - if refcount == 0 { + .expect("Could not communicate with AshMem server!"); + if refcount == 1 { unsafe { ManuallyDrop::drop(&mut map.inner); } @@ -211,7 +211,7 @@ impl AshmemClient { pub struct AshmemService { provider: AshmemShMemProvider, clients: HashMap, - all_maps: HashMap>>, + all_maps: HashMap>>, } #[derive(Debug)] @@ -252,9 +252,14 @@ impl AshmemService { }; Ok(AshmemResponse::Id(client_id)) } - AshmemRequest::NewMap(map_size) => Ok(AshmemResponse::Mapping(Rc::new(RefCell::new( - self.provider.new_map(map_size)?, - )))), + AshmemRequest::NewMap(map_size) => { + let new_map = self.provider.new_map(map_size)?; + let description = new_map.description(); + let new_rc = Rc::new(RefCell::new(new_map)); + self.all_maps + .insert(description.id.to_int(), Rc::downgrade(&new_rc)); + Ok(AshmemResponse::Mapping(new_rc)) + } AshmemRequest::ExistingMap(description) => { let client = self.clients.get_mut(&client_id).unwrap(); if client.maps.contains_key(&description.id.to_int()) { @@ -269,25 +274,27 @@ impl AshmemService { .unwrap() .clone(), )) - } else if self.all_maps.contains_key(&description.id.to_int()) { + } else { Ok(AshmemResponse::Mapping( self.all_maps .get_mut(&description.id.to_int()) .unwrap() - .clone(), + .clone() + .upgrade() + .unwrap(), )) - } else { - let new_rc = - Rc::new(RefCell::new(self.provider.from_description(description)?)); - self.all_maps - .insert(description.id.to_int(), new_rc.clone()); - Ok(AshmemResponse::Mapping(new_rc)) } } AshmemRequest::Deregister(map_id) => { let client = self.clients.get_mut(&client_id).unwrap(); - let map = client.maps.entry(map_id).or_default().pop().unwrap(); - Ok(AshmemResponse::RefCount(Rc::strong_count(&map) as u32)) + let maps = client.maps.entry(map_id).or_default(); + if maps.is_empty() { + Ok(AshmemResponse::RefCount(0u32)) + } else { + Ok(AshmemResponse::RefCount( + Rc::strong_count(&maps.pop().unwrap()) as u32, + )) + } } }; //println!("send ashmem client: {}, response: {:?}", client_id, &response); diff --git a/libafl/src/bolts/shmem.rs b/libafl/src/bolts/shmem.rs index 1549acc2a0..bbd7db0d07 100644 --- a/libafl/src/bolts/shmem.rs +++ b/libafl/src/bolts/shmem.rs @@ -656,7 +656,13 @@ pub mod unix_shmem { if let Ok(boot_id) = std::fs::read_to_string("/proc/sys/kernel/random/boot_id") { - format!("{}{}", "/dev/ashmem", boot_id).trim().to_string() + let path_str = + format!("{}{}", "/dev/ashmem", boot_id).trim().to_string(); + if std::path::Path::new(&path_str).exists() { + path_str + } else { + "/dev/ashmem".to_string() + } } else { "/dev/ashmem".to_string() }, diff --git a/libafl_frida/src/asan_rt.rs b/libafl_frida/src/asan_rt.rs index dd58e4cdf3..d83e9b883d 100644 --- a/libafl_frida/src/asan_rt.rs +++ b/libafl_frida/src/asan_rt.rs @@ -745,30 +745,6 @@ impl AsanRuntime { /// instance after this function has been called, as the generated blobs would become /// invalid! pub fn init(&mut self, modules_to_instrument: &[PathBuf]) { - // workaround frida's frida-gum-allocate-near bug: - unsafe { - for _ in 0..512 { - mmap( - std::ptr::null_mut(), - 128 * 1024, - ProtFlags::PROT_NONE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - -1, - 0, - ) - .expect("Failed to map dummy regions for frida workaround"); - mmap( - std::ptr::null_mut(), - 4 * 1024 * 1024, - ProtFlags::PROT_NONE, - MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, - -1, - 0, - ) - .expect("Failed to map dummy regions for frida workaround"); - } - } - unsafe { ASAN_ERRORS = Some(AsanErrors::new()); } @@ -1443,7 +1419,7 @@ impl AsanRuntime { } #[allow(clippy::unused_self)] - fn generate_shadow_check_exact_blob(&mut self, val: u32) -> Box<[u8]> { + fn generate_shadow_check_exact_blob(&mut self, val: u64) -> Box<[u8]> { let shadow_bit = Allocator::get().shadow_bit as u32; macro_rules! shadow_check_exact { ($ops:ident, $val:expr) => {dynasm!($ops @@ -1460,9 +1436,11 @@ impl AsanRuntime { ; lsr x1, x1, #16 ; lsr x1, x1, x0 ; .dword -717536768 // 0xd53b4200 //mrs x0, NZCV - ; and x1, x1, #$val as u64 - ; cmp x1, #$val - ; b.eq >done + ; stp x2, x3, [sp, #-0x10]! + ; mov x2, $val + ; ands x1, x1, x2 + ; ldp x2, x3, [sp], 0x10 + ; b.ne >done ; adr x1, >done ; nop // will be replaced by b to report diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 2d00caf97e..b6d0be139b 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -36,6 +36,8 @@ use num_traits::cast::FromPrimitive; use rangemap::RangeMap; use std::{path::PathBuf, rc::Rc}; +use nix::sys::mman::{mmap, MapFlags, ProtFlags}; + use crate::{asan_rt::AsanRuntime, FridaOptions}; /// An helper that feeds [`FridaInProcessExecutor`] with user-supplied instrumentation @@ -216,6 +218,30 @@ impl<'a> FridaInstrumentationHelper<'a> { _harness_module_name: &str, modules_to_instrument: &'a [PathBuf], ) -> Self { + // workaround frida's frida-gum-allocate-near bug: + unsafe { + for _ in 0..512 { + mmap( + std::ptr::null_mut(), + 128 * 1024, + ProtFlags::PROT_NONE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE | MapFlags::MAP_NORESERVE, + -1, + 0, + ) + .expect("Failed to map dummy regions for frida workaround"); + mmap( + std::ptr::null_mut(), + 4 * 1024 * 1024, + ProtFlags::PROT_NONE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE | MapFlags::MAP_NORESERVE, + -1, + 0, + ) + .expect("Failed to map dummy regions for frida workaround"); + } + } + let mut helper = Self { map: [0u8; MAP_SIZE], previous_pc: [0u64; 1],