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
This commit is contained in:
parent
bfbaa7ae83
commit
533a93ddd6
@ -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.
|
||||
|
@ -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<RawFd, AshmemClient>,
|
||||
all_maps: HashMap<i32, Rc<RefCell<AshmemShMem>>>,
|
||||
all_maps: HashMap<i32, Weak<RefCell<AshmemShMem>>>,
|
||||
}
|
||||
|
||||
#[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);
|
||||
|
@ -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()
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
|
Loading…
x
Reference in New Issue
Block a user