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:
parent
e728df9843
commit
0154a3b930
@ -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 = [
|
||||||
|
@ -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 }
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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> {
|
||||||
|
@ -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",
|
||||||
|
@ -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",
|
||||||
|
@ -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",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user