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 <you@example.com>
This commit is contained in:
WorksButNotTested 2025-03-14 12:19:23 +00:00 committed by GitHub
parent e728df9843
commit 0154a3b930
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 57 additions and 33 deletions

View File

@ -8,8 +8,11 @@ rust-version.workspace = true
crate-type = ["rlib"] crate-type = ["rlib"]
[features] [features]
#! # Features
default = [ default = [
"dlmalloc", "dlmalloc",
"document-features",
"global_allocator",
"guest", "guest",
"hooks", "hooks",
"host", "host",
@ -19,14 +22,27 @@ default = [
"test", "test",
"tracking", "tracking",
] ]
## Enable support for the `dlmalloc` allocator backend
dlmalloc = ["dep:dlmalloc"] 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 = [] guest = []
## Enable support for hooking functions in the guest
hooks = [] hooks = []
## Enable support for shadow memory and tracking in the host
host = ["dep:syscalls"] host = ["dep:syscalls"]
## Enable use of the `libc` library to support creation of mappings, read/write, logging etc (more OS agnostic)
libc = ["dep:libc"] libc = ["dep:libc"]
## Enable the use of direct syscalls (supported by `rustix`) to interact with the operating system (Linux specific).
linux = ["dep:rustix"] linux = ["dep:rustix"]
## Enable the `baby_mimalloc` allocator
mimalloc = ["dep:baby-mimalloc"] mimalloc = ["dep:baby-mimalloc"]
## Disable the magic used to support `no_std` environments for running unit and integration tests
test = [] test = []
## Enable support for memory tracking
tracking = [] tracking = []
[dependencies] [dependencies]
@ -34,6 +50,7 @@ baby-mimalloc = { version = "0.2.1", default-features = false, features = [
"spin_mutex", "spin_mutex",
], optional = true } ], optional = true }
bitflags = { version = "2.8.0", default-features = false } 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 } dlmalloc = { version = "0.2.7", default-features = false, optional = true }
itertools = { version = "0.14.0", default-features = false } itertools = { version = "0.14.0", default-features = false }
log = { version = "0.4.22", default-features = false, features = [ log = { version = "0.4.22", default-features = false, features = [

View File

@ -73,7 +73,7 @@ pub struct PatchedHook {
} }
impl PatchedHook { impl PatchedHook {
const fn new<F: Copy>(name: &'static CStr, func: F) -> Self { pub const fn new<F: Copy>(name: &'static CStr, func: F) -> Self {
let pf = (&func) as *const F as *const GuestAddr; let pf = (&func) as *const F as *const GuestAddr;
let destination = unsafe { *pf }; let destination = unsafe { *pf };
Self { name, destination } Self { name, destination }

View File

@ -29,21 +29,9 @@
//! The componentized nature of the design is intended to permit the user to //! The componentized nature of the design is intended to permit the user to
//! adapt `asan` to their needs with minimal modification by selecting and //! adapt `asan` to their needs with minimal modification by selecting and
//! combining alternative implementations of the various key components. //! 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(not(feature = "test"), no_std)]
#![cfg_attr(target_arch = "powerpc", feature(asm_experimental_arch))] #![cfg_attr(target_arch = "powerpc", feature(asm_experimental_arch))]
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
pub mod allocator; pub mod allocator;

View File

@ -3,10 +3,10 @@ use core::{
slice::{from_raw_parts, from_raw_parts_mut}, slice::{from_raw_parts, from_raw_parts_mut},
}; };
#[cfg(feature = "dlmalloc")] #[cfg(all(feature = "global_allocator", feature = "dlmalloc"))]
use crate::allocator::backend::dlmalloc::DlmallocBackend; 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; type Mmap = crate::mmap::linux::LinuxMmap;
#[cfg(feature = "libc")] #[cfg(feature = "libc")]
@ -14,14 +14,23 @@ type Mmap = crate::mmap::libc::LibcMmap<
crate::symbols::dlsym::DlSymSymbols<crate::symbols::dlsym::LookupTypeNext>, crate::symbols::dlsym::DlSymSymbols<crate::symbols::dlsym::LookupTypeNext>,
>; >;
#[cfg(all(feature = "global_allocator"))]
const PAGE_SIZE: usize = 4096; const PAGE_SIZE: usize = 4096;
#[global_allocator] #[global_allocator]
#[cfg(all(feature = "dlmalloc", not(feature = "mimalloc")))] #[cfg(all(
feature = "global_allocator",
feature = "dlmalloc",
not(feature = "mimalloc")
))]
static GLOBAL_ALLOCATOR: DlmallocBackend<Mmap> = DlmallocBackend::new(PAGE_SIZE); static GLOBAL_ALLOCATOR: DlmallocBackend<Mmap> = DlmallocBackend::new(PAGE_SIZE);
#[global_allocator] #[global_allocator]
#[cfg(all(feature = "dlmalloc", feature = "mimalloc"))] #[cfg(all(
feature = "global_allocator",
feature = "dlmalloc",
feature = "mimalloc"
))]
static GLOBAL_ALLOCATOR: baby_mimalloc::MimallocMutexWrapper<DlmallocBackend<Mmap>> = static GLOBAL_ALLOCATOR: baby_mimalloc::MimallocMutexWrapper<DlmallocBackend<Mmap>> =
baby_mimalloc::MimallocMutexWrapper::with_os_allocator(DlmallocBackend::new(PAGE_SIZE)); baby_mimalloc::MimallocMutexWrapper::with_os_allocator(DlmallocBackend::new(PAGE_SIZE));

