Exclude ASAN DSO address ranges in QEMU AsanModule (#3180)

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
This commit is contained in:
Wim de With 2025-05-02 15:14:39 +02:00 committed by GitHub
parent 1620bd766f
commit 3b23012faf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -14,7 +14,7 @@ use std::{
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use libafl::{executors::ExitKind, observers::ObserversTuple}; use libafl::{executors::ExitKind, observers::ObserversTuple};
use libafl_bolts::os::unix_signals::Signal; use libafl_bolts::os::unix_signals::Signal;
use libafl_qemu_sys::GuestAddr; use libafl_qemu_sys::{GuestAddr, MapInfo};
use libc::{ use libc::{
MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE, c_void, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE, c_void,
}; };
@ -61,6 +61,8 @@ pub struct AsanModule {
empty: bool, empty: bool,
rt: Pin<Box<AsanGiovese>>, rt: Pin<Box<AsanGiovese>>,
filter: StdAddressFilter, filter: StdAddressFilter,
asan_lib: Option<String>,
asan_mappings: Option<Vec<MapInfo>>,
} }
pub struct AsanGiovese { pub struct AsanGiovese {
@ -408,6 +410,8 @@ impl AsanModule {
empty: true, empty: true,
rt, rt,
filter, filter,
asan_lib: None,
asan_mappings: None,
} }
} }
@ -981,7 +985,7 @@ where
// Let the use skip preloading the ASAN DSO. Maybe they want to use // Let the use skip preloading the ASAN DSO. Maybe they want to use
// their own implementation. // their own implementation.
if env::var_os("SKIP_ASAN_LD_PRELOAD").is_none() { let asan_lib = if env::var_os("SKIP_ASAN_LD_PRELOAD").is_none() {
let current = env::current_exe().unwrap(); let current = env::current_exe().unwrap();
let asan_lib = fs::canonicalize(current) let asan_lib = fs::canonicalize(current)
.unwrap() .unwrap()
@ -1034,13 +1038,18 @@ where
args.insert(1, "LD_PRELOAD=".to_string() + &asan_lib); args.insert(1, "LD_PRELOAD=".to_string() + &asan_lib);
args.insert(1, "-E".into()); args.insert(1, "-E".into());
} }
} Some(asan_lib)
} else {
None
};
unsafe { unsafe {
AsanGiovese::init(&mut self.rt, emulator_modules.hooks().qemu_hooks()); AsanGiovese::init(&mut self.rt, emulator_modules.hooks().qemu_hooks());
} }
*qemu_params = QemuParams::Cli(args); *qemu_params = QemuParams::Cli(args);
self.asan_lib = asan_lib;
} }
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, I, S>) fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, I, S>)
@ -1056,12 +1065,23 @@ where
fn first_exec<ET>( fn first_exec<ET>(
&mut self, &mut self,
_qemu: Qemu, qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, I, S>, emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S, _state: &mut S,
) where ) where
ET: EmulatorModuleTuple<I, S>, ET: EmulatorModuleTuple<I, S>,
{ {
if let Some(asan_lib) = &self.asan_lib {
let asan_mappings = qemu
.mappings()
.filter(|m| match m.path() {
Some(p) => p == asan_lib,
None => false,
})
.collect::<Vec<MapInfo>>();
self.asan_mappings = Some(asan_mappings);
}
emulator_modules.reads( emulator_modules.reads(
Hook::Function(gen_readwrite_asan::<ET, I, S>), Hook::Function(gen_readwrite_asan::<ET, I, S>),
Hook::Function(trace_read_asan::<ET, I, S, 1>), Hook::Function(trace_read_asan::<ET, I, S, 1>),
@ -1173,11 +1193,21 @@ where
S: Unpin, S: Unpin,
{ {
let h = emulator_modules.get_mut::<AsanModule>().unwrap(); let h = emulator_modules.get_mut::<AsanModule>().unwrap();
if h.must_instrument(pc) { if !h.must_instrument(pc) {
Some(pc.into()) return None;
} else {
None
} }
// Don't sanitize the sanitizer!
if let Some(asan_mappings) = &h.asan_mappings {
if asan_mappings
.iter()
.any(|m| m.start() <= pc && pc < m.end())
{
return None;
}
}
Some(pc.into())
} }
pub fn trace_read_asan<ET, I, S, const N: usize>( pub fn trace_read_asan<ET, I, S, const N: usize>(
@ -1260,11 +1290,21 @@ where
S: Unpin, S: Unpin,
{ {
let h = emulator_modules.get_mut::<AsanModule>().unwrap(); let h = emulator_modules.get_mut::<AsanModule>().unwrap();
if h.must_instrument(pc) { if !h.must_instrument(pc) {
Some(pc.into()) return Some(0);
} else {
Some(0)
} }
// Don't sanitize the sanitizer!
if let Some(asan_mappings) = &h.asan_mappings {
if asan_mappings
.iter()
.any(|m| m.start() <= pc && pc < m.end())
{
return Some(0);
}
}
Some(pc.into())
} }
pub fn trace_write_asan_snapshot<ET, I, S, const N: usize>( pub fn trace_write_asan_snapshot<ET, I, S, const N: usize>(