From 0154a3b930876d23d2562540d9b761ab9495faf1 Mon Sep 17 00:00:00 2001 From: WorksButNotTested <62701594+WorksButNotTested@users.noreply.github.com> Date: Fri, 14 Mar 2025 12:19:23 +0000 Subject: [PATCH] Added heap feature (#3074) * Added heap feature * Rename feature and add some more docs * Use document-features crate * Expose the patching API for more flexibility --------- Co-authored-by: Your Name --- libafl_qemu/librasan/asan/Cargo.toml | 17 +++++++++ libafl_qemu/librasan/asan/src/hooks/mod.rs | 2 +- libafl_qemu/librasan/asan/src/lib.rs | 14 +------- libafl_qemu/librasan/asan/src/mem.rs | 17 ++++++--- libafl_qemu/librasan/asan/src/patch/hooks.rs | 37 ++++++++++++-------- libafl_qemu/librasan/gasan/Cargo.toml | 1 + libafl_qemu/librasan/qasan/Cargo.toml | 1 + libafl_qemu/librasan/zasan/Cargo.toml | 1 + 8 files changed, 57 insertions(+), 33 deletions(-) diff --git a/libafl_qemu/librasan/asan/Cargo.toml b/libafl_qemu/librasan/asan/Cargo.toml index 5c664012c2..d48a51733d 100644 --- a/libafl_qemu/librasan/asan/Cargo.toml +++ b/libafl_qemu/librasan/asan/Cargo.toml @@ -8,8 +8,11 @@ rust-version.workspace = true crate-type = ["rlib"] [features] +#! # Features default = [ "dlmalloc", + "document-features", + "global_allocator", "guest", "hooks", "host", @@ -19,14 +22,27 @@ default = [ "test", "tracking", ] +## Enable support for the `dlmalloc` allocator backend dlmalloc = ["dep:dlmalloc"] +## Enable documentation of features +document-features = ["dep:document-features"] +## Configure a global allocator (using dlmalloc or mimalloc as configured) +global_allocator = [] +## Enable support for shadow memory and tracking in the guest guest = [] +## Enable support for hooking functions in the guest hooks = [] +## Enable support for shadow memory and tracking in the host host = ["dep:syscalls"] +## Enable use of the `libc` library to support creation of mappings, read/write, logging etc (more OS agnostic) libc = ["dep:libc"] +## Enable the use of direct syscalls (supported by `rustix`) to interact with the operating system (Linux specific). linux = ["dep:rustix"] +## Enable the `baby_mimalloc` allocator mimalloc = ["dep:baby-mimalloc"] +## Disable the magic used to support `no_std` environments for running unit and integration tests test = [] +## Enable support for memory tracking tracking = [] [dependencies] @@ -34,6 +50,7 @@ baby-mimalloc = { version = "0.2.1", default-features = false, features = [ "spin_mutex", ], optional = true } bitflags = { version = "2.8.0", default-features = false } +document-features = { version = "0.2.11", optional = true } dlmalloc = { version = "0.2.7", default-features = false, optional = true } itertools = { version = "0.14.0", default-features = false } log = { version = "0.4.22", default-features = false, features = [ diff --git a/libafl_qemu/librasan/asan/src/hooks/mod.rs b/libafl_qemu/librasan/asan/src/hooks/mod.rs index a1501266f2..952a47ae47 100644 --- a/libafl_qemu/librasan/asan/src/hooks/mod.rs +++ b/libafl_qemu/librasan/asan/src/hooks/mod.rs @@ -73,7 +73,7 @@ pub struct PatchedHook { } impl PatchedHook { - const fn new(name: &'static CStr, func: F) -> Self { + pub const fn new(name: &'static CStr, func: F) -> Self { let pf = (&func) as *const F as *const GuestAddr; let destination = unsafe { *pf }; Self { name, destination } diff --git a/libafl_qemu/librasan/asan/src/lib.rs b/libafl_qemu/librasan/asan/src/lib.rs index 09585c5143..d63bca14bb 100644 --- a/libafl_qemu/librasan/asan/src/lib.rs +++ b/libafl_qemu/librasan/asan/src/lib.rs @@ -29,21 +29,9 @@ //! The componentized nature of the design is intended to permit the user to //! adapt `asan` to their needs with minimal modification by selecting and //! combining alternative implementations of the various key components. -//! -//! ## Features -//! - `dlmalloc` - Enable support for the dlmalloc allocator backend. -//! - `guest` - Enable support for shadow memory and tracking in the guest -//! - `hooks` - Enable support for hooking functions in the guest -//! - `host` - Enable support for shadow memory and tracking in the host -//! - `libc` - Enable use of the `libc` library to support creation of mappings, -//! read/write, logging etc (more OS agnostic) -//! - `linux` - Enable the use of direct syscalls (supported by `rustix`) to -//! interact with the operating system (Linux specific). -//! - `test` - Disable the magic used to support `no_std` environments for -//! running unit and integration tests -//! - `tracking` - Enable support for memory tracking. #![cfg_attr(not(feature = "test"), no_std)] #![cfg_attr(target_arch = "powerpc", feature(asm_experimental_arch))] +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] pub mod allocator; diff --git a/libafl_qemu/librasan/asan/src/mem.rs b/libafl_qemu/librasan/asan/src/mem.rs index 9fb053025f..21b5b3bbf7 100644 --- a/libafl_qemu/librasan/asan/src/mem.rs +++ b/libafl_qemu/librasan/asan/src/mem.rs @@ -3,10 +3,10 @@ use core::{ slice::{from_raw_parts, from_raw_parts_mut}, }; -#[cfg(feature = "dlmalloc")] +#[cfg(all(feature = "global_allocator", feature = "dlmalloc"))] use crate::allocator::backend::dlmalloc::DlmallocBackend; -#[cfg(all(feature = "linux", not(feature = "libc")))] +#[cfg(all(feature = "global_allocator", feature = "linux", not(feature = "libc")))] type Mmap = crate::mmap::linux::LinuxMmap; #[cfg(feature = "libc")] @@ -14,14 +14,23 @@ type Mmap = crate::mmap::libc::LibcMmap< crate::symbols::dlsym::DlSymSymbols, >; +#[cfg(all(feature = "global_allocator"))] const PAGE_SIZE: usize = 4096; #[global_allocator] -#[cfg(all(feature = "dlmalloc", not(feature = "mimalloc")))] +#[cfg(all( + feature = "global_allocator", + feature = "dlmalloc", + not(feature = "mimalloc") +))] static GLOBAL_ALLOCATOR: DlmallocBackend = DlmallocBackend::new(PAGE_SIZE); #[global_allocator] -#[cfg(all(feature = "dlmalloc", feature = "mimalloc"))] +#[cfg(all( + feature = "global_allocator", + feature = "dlmalloc", + feature = "mimalloc" +))] static GLOBAL_ALLOCATOR: baby_mimalloc::MimallocMutexWrapper> = baby_mimalloc::MimallocMutexWrapper::with_os_allocator(DlmallocBackend::new(PAGE_SIZE)); diff --git a/libafl_qemu/librasan/asan/src/patch/hooks.rs b/libafl_qemu/librasan/asan/src/patch/hooks.rs index 609f8bf935..ab913fac98 100644 --- a/libafl_qemu/librasan/asan/src/patch/hooks.rs +++ b/libafl_qemu/librasan/asan/src/patch/hooks.rs @@ -23,26 +23,32 @@ impl PatchedHooks { pub fn init() -> Result<(), PatchesError> { debug!("Installing patches"); - let reader = R::new().map_err(|e| PatchesError::MapReaderError(e))?; - let mappings = MapIterator::new(reader).collect::>(); + let mappings = Self::get_mappings()?; mappings.iter().for_each(|m| trace!("{m:?}")); - let patches = PatchedHook::all() - .into_iter() - .map(|p| Self::apply_patch(p, &mappings)) - .collect::, PatchesError>>()?; - PATCHED.lock().replace(patches); + for patch in PatchedHook::all() { + Self::patch(patch, &mappings)?; + } debug!("Patching complete"); Ok(()) } - fn apply_patch( - p: PatchedHook, + pub fn get_mappings() + -> Result, PatchesError> { + let reader = R::new().map_err(|e| PatchesError::MapReaderError(e))?; + Ok(MapIterator::new(reader).collect::>()) + } + + pub fn patch( + patch: PatchedHook, mappings: &[MapEntry], - ) -> Result<(GuestAddr, PatchedHook), PatchesError> { - trace!("patch: {:?}, destination: {:#x}", p.name, p.destination); - let target = S::lookup(p.name.as_ptr() as *const c_char) + ) -> Result<(), PatchesError> { + trace!( + "patch: {:?}, destination: {:#x}", + patch.name, patch.destination + ); + let target = S::lookup(patch.name.as_ptr() as *const c_char) .map_err(|e| PatchesError::SymbolsError(e))?; - trace!("patching: {:#x} -> {:#x}", target, p.destination); + trace!("patching: {:#x} -> {:#x}", target, patch.destination); let mapping = mappings .iter() .filter(|m| m.contains(target)) @@ -51,9 +57,10 @@ impl PatchedHooks { let prot = mapping .writeable::() .map_err(|e| PatchesError::MmapError(e))?; - P::patch(target, p.destination).map_err(|e| PatchesError::PatchError(e))?; + P::patch(target, patch.destination).map_err(|e| PatchesError::PatchError(e))?; drop(prot); - Ok((target, p)) + PATCHED.lock().get_or_insert_default().insert(target, patch); + Ok(()) } pub fn check_patched(addr: GuestAddr) -> Result<(), PatchesCheckError> { diff --git a/libafl_qemu/librasan/gasan/Cargo.toml b/libafl_qemu/librasan/gasan/Cargo.toml index ecbfb19756..1a408e0d04 100644 --- a/libafl_qemu/librasan/gasan/Cargo.toml +++ b/libafl_qemu/librasan/gasan/Cargo.toml @@ -14,6 +14,7 @@ test = ["asan/test", "dummy_libc/test"] [dependencies] asan = { path = "../asan", default-features = false, features = [ "dlmalloc", + "global_allocator", "guest", "hooks", "libc", diff --git a/libafl_qemu/librasan/qasan/Cargo.toml b/libafl_qemu/librasan/qasan/Cargo.toml index e7f1ed66d0..58679a6570 100644 --- a/libafl_qemu/librasan/qasan/Cargo.toml +++ b/libafl_qemu/librasan/qasan/Cargo.toml @@ -14,6 +14,7 @@ test = ["asan/test", "dummy_libc/test"] [dependencies] asan = { path = "../asan", default-features = false, features = [ "dlmalloc", + "global_allocator", "hooks", "host", "libc", diff --git a/libafl_qemu/librasan/zasan/Cargo.toml b/libafl_qemu/librasan/zasan/Cargo.toml index 2821b6d662..2672c57a4f 100644 --- a/libafl_qemu/librasan/zasan/Cargo.toml +++ b/libafl_qemu/librasan/zasan/Cargo.toml @@ -14,6 +14,7 @@ test = ["asan/test"] [dependencies] asan = { path = "../asan", default-features = false, features = [ "dlmalloc", + "global_allocator", "guest", "hooks", "host",