View File

@ -23,26 +23,32 @@ impl PatchedHooks {
pub fn init<S: Symbols, P: Patch, R: MapReader, M: Mmap>() pub fn init<S: Symbols, P: Patch, R: MapReader, M: Mmap>()
-> Result<(), PatchesError<S, P, R, M>> { -> Result<(), PatchesError<S, P, R, M>> {
debug!("Installing patches"); debug!("Installing patches");
let reader = R::new().map_err(|e| PatchesError::MapReaderError(e))?; let mappings = Self::get_mappings()?;
let mappings = MapIterator::new(reader).collect::<Vec<MapEntry>>();
mappings.iter().for_each(|m| trace!("{m:?}")); mappings.iter().for_each(|m| trace!("{m:?}"));
let patches = PatchedHook::all() for patch in PatchedHook::all() {
.into_iter() Self::patch(patch, &mappings)?;
.map(|p| Self::apply_patch(p, &mappings)) }
.collect::<Result<BTreeMap<GuestAddr, PatchedHook>, PatchesError<S, P, R, M>>>()?;
PATCHED.lock().replace(patches);
debug!("Patching complete"); debug!("Patching complete");
Ok(()) Ok(())
} }
fn apply_patch<S: Symbols, P: Patch, R: MapReader, M: Mmap>( pub fn get_mappings<S: Symbols, P: Patch, R: MapReader, M: Mmap>()
p: PatchedHook, -> Result<Vec<MapEntry>, PatchesError<S, P, R, M>> {
let reader = R::new().map_err(|e| PatchesError::MapReaderError(e))?;
Ok(MapIterator::new(reader).collect::<Vec<MapEntry>>())
}
pub fn patch<S: Symbols, P: Patch, R: MapReader, M: Mmap>(
patch: PatchedHook,
mappings: &[MapEntry], mappings: &[MapEntry],
) -> Result<(GuestAddr, PatchedHook), PatchesError<S, P, R, M>> { ) -> Result<(), PatchesError<S, P, R, M>> {
trace!("patch: {:?}, destination: {:#x}", p.name, p.destination); trace!(
let target = S::lookup(p.name.as_ptr() as *const c_char) "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))?; .map_err(|e| PatchesError::SymbolsError(e))?;
trace!("patching: {:#x} -> {:#x}", target, p.destination); trace!("patching: {:#x} -> {:#x}", target, patch.destination);
let mapping = mappings let mapping = mappings
.iter() .iter()
.filter(|m| m.contains(target)) .filter(|m| m.contains(target))
@ -51,9 +57,10 @@ impl PatchedHooks {
let prot = mapping let prot = mapping
.writeable::<M>() .writeable::<M>()
.map_err(|e| PatchesError::MmapError(e))?; .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); drop(prot);
Ok((target, p)) PATCHED.lock().get_or_insert_default().insert(target, patch);
Ok(())
} }
pub fn check_patched(addr: GuestAddr) -> Result<(), PatchesCheckError> { pub fn check_patched(addr: GuestAddr) -> Result<(), PatchesCheckError> {

View File

@ -14,6 +14,7 @@ test = ["asan/test", "dummy_libc/test"]
[dependencies] [dependencies]
asan = { path = "../asan", default-features = false, features = [ asan = { path = "../asan", default-features = false, features = [
"dlmalloc", "dlmalloc",
"global_allocator",
"guest", "guest",
"hooks", "hooks",
"libc", "libc",

View File

@ -14,6 +14,7 @@ test = ["asan/test", "dummy_libc/test"]
[dependencies] [dependencies]
asan = { path = "../asan", default-features = false, features = [ asan = { path = "../asan", default-features = false, features = [
"dlmalloc", "dlmalloc",
"global_allocator",
"hooks", "hooks",
"host", "host",
"libc", "libc",

View File

@ -14,6 +14,7 @@ test = ["asan/test"]
[dependencies] [dependencies]
asan = { path = "../asan", default-features = false, features = [ asan = { path = "../asan", default-features = false, features = [
"dlmalloc", "dlmalloc",
"global_allocator",
"guest", "guest",
"hooks", "hooks",
"host", "host",