From 7c181e8fb9f3b49bb0538ec200ce46094db7e09a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 16 Jul 2025 00:11:45 +0200 Subject: [PATCH 1/3] Make mmap feature unix-wide --- crates/libafl_asan/Cargo.toml | 6 +-- crates/libafl_asan/build.rs | 2 +- .../libafl_asan/libafl_asan_fuzz/Cargo.toml | 2 +- .../fuzz_targets/default_frontend_dlmalloc.rs | 10 ++--- .../fuzz_targets/default_frontend_mock.rs | 8 ++-- crates/libafl_asan/src/exit/mod.rs | 10 ++--- crates/libafl_asan/src/file/mod.rs | 2 +- crates/libafl_asan/src/hooks/mmap/mod.rs | 2 +- crates/libafl_asan/src/hooks/munmap/mod.rs | 2 +- crates/libafl_asan/src/hooks/read/mod.rs | 2 +- crates/libafl_asan/src/hooks/write/mod.rs | 2 +- crates/libafl_asan/src/host/mod.rs | 2 +- crates/libafl_asan/src/logger/mod.rs | 2 +- crates/libafl_asan/src/mem.rs | 4 +- crates/libafl_asan/src/mmap/mod.rs | 4 +- .../src/mmap/{linux.rs => unix.rs} | 43 +++++++++++-------- crates/libafl_asan/src/test.rs | 10 ++--- crates/libafl_asan/tests/default_frontend.rs | 12 +++--- .../tests/default_frontend_mock.rs | 10 ++--- crates/libafl_asan/tests/dlmalloc_backend.rs | 8 ++-- crates/libafl_asan/tests/hooks_read_linux.rs | 2 +- crates/libafl_asan/tests/hooks_write_linux.rs | 2 +- crates/libafl_asan/tests/host.rs | 2 +- crates/libafl_asan/tests/linux_env.rs | 2 +- crates/libafl_asan/tests/linux_map_reader.rs | 2 +- crates/libafl_qemu/libafl_qemu_asan/README.md | 2 +- .../libafl_qemu_asan_nolibc/src/lib.rs | 10 ++--- 27 files changed, 87 insertions(+), 78 deletions(-) rename crates/libafl_asan/src/mmap/{linux.rs => unix.rs} (73%) diff --git a/crates/libafl_asan/Cargo.toml b/crates/libafl_asan/Cargo.toml index e2f24c07a4..6f59c0c2c4 100644 --- a/crates/libafl_asan/Cargo.toml +++ b/crates/libafl_asan/Cargo.toml @@ -29,7 +29,7 @@ default = [ "hooks", "host", "libc", - "linux", + "syscalls", "mimalloc", "test", "tracking", @@ -50,8 +50,8 @@ host = ["dep:syscalls"] initialize = [] ## 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", "dep:syscalls"] +## Enable the use of direct syscalls (supported by `rustix`) to interact with the operating system (Unix specific). +syscalls = ["dep:rustix", "dep:syscalls"] ## Enable the `baby_mimalloc` allocator mimalloc = ["dep:baby-mimalloc"] ## Disable the magic used to support `no_std` environments for running unit and integration tests (we only run our tests on Linux right now). diff --git a/crates/libafl_asan/build.rs b/crates/libafl_asan/build.rs index 86aa15b056..209f8a9592 100644 --- a/crates/libafl_asan/build.rs +++ b/crates/libafl_asan/build.rs @@ -1,5 +1,5 @@ fn main() { - #[cfg(all(feature = "linux", not(target_os = "linux")))] + //#[cfg(all(feature = "syscalls", not(target_os = "linux")))] println!("cargo:warning=The feature `linux` can only be used on Linux!"); println!("cargo:rerun-if-changed=cc/include/hooks.h"); diff --git a/crates/libafl_asan/libafl_asan_fuzz/Cargo.toml b/crates/libafl_asan/libafl_asan_fuzz/Cargo.toml index b4a13ab9a5..9f8f9dbdc3 100644 --- a/crates/libafl_asan/libafl_asan_fuzz/Cargo.toml +++ b/crates/libafl_asan/libafl_asan_fuzz/Cargo.toml @@ -15,7 +15,7 @@ libafl_asan = { path = "../", default-features = false, features = [ "guest", "host", "libc", - "linux", + "syscalls", "test", "tracking", ] } diff --git a/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_dlmalloc.rs b/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_dlmalloc.rs index ddd844a08c..7230876e19 100644 --- a/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_dlmalloc.rs +++ b/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_dlmalloc.rs @@ -8,7 +8,7 @@ use libafl_asan::{ backend::dlmalloc::DlmallocBackend, frontend::{AllocatorFrontend, default::DefaultFrontend}, }, - mmap::linux::LinuxMmap, + mmap::unix::MmapRegion, shadow::{ Shadow, guest::{DefaultShadowLayout, GuestShadow}, @@ -19,8 +19,8 @@ use libfuzzer_sys::fuzz_target; use log::info; type DF = DefaultFrontend< - DlmallocBackend, - GuestShadow, + DlmallocBackend, + GuestShadow, GuestTracking, >; @@ -28,8 +28,8 @@ const PAGE_SIZE: usize = 4096; static INIT_ONCE: LazyLock> = LazyLock::new(|| { env_logger::init(); - let backend = DlmallocBackend::::new(PAGE_SIZE); - let shadow = GuestShadow::::new().unwrap(); + let backend = DlmallocBackend::::new(PAGE_SIZE); + let shadow = GuestShadow::::new().unwrap(); let tracking = GuestTracking::new().unwrap(); let frontend = DF::new( backend, diff --git a/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_mock.rs b/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_mock.rs index df818fb8b1..1424792552 100644 --- a/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_mock.rs +++ b/crates/libafl_asan/libafl_asan_fuzz/fuzz_targets/default_frontend_mock.rs @@ -9,7 +9,7 @@ use std::{ use libafl_asan::{ GuestAddr, allocator::frontend::{AllocatorFrontend, default::DefaultFrontend}, - mmap::{Mmap, linux::LinuxMmap}, + mmap::{Mmap, unix::MmapRegion}, shadow::{ Shadow, guest::{DefaultShadowLayout, GuestShadow}, @@ -52,14 +52,14 @@ unsafe impl GlobalAlloc for MockBackend { #[derive(Error, Debug, PartialEq)] pub enum MockBackendError {} -type DF = DefaultFrontend, GuestTracking>; +type DF = DefaultFrontend, GuestTracking>; -static MAP: LazyLock = LazyLock::new(|| LinuxMmap::map(MAX_ADDR).unwrap()); +static MAP: LazyLock = LazyLock::new(|| MmapRegion::map(MAX_ADDR).unwrap()); static INIT_ONCE: LazyLock> = LazyLock::new(|| { env_logger::init(); let backend = MockBackend::new(); - let shadow = GuestShadow::::new().unwrap(); + let shadow = GuestShadow::::new().unwrap(); let tracking = GuestTracking::new().unwrap(); let frontend = DF::new( backend, diff --git a/crates/libafl_asan/src/exit/mod.rs b/crates/libafl_asan/src/exit/mod.rs index 5da0209df9..17f4723496 100644 --- a/crates/libafl_asan/src/exit/mod.rs +++ b/crates/libafl_asan/src/exit/mod.rs @@ -4,20 +4,20 @@ pub use crate::exit::libc::abort; #[cfg(feature = "libc")] pub use crate::exit::libc::exit; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] pub use crate::exit::linux::abort; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] pub use crate::exit::linux::exit; #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux"))] +#[cfg(all(feature = "syscalls", target_os = "linux"))] pub mod linux; #[cfg(all( not(feature = "libc"), - not(all(feature = "linux", target_os = "linux")) + not(all(feature = "syscalls", target_os = "linux")) ))] pub fn abort() -> ! { loop {} @@ -25,7 +25,7 @@ pub fn abort() -> ! { #[cfg(all( not(feature = "libc"), - not(all(feature = "linux", target_os = "linux")) + not(all(feature = "syscalls", target_os = "linux")) ))] pub fn exit(_status: core::ffi::c_int) -> ! { loop {} diff --git a/crates/libafl_asan/src/file/mod.rs b/crates/libafl_asan/src/file/mod.rs index 910801212c..9ea4674b7a 100644 --- a/crates/libafl_asan/src/file/mod.rs +++ b/crates/libafl_asan/src/file/mod.rs @@ -4,7 +4,7 @@ use core::ffi::CStr; #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux"))] +#[cfg(all(feature = "syscalls", target_os = "linux"))] pub mod linux; pub trait FileReader: Debug + Send + Sized { diff --git a/crates/libafl_asan/src/hooks/mmap/mod.rs b/crates/libafl_asan/src/hooks/mmap/mod.rs index 23273162cf..759766e3f2 100644 --- a/crates/libafl_asan/src/hooks/mmap/mod.rs +++ b/crates/libafl_asan/src/hooks/mmap/mod.rs @@ -1,5 +1,5 @@ #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] pub mod linux; diff --git a/crates/libafl_asan/src/hooks/munmap/mod.rs b/crates/libafl_asan/src/hooks/munmap/mod.rs index 23273162cf..759766e3f2 100644 --- a/crates/libafl_asan/src/hooks/munmap/mod.rs +++ b/crates/libafl_asan/src/hooks/munmap/mod.rs @@ -1,5 +1,5 @@ #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] pub mod linux; diff --git a/crates/libafl_asan/src/hooks/read/mod.rs b/crates/libafl_asan/src/hooks/read/mod.rs index 23273162cf..759766e3f2 100644 --- a/crates/libafl_asan/src/hooks/read/mod.rs +++ b/crates/libafl_asan/src/hooks/read/mod.rs @@ -1,5 +1,5 @@ #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] pub mod linux; diff --git a/crates/libafl_asan/src/hooks/write/mod.rs b/crates/libafl_asan/src/hooks/write/mod.rs index 23273162cf..759766e3f2 100644 --- a/crates/libafl_asan/src/hooks/write/mod.rs +++ b/crates/libafl_asan/src/hooks/write/mod.rs @@ -1,5 +1,5 @@ #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] pub mod linux; diff --git a/crates/libafl_asan/src/host/mod.rs b/crates/libafl_asan/src/host/mod.rs index e8e7d4e967..6fb3026f18 100644 --- a/crates/libafl_asan/src/host/mod.rs +++ b/crates/libafl_asan/src/host/mod.rs @@ -11,7 +11,7 @@ use crate::{GuestAddr, shadow::PoisonType}; #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux"))] +#[cfg(all(feature = "syscalls", target_os = "linux"))] pub mod linux; #[repr(usize)] diff --git a/crates/libafl_asan/src/logger/mod.rs b/crates/libafl_asan/src/logger/mod.rs index 87657259f8..cd2fe58758 100644 --- a/crates/libafl_asan/src/logger/mod.rs +++ b/crates/libafl_asan/src/logger/mod.rs @@ -5,7 +5,7 @@ #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux"))] +#[cfg(all(feature = "syscalls", target_os = "linux"))] pub mod linux; use core::ffi::{CStr, c_char}; diff --git a/crates/libafl_asan/src/mem.rs b/crates/libafl_asan/src/mem.rs index f4dc92deff..9d2d8d7d4e 100644 --- a/crates/libafl_asan/src/mem.rs +++ b/crates/libafl_asan/src/mem.rs @@ -7,11 +7,11 @@ use crate::allocator::backend::dlmalloc::DlmallocBackend; #[cfg(all( feature = "global_allocator", - feature = "linux", + feature = "syscalls", target_os = "linux", not(feature = "libc") ))] -type Mmap = crate::mmap::linux::LinuxMmap; +type Mmap = crate::mmap::linux::MmapRegion; #[cfg(all(feature = "global_allocator", feature = "libc",))] type Mmap = crate::mmap::libc::LibcMmap< diff --git a/crates/libafl_asan/src/mmap/mod.rs b/crates/libafl_asan/src/mmap/mod.rs index 1f9dd2a2bc..466af5759a 100644 --- a/crates/libafl_asan/src/mmap/mod.rs +++ b/crates/libafl_asan/src/mmap/mod.rs @@ -11,8 +11,8 @@ use crate::GuestAddr; #[cfg(feature = "libc")] pub mod libc; -#[cfg(all(feature = "linux", target_os = "linux"))] -pub mod linux; +#[cfg(all(feature = "syscalls", unix))] +pub mod unix; bitflags! { #[derive(PartialEq, Eq)] diff --git a/crates/libafl_asan/src/mmap/linux.rs b/crates/libafl_asan/src/mmap/unix.rs similarity index 73% rename from crates/libafl_asan/src/mmap/linux.rs rename to crates/libafl_asan/src/mmap/unix.rs index 0c515ec3b2..d8126fa6ad 100644 --- a/crates/libafl_asan/src/mmap/linux.rs +++ b/crates/libafl_asan/src/mmap/unix.rs @@ -1,6 +1,6 @@ //! # linux //! This implementation of `Mmap` uses the `rustix` crate to make direct -//! `syscalls` to allocate pages and therefore whilst Linux specific, does not +//! `syscalls` to allocate pages and therefore whilst Unix specific, does not //! introduce a dependency on the `libc` library and is therefore suited for //! targets where `libc` is statically linked. use core::{ @@ -10,9 +10,11 @@ use core::{ }; use log::trace; +#[cfg(target_os = "linux")] +use rustix::{Advice, madvise}; use rustix::{ io::Errno, - mm::{Advice, MapFlags, MprotectFlags, ProtFlags, madvise, mmap_anonymous, mprotect, munmap}, + mm::{MapFlags, MprotectFlags, ProtFlags, mmap_anonymous, mprotect, munmap}, }; use thiserror::Error; @@ -22,13 +24,13 @@ use crate::{ }; #[derive(Ord, PartialOrd, PartialEq, Eq, Debug)] -pub struct LinuxMmap { +pub struct MmapRegion { addr: GuestAddr, len: usize, } -impl Mmap for LinuxMmap { - type Error = LinuxMapError; +impl Mmap for MmapRegion { + type Error = MmapError; fn map(len: usize) -> Result { unsafe { let addr = mmap_anonymous( @@ -37,25 +39,26 @@ impl Mmap for LinuxMmap { ProtFlags::READ | ProtFlags::WRITE, MapFlags::PRIVATE | MapFlags::NORESERVE, ) - .map_err(|errno| LinuxMapError::FailedToMap(len, errno))? + .map_err(|errno| MmapError::FailedToMap(len, errno))? as GuestAddr; trace!("Mapped: {:#x}-{:#x}", addr, addr + len); Ok(Self { addr, len }) } } - fn map_at(addr: GuestAddr, len: usize) -> Result { + fn map_at(addr: GuestAddr, len: usize) -> Result { + let flags = MapFlags::PRIVATE | MapFlags::FIXED | MapFlags::NORESERVE; + #[cfg(target_os = "linux")] + let flags = flags | MapFlags::FIXED_NOREPLACE; + unsafe { mmap_anonymous( addr as *mut c_void, len, ProtFlags::READ | ProtFlags::WRITE, - MapFlags::PRIVATE - | MapFlags::FIXED - | MapFlags::FIXED_NOREPLACE - | MapFlags::NORESERVE, + flags, ) - .map_err(|errno| LinuxMapError::FailedToMapAt(addr, len, errno))?; + .map_err(|errno| MmapError::FailedToMapAt(addr, len, errno))?; trace!("Mapped: {:#x}-{:#x}", addr, addr + len); }; Ok(Self { addr, len }) @@ -73,23 +76,29 @@ impl Mmap for LinuxMmap { trace!("protect - addr: {addr:#x}, len: {len:#x}, prot: {prot:#x}",); unsafe { mprotect(addr as *mut c_void, len, MprotectFlags::from(&prot)) - .map_err(|errno| LinuxMapError::FailedToMprotect(addr, len, prot, errno)) + .map_err(|errno| MmapError::FailedToMprotect(addr, len, prot, errno)) } } fn huge_pages(addr: GuestAddr, len: usize) -> Result<(), Self::Error> { trace!("huge_pages - addr: {addr:#x}, len: {len:#x}"); + #[cfg(not(target_os = "linux"))] + unimplemented!(); + #[cfg(target_os = "linux")] unsafe { madvise(addr as *mut c_void, len, Advice::LinuxHugepage) - .map_err(|errno| LinuxMapError::FailedToMadviseHugePage(addr, len, errno)) + .map_err(|errno| MmapError::FailedToMadviseHugePage(addr, len, errno)) } } fn dont_dump(addr: GuestAddr, len: usize) -> Result<(), Self::Error> { trace!("dont_dump - addr: {addr:#x}, len: {len:#x}"); + #[cfg(not(target_os = "linux"))] + unimplemented!(); + #[cfg(target_os = "linux")] unsafe { madvise(addr as *mut c_void, len, Advice::LinuxDontDump) - .map_err(|errno| LinuxMapError::FailedToMadviseDontDump(addr, len, errno)) + .map_err(|errno| MmapError::FailedToMadviseDontDump(addr, len, errno)) } } } @@ -110,7 +119,7 @@ impl From<&MmapProt> for MprotectFlags { } } -impl Drop for LinuxMmap { +impl Drop for MmapRegion { fn drop(&mut self) { unsafe { munmap(self.addr as *mut c_void, self.len).unwrap(); @@ -120,7 +129,7 @@ impl Drop for LinuxMmap { } #[derive(Error, Debug, PartialEq)] -pub enum LinuxMapError { +pub enum MmapError { #[error("Failed to map - len: {0}, errno: {1}")] FailedToMap(usize, Errno), #[error("Failed to map: {0}, len: {1}, errno: {2}")] diff --git a/crates/libafl_asan/src/test.rs b/crates/libafl_asan/src/test.rs index 33f1f03e21..28042c7aa0 100644 --- a/crates/libafl_asan/src/test.rs +++ b/crates/libafl_asan/src/test.rs @@ -24,8 +24,8 @@ type TestSyms = crate::symbols::nop::NopSymbols; #[cfg(feature = "libc")] type TestSyms = crate::symbols::dlsym::DlSymSymbols; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] -type TestMap = crate::mmap::linux::LinuxMmap; +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] +type TestMap = crate::mmap::linux::MmapRegion; #[cfg(feature = "libc")] type TestMap = crate::mmap::libc::LibcMmap; @@ -34,7 +34,7 @@ type TestMap = crate::mmap::libc::LibcMmap; type TestHost = crate::host::libc::LibcHost; #[cfg(all( - feature = "linux", + feature = "syscalls", target_os = "linux", not(feature = "libc"), not(feature = "guest"), @@ -57,7 +57,7 @@ type TestShadow = crate::shadow::host::HostShadow; #[cfg(feature = "libc")] use crate::logger::libc::LibcLogger; -#[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] +#[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] use crate::logger::linux::LinuxLogger; pub type TestFrontend = DefaultFrontend, TestShadow, TestTracking>; @@ -65,7 +65,7 @@ pub type TestFrontend = DefaultFrontend, TestShadow, Te const PAGE_SIZE: usize = 4096; static FRONTEND: Lazy> = Lazy::new(|| { - #[cfg(all(feature = "linux", target_os = "linux", not(feature = "libc")))] + #[cfg(all(feature = "syscalls", target_os = "linux", not(feature = "libc")))] LinuxLogger::initialize(Level::Info); #[cfg(feature = "libc")] LibcLogger::initialize::(Level::Info); diff --git a/crates/libafl_asan/tests/default_frontend.rs b/crates/libafl_asan/tests/default_frontend.rs index e9976b3fd9..1572fb7a81 100644 --- a/crates/libafl_asan/tests/default_frontend.rs +++ b/crates/libafl_asan/tests/default_frontend.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, feature = "linux", target_os = "linux", feature = "dlmalloc"))] +#[cfg(all(test, feature = "syscalls", target_os = "linux", feature = "dlmalloc"))] mod tests { use libafl_asan::{ @@ -6,7 +6,7 @@ mod tests { backend::dlmalloc::DlmallocBackend, frontend::{AllocatorFrontend, default::DefaultFrontend}, }, - mmap::linux::LinuxMmap, + mmap::linux::MmapRegion, shadow::{ Shadow, guest::{DefaultShadowLayout, GuestShadow}, @@ -20,8 +20,8 @@ mod tests { static INIT_ONCE: Lazy> = Lazy::new(|| { Mutex::new({ env_logger::init(); - let backend = DlmallocBackend::::new(PAGE_SIZE); - let shadow = GuestShadow::::new().unwrap(); + let backend = DlmallocBackend::::new(PAGE_SIZE); + let shadow = GuestShadow::::new().unwrap(); let tracking = GuestTracking::new().unwrap(); DF::new( backend, @@ -35,8 +35,8 @@ mod tests { }); type DF = DefaultFrontend< - DlmallocBackend, - GuestShadow, + DlmallocBackend, + GuestShadow, GuestTracking, >; diff --git a/crates/libafl_asan/tests/default_frontend_mock.rs b/crates/libafl_asan/tests/default_frontend_mock.rs index 552036ce24..21682fbea7 100644 --- a/crates/libafl_asan/tests/default_frontend_mock.rs +++ b/crates/libafl_asan/tests/default_frontend_mock.rs @@ -1,13 +1,13 @@ extern crate alloc; -#[cfg(all(test, feature = "linux", target_os = "linux"))] +#[cfg(all(test, feature = "syscalls", target_os = "linux"))] mod tests { use alloc::alloc::{GlobalAlloc, Layout}; use libafl_asan::{ GuestAddr, allocator::frontend::{AllocatorFrontend, default::DefaultFrontend}, - mmap::{Mmap, linux::LinuxMmap}, + mmap::{Mmap, linux::MmapRegion}, shadow::{ Shadow, guest::{DefaultShadowLayout, GuestShadow}, @@ -52,7 +52,7 @@ mod tests { Mutex::new({ env_logger::init(); let backend = MockBackend::new(); - let shadow = GuestShadow::::new().unwrap(); + let shadow = GuestShadow::::new().unwrap(); let tracking = GuestTracking::new().unwrap(); DF::new( backend, @@ -65,10 +65,10 @@ mod tests { }) }); - static MAP: Lazy = Lazy::new(|| LinuxMmap::map(MAX_ADDR).unwrap()); + static MAP: Lazy = Lazy::new(|| MmapRegion::map(MAX_ADDR).unwrap()); type DF = - DefaultFrontend, GuestTracking>; + DefaultFrontend, GuestTracking>; fn frontend() -> MutexGuard<'static, DF> { INIT_ONCE.lock() diff --git a/crates/libafl_asan/tests/dlmalloc_backend.rs b/crates/libafl_asan/tests/dlmalloc_backend.rs index 414558ba4d..3a5d1c2659 100644 --- a/crates/libafl_asan/tests/dlmalloc_backend.rs +++ b/crates/libafl_asan/tests/dlmalloc_backend.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, feature = "linux", target_os = "linux", feature = "dlmalloc"))] +#[cfg(all(test, feature = "syscalls", target_os = "linux", feature = "dlmalloc"))] mod tests { use std::{ @@ -6,7 +6,7 @@ mod tests { sync::Mutex, }; - use libafl_asan::{allocator::backend::dlmalloc::DlmallocBackend, mmap::linux::LinuxMmap}; + use libafl_asan::{allocator::backend::dlmalloc::DlmallocBackend, mmap::linux::MmapRegion}; use spin::Lazy; static INIT_ONCE: Lazy> = Lazy::new(|| { @@ -18,9 +18,9 @@ mod tests { const PAGE_SIZE: usize = 4096; - fn allocator() -> DlmallocBackend { + fn allocator() -> DlmallocBackend { drop(INIT_ONCE.lock().unwrap()); - DlmallocBackend::::new(PAGE_SIZE) + DlmallocBackend::::new(PAGE_SIZE) } #[test] diff --git a/crates/libafl_asan/tests/hooks_read_linux.rs b/crates/libafl_asan/tests/hooks_read_linux.rs index 5b6ce54e7d..3c4d74daa9 100644 --- a/crates/libafl_asan/tests/hooks_read_linux.rs +++ b/crates/libafl_asan/tests/hooks_read_linux.rs @@ -1,7 +1,7 @@ #[cfg(all( test, feature = "hooks", - feature = "linux", + feature = "syscalls", target_os = "linux", not(feature = "libc") ))] diff --git a/crates/libafl_asan/tests/hooks_write_linux.rs b/crates/libafl_asan/tests/hooks_write_linux.rs index 4d31937f11..abda1ec9f1 100644 --- a/crates/libafl_asan/tests/hooks_write_linux.rs +++ b/crates/libafl_asan/tests/hooks_write_linux.rs @@ -1,7 +1,7 @@ #[cfg(all( test, feature = "hooks", - feature = "linux", + feature = "syscalls", target_os = "linux", not(feature = "libc") ))] diff --git a/crates/libafl_asan/tests/host.rs b/crates/libafl_asan/tests/host.rs index d7cbbca271..ce5a6baabd 100644 --- a/crates/libafl_asan/tests/host.rs +++ b/crates/libafl_asan/tests/host.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, feature = "host", feature = "linux", target_os = "linux"))] +#[cfg(all(test, feature = "host", feature = "syscalls", target_os = "linux"))] mod tests { use libafl_asan::host::linux::LinuxHost; diff --git a/crates/libafl_asan/tests/linux_env.rs b/crates/libafl_asan/tests/linux_env.rs index aa711b9436..5ed099d01a 100644 --- a/crates/libafl_asan/tests/linux_env.rs +++ b/crates/libafl_asan/tests/linux_env.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, feature = "linux", target_os = "linux"))] +#[cfg(all(test, feature = "syscalls", target_os = "linux"))] mod tests { use libafl_asan::{env::Env, file::linux::LinuxFileReader}; #[test] diff --git a/crates/libafl_asan/tests/linux_map_reader.rs b/crates/libafl_asan/tests/linux_map_reader.rs index a9f4a3aa75..c50dc1e0b5 100644 --- a/crates/libafl_asan/tests/linux_map_reader.rs +++ b/crates/libafl_asan/tests/linux_map_reader.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, feature = "linux", target_os = "linux"))] +#[cfg(all(test, feature = "syscalls", target_os = "linux"))] mod tests { use itertools::Itertools; use libafl_asan::{ diff --git a/crates/libafl_qemu/libafl_qemu_asan/README.md b/crates/libafl_qemu/libafl_qemu_asan/README.md index 64cf6aef14..f09ec6fb01 100644 --- a/crates/libafl_qemu/libafl_qemu_asan/README.md +++ b/crates/libafl_qemu/libafl_qemu_asan/README.md @@ -28,7 +28,7 @@ and combining alternative implementations of the various key components. - `host` - Enable support for shadow memory and tracking in the host - `libc` - Enable use of `LibcMmap` to support creation of mappings using `libc` -- `linux` - Enable use of `LinuxMmap` to support creation of mappings and +- `linux` - Enable use of `MmapRegion` to support creation of mappings and host interaction using `rustix`. - `std` - Disable the magic used to support `no_std` environments diff --git a/crates/libafl_qemu/libafl_qemu_asan/libafl_qemu_asan_nolibc/src/lib.rs b/crates/libafl_qemu/libafl_qemu_asan/libafl_qemu_asan_nolibc/src/lib.rs index 80ed1c0f2e..9c5953f978 100644 --- a/crates/libafl_qemu/libafl_qemu_asan/libafl_qemu_asan_nolibc/src/lib.rs +++ b/crates/libafl_qemu/libafl_qemu_asan/libafl_qemu_asan_nolibc/src/lib.rs @@ -12,7 +12,7 @@ use libafl_asan::{ env::Env, file::linux::LinuxFileReader, logger::linux::LinuxLogger, - mmap::linux::LinuxMmap, + mmap::linux::MmapRegion, shadow::{ Shadow, guest::{DefaultShadowLayout, GuestShadow}, @@ -24,8 +24,8 @@ use log::{Level, info, trace}; use spin::{Lazy, Mutex}; pub type ZasanFrontend = DefaultFrontend< - DlmallocBackend, - GuestShadow, + DlmallocBackend, + GuestShadow, GuestFastTracking, >; @@ -42,8 +42,8 @@ static FRONTEND: Lazy> = Lazy::new(|| { .unwrap_or(Level::Warn); LinuxLogger::initialize(level); info!("Zasan initializing..."); - let backend = DlmallocBackend::::new(PAGE_SIZE); - let shadow = GuestShadow::::new().unwrap(); + let backend = DlmallocBackend::::new(PAGE_SIZE); + let shadow = GuestShadow::::new().unwrap(); let tracking = GuestFastTracking::new().unwrap(); let frontend = ZasanFrontend::new( backend, From 907108fafa5357d1d3c8103945215294603f1d3a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 20 Aug 2025 08:41:47 +0200 Subject: [PATCH 2/3] Fixing ASan for MacOS --- crates/libafl_asan/src/file/libc.rs | 30 +---------------------- crates/libafl_asan/src/lib.rs | 14 +++++------ crates/libafl_asan/src/maps/libc.rs | 34 +++------------------------ crates/libafl_asan/src/mmap/libc.rs | 22 +++-------------- crates/libafl_asan/src/symbols/mod.rs | 32 ++++++++++++++++++++++++- 5 files changed, 45 insertions(+), 87 deletions(-) diff --git a/crates/libafl_asan/src/file/libc.rs b/crates/libafl_asan/src/file/libc.rs index 00bab2cf81..8b2ef68eea 100644 --- a/crates/libafl_asan/src/file/libc.rs +++ b/crates/libafl_asan/src/file/libc.rs @@ -38,18 +38,9 @@ impl Function for FunctionRead { type Func = unsafe extern "C" fn(c_int, *mut c_char, size_t) -> ssize_t; } -#[derive(Debug)] -struct FunctionErrnoLocation; - -impl Function for FunctionErrnoLocation { - const NAME: &CStr = c"__errno_location"; - type Func = unsafe extern "C" fn() -> *mut c_int; -} - static OPEN_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static CLOSE_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static READ_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); -static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); #[derive(Debug)] pub struct LibcFileReader { @@ -84,25 +75,6 @@ impl LibcFileReader { FunctionRead::as_ptr(addr).map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; Ok(f) } - - fn get_errno_location() - -> Result<::Func, LibcFileReaderError> { - let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { - S::lookup(FunctionErrnoLocation::NAME) - .map_err(|e| LibcFileReaderError::FailedToFindSymbol(e)) - })?; - let f = FunctionErrnoLocation::as_ptr(addr) - .map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; - Ok(f) - } - - fn errno() -> Result> { - unsafe { asan_swap(false) }; - let errno_location = Self::get_errno_location()?; - unsafe { asan_swap(true) }; - let errno = unsafe { *errno_location() }; - Ok(errno) - } } impl FileReader for LibcFileReader { @@ -113,7 +85,7 @@ impl FileReader for LibcFileReader { let fd = unsafe { fn_open(path.as_ptr() as *const c_char, O_NONBLOCK | O_RDONLY, 0) }; unsafe { asan_swap(true) }; if fd < 0 { - let errno = Self::errno().unwrap(); + let errno = errno().unwrap(); return Err(LibcFileReaderError::FailedToOpen(errno)); } Ok(LibcFileReader { diff --git a/crates/libafl_asan/src/lib.rs b/crates/libafl_asan/src/lib.rs index cd416fcf47..4c7249222b 100644 --- a/crates/libafl_asan/src/lib.rs +++ b/crates/libafl_asan/src/lib.rs @@ -121,6 +121,13 @@ use core::mem::transmute; use ::core::ffi::{c_char, c_void}; use nostd_printf::vsnprintf; +/* + * vsnprintf is only called from our C code, but we need to tell Rust that we + * still need it even though it isn't referenced from rust. + */ +#[used] +static LINK_VSNPRINTF: unsafe extern "C" fn() = unsafe { transmute(vsnprintf as *const ()) }; + #[cfg(not(feature = "test"))] unsafe extern "C" { pub fn asan_load(addr: *const c_void, size: usize); @@ -136,10 +143,3 @@ unsafe extern "C" { pub fn asan_panic(msg: *const c_char) -> !; pub fn asan_swap(enabled: bool); } - -/* - * vsnprintf is only called from our C code, but we need to tell Rust that we - * still need it even though it isn't referenced from rust. - */ -#[used] -static LINK_VSNPRINTF: unsafe extern "C" fn() = unsafe { transmute(vsnprintf as *const ()) }; diff --git a/crates/libafl_asan/src/maps/libc.rs b/crates/libafl_asan/src/maps/libc.rs index 6ac82d3171..8eeb41076b 100644 --- a/crates/libafl_asan/src/maps/libc.rs +++ b/crates/libafl_asan/src/maps/libc.rs @@ -40,18 +40,9 @@ impl Function for FunctionRead { const NAME: &'static CStr = c"read"; } -#[derive(Debug)] -struct FunctionErrnoLocation; - -impl Function for FunctionErrnoLocation { - type Func = unsafe extern "C" fn() -> *mut c_int; - const NAME: &'static CStr = c"__errno_location"; -} - static OPEN_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static CLOSE_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static READ_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); -static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); #[derive(Debug)] pub struct LibcMapReader { @@ -87,25 +78,6 @@ impl LibcMapReader { FunctionRead::as_ptr(addr).map_err(|e| LibcMapReaderError::InvalidPointerType(e))?; Ok(f) } - - fn get_errno_location() - -> Result<::Func, LibcMapReaderError> { - let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { - S::lookup(FunctionErrnoLocation::NAME) - .map_err(|e| LibcMapReaderError::FailedToFindSymbol(e)) - })?; - let f = FunctionErrnoLocation::as_ptr(addr) - .map_err(|e| LibcMapReaderError::InvalidPointerType(e))?; - Ok(f) - } - - fn errno() -> Result> { - unsafe { asan_swap(false) }; - let errno_location = Self::get_errno_location()?; - unsafe { asan_swap(true) }; - let errno = unsafe { *errno_location() }; - Ok(errno) - } } impl MapReader for LibcMapReader { @@ -123,7 +95,7 @@ impl MapReader for LibcMapReader { }; unsafe { asan_swap(true) }; if fd < 0 { - let errno = Self::errno().unwrap(); + let errno = errno(); return Err(LibcMapReaderError::FailedToOpen(errno)); } Ok(LibcMapReader { @@ -138,7 +110,7 @@ impl MapReader for LibcMapReader { let ret = unsafe { fn_read(self.fd, buf.as_mut_ptr() as *mut c_char, buf.len()) }; unsafe { asan_swap(true) }; if ret < 0 { - let errno = Self::errno().unwrap(); + let errno = Self::errno(); return Err(LibcMapReaderError::FailedToRead(self.fd, errno)); } Ok(ret as usize) @@ -152,7 +124,7 @@ impl Drop for LibcMapReader { let ret = unsafe { fn_close(self.fd) }; unsafe { asan_swap(true) }; if ret < 0 { - let errno = Self::errno().unwrap(); + let errno = errno(); panic!("Failed to close: {}, Errno: {}", self.fd, errno); } trace!("Closed fd: {}", self.fd); diff --git a/crates/libafl_asan/src/mmap/libc.rs b/crates/libafl_asan/src/mmap/libc.rs index bf88b1d12c..3615b6e3ca 100644 --- a/crates/libafl_asan/src/mmap/libc.rs +++ b/crates/libafl_asan/src/mmap/libc.rs @@ -48,9 +48,11 @@ impl Function for FunctionMprotect { const NAME: &'static CStr = c"mprotect"; } +#[cfg(target_os = "linux")] #[derive(Debug)] struct FunctionErrnoLocation; +#[cfg(target_os = "linux")] impl Function for FunctionErrnoLocation { type Func = unsafe extern "C" fn() -> *mut c_int; const NAME: &'static CStr = c"__errno_location"; @@ -94,7 +96,6 @@ impl Eq for LibcMmap {} static MMAP_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static MUNMAP_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static MPROTECT_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); -static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static MADVISE_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); impl LibcMmap { @@ -122,15 +123,6 @@ impl LibcMmap { Ok(f) } - fn get_errno_location() -> Result<::Func, LibcMapError> { - let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { - S::lookup(FunctionErrnoLocation::NAME).map_err(|e| LibcMapError::FailedToFindSymbol(e)) - })?; - let f = - FunctionErrnoLocation::as_ptr(addr).map_err(|e| LibcMapError::InvalidPointerType(e))?; - Ok(f) - } - pub fn get_madvise() -> Result<::Func, LibcMapError> { let addr = MADVISE_ADDR.try_get_or_insert_with(|| { S::lookup(FunctionMadvise::NAME).map_err(|e| LibcMapError::FailedToFindSymbol(e)) @@ -138,14 +130,6 @@ impl LibcMmap { let f = FunctionMadvise::as_ptr(addr).map_err(|e| LibcMapError::InvalidPointerType(e))?; Ok(f) } - - fn errno() -> Result> { - unsafe { asan_swap(false) }; - let errno_location = Self::get_errno_location()?; - unsafe { asan_swap(true) }; - let errno = unsafe { *errno_location() }; - Ok(errno) - } } impl Mmap for LibcMmap { @@ -166,7 +150,7 @@ impl Mmap for LibcMmap { }; unsafe { asan_swap(true) }; if map == libc::MAP_FAILED { - let errno = Self::errno()?; + let errno = errno(); Err(LibcMapError::FailedToMap(len, errno)) } else { let addr = map as GuestAddr; diff --git a/crates/libafl_asan/src/symbols/mod.rs b/crates/libafl_asan/src/symbols/mod.rs index 4a9d3285e7..90011e2489 100644 --- a/crates/libafl_asan/src/symbols/mod.rs +++ b/crates/libafl_asan/src/symbols/mod.rs @@ -5,7 +5,7 @@ //! linked use alloc::fmt::Debug; use core::{ - ffi::{CStr, c_char, c_void}, + ffi::{CStr, c_char, c_int, c_void}, ptr::null_mut, sync::atomic::{AtomicPtr, Ordering}, }; @@ -19,6 +19,8 @@ pub mod dlsym; pub mod nop; +static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); + pub struct AtomicGuestAddr { addr: AtomicPtr, } @@ -120,3 +122,31 @@ pub enum FunctionPointerError { #[error("Patched address: {0}")] PatchedAddress(GuestAddr), } + +#[derive(Debug)] +struct FunctionErrnoLocation; + +impl Function for FunctionErrnoLocation { + #[cfg(target_os = "linux")] + const NAME: &CStr = c"__errno_location"; + #[cfg(target_vendor = "apple")] + const NAME: &CStr = c"___error"; + type Func = unsafe extern "C" fn() -> *mut c_int; +} + +fn get_errno_location() -> Result<::Func, ::Error> { + let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { + S::lookup(FunctionErrnoLocation::NAME) + })?; + let f = FunctionErrnoLocation::as_ptr(addr) + .map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; + Ok(f) +} + +pub fn errno() -> Result> { + unsafe { asan_swap(false) }; + let errno_location = get_errno_location()?; + unsafe { asan_swap(true) }; + let errno = unsafe { *errno_location() }; + Ok(errno) +} From 5e45597842dc05f6bfa422562644fd572ea0949d Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 21 Aug 2025 01:57:32 +0200 Subject: [PATCH 3/3] Make this thing build on MacOS --- .../src/allocator/frontend/default.rs | 8 +-- crates/libafl_asan/src/file/libc.rs | 30 ++++++++- crates/libafl_asan/src/hooks/aligned_alloc.rs | 2 +- crates/libafl_asan/src/hooks/memalign.rs | 2 +- .../libafl_asan/src/hooks/posix_memalign.rs | 2 +- crates/libafl_asan/src/maps/libc.rs | 37 ++++++++++- crates/libafl_asan/src/mmap/libc.rs | 61 ++++++++++++++++++- crates/libafl_asan/src/shadow/guest.rs | 15 +++-- crates/libafl_asan/src/symbols/mod.rs | 32 +--------- .../libafl_asan/tests/guest_shadow_example.rs | 6 +- utils/gdb_qemu/gdb_qemu/src/errno.rs | 16 +++++ 11 files changed, 158 insertions(+), 53 deletions(-) diff --git a/crates/libafl_asan/src/allocator/frontend/default.rs b/crates/libafl_asan/src/allocator/frontend/default.rs index 7ed14904b0..b80cb7cf7c 100644 --- a/crates/libafl_asan/src/allocator/frontend/default.rs +++ b/crates/libafl_asan/src/allocator/frontend/default.rs @@ -54,12 +54,12 @@ impl AllocatorFrontend for Defaul fn alloc(&mut self, len: usize, align: usize) -> Result { debug!("alloc - len: {len:#x}, align: {align:#x}"); - if align % size_of::() != 0 { + if !align.is_multiple_of(size_of::()) { Err(DefaultFrontendError::InvalidAlignment(align))?; } let size = len + align; let allocated_size = (self.red_zone_size * 2) + Self::align_up(size); - assert!(allocated_size % Self::ALLOC_ALIGN_SIZE == 0); + assert!(allocated_size.is_multiple_of(Self::ALLOC_ALIGN_SIZE)); let ptr = unsafe { self.backend.alloc( Layout::from_size_align(allocated_size, Self::ALLOC_ALIGN_SIZE) @@ -84,7 +84,7 @@ impl AllocatorFrontend for Defaul } else { rz + align - (rz % align) }; - assert!(align == 0 || data % align == 0); + assert!(align == 0 || data.is_multiple_of(align)); assert!(data + len <= orig + allocated_size); self.allocations.insert( @@ -171,7 +171,7 @@ impl DefaultFrontend { red_zone_size: usize, quarantine_size: usize, ) -> Result, DefaultFrontendError> { - if red_zone_size % Self::ALLOC_ALIGN_SIZE != 0 { + if !red_zone_size.is_multiple_of(Self::ALLOC_ALIGN_SIZE) { Err(DefaultFrontendError::InvalidRedZoneSize(red_zone_size))?; } Ok(DefaultFrontend:: { diff --git a/crates/libafl_asan/src/file/libc.rs b/crates/libafl_asan/src/file/libc.rs index 8b2ef68eea..00bab2cf81 100644 --- a/crates/libafl_asan/src/file/libc.rs +++ b/crates/libafl_asan/src/file/libc.rs @@ -38,9 +38,18 @@ impl Function for FunctionRead { type Func = unsafe extern "C" fn(c_int, *mut c_char, size_t) -> ssize_t; } +#[derive(Debug)] +struct FunctionErrnoLocation; + +impl Function for FunctionErrnoLocation { + const NAME: &CStr = c"__errno_location"; + type Func = unsafe extern "C" fn() -> *mut c_int; +} + static OPEN_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static CLOSE_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static READ_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); +static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); #[derive(Debug)] pub struct LibcFileReader { @@ -75,6 +84,25 @@ impl LibcFileReader { FunctionRead::as_ptr(addr).map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; Ok(f) } + + fn get_errno_location() + -> Result<::Func, LibcFileReaderError> { + let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { + S::lookup(FunctionErrnoLocation::NAME) + .map_err(|e| LibcFileReaderError::FailedToFindSymbol(e)) + })?; + let f = FunctionErrnoLocation::as_ptr(addr) + .map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; + Ok(f) + } + + fn errno() -> Result> { + unsafe { asan_swap(false) }; + let errno_location = Self::get_errno_location()?; + unsafe { asan_swap(true) }; + let errno = unsafe { *errno_location() }; + Ok(errno) + } } impl FileReader for LibcFileReader { @@ -85,7 +113,7 @@ impl FileReader for LibcFileReader { let fd = unsafe { fn_open(path.as_ptr() as *const c_char, O_NONBLOCK | O_RDONLY, 0) }; unsafe { asan_swap(true) }; if fd < 0 { - let errno = errno().unwrap(); + let errno = Self::errno().unwrap(); return Err(LibcFileReaderError::FailedToOpen(errno)); } Ok(LibcFileReader { diff --git a/crates/libafl_asan/src/hooks/aligned_alloc.rs b/crates/libafl_asan/src/hooks/aligned_alloc.rs index a97df6a822..f99ccb1f28 100644 --- a/crates/libafl_asan/src/hooks/aligned_alloc.rs +++ b/crates/libafl_asan/src/hooks/aligned_alloc.rs @@ -19,7 +19,7 @@ pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut n != 0 && (n & (n - 1)) == 0 } - if alignment % size_of::() != 0 { + if !alignment.is_multiple_of(size_of::()) { asan_panic( c"aligned_alloc - alignment is not a multiple of pointer size".as_ptr() as *const c_char, diff --git a/crates/libafl_asan/src/hooks/memalign.rs b/crates/libafl_asan/src/hooks/memalign.rs index bc22b7b3d1..a521f2ff27 100644 --- a/crates/libafl_asan/src/hooks/memalign.rs +++ b/crates/libafl_asan/src/hooks/memalign.rs @@ -18,7 +18,7 @@ pub unsafe extern "C" fn memalign(align: size_t, size: size_t) -> *mut c_void { n != 0 && (n & (n - 1)) == 0 } - if align % size_of::() != 0 { + if !align.is_multiple_of(size_of::()) { asan_panic( c"memalign - align is not a multiple of pointer size".as_ptr() as *const c_char, ); diff --git a/crates/libafl_asan/src/hooks/posix_memalign.rs b/crates/libafl_asan/src/hooks/posix_memalign.rs index ceaecae42a..f9fa54e178 100644 --- a/crates/libafl_asan/src/hooks/posix_memalign.rs +++ b/crates/libafl_asan/src/hooks/posix_memalign.rs @@ -27,7 +27,7 @@ pub unsafe extern "C" fn posix_memalign( n != 0 && (n & (n - 1)) == 0 } - if align % size_of::() != 0 { + if !align.is_multiple_of(size_of::()) { asan_panic( c"posix_memalign - align is not a multiple of pointer size".as_ptr() as *const c_char, diff --git a/crates/libafl_asan/src/maps/libc.rs b/crates/libafl_asan/src/maps/libc.rs index 8eeb41076b..33da13242d 100644 --- a/crates/libafl_asan/src/maps/libc.rs +++ b/crates/libafl_asan/src/maps/libc.rs @@ -40,9 +40,24 @@ impl Function for FunctionRead { const NAME: &'static CStr = c"read"; } +#[derive(Debug)] +struct FunctionErrnoLocation; + +#[cfg(target_os = "linux")] +impl Function for FunctionErrnoLocation { + type Func = unsafe extern "C" fn() -> *mut c_int; + const NAME: &'static CStr = c"__errno_location"; +} +#[cfg(target_vendor = "apple")] +impl Function for FunctionErrnoLocation { + type Func = unsafe extern "C" fn() -> *mut c_int; + const NAME: &'static CStr = c"__error"; +} + static OPEN_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static CLOSE_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static READ_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); +static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); #[derive(Debug)] pub struct LibcMapReader { @@ -78,6 +93,24 @@ impl LibcMapReader { FunctionRead::as_ptr(addr).map_err(|e| LibcMapReaderError::InvalidPointerType(e))?; Ok(f) } + + fn get_errno_location() -> Result<::Func, LibcMapReaderError> { + let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { + S::lookup(FunctionErrnoLocation::NAME) + .map_err(|e| LibcMapReaderError::FailedToFindSymbol(e)) + })?; + let f = FunctionErrnoLocation::as_ptr(addr) + .map_err(|e| LibcMapReaderError::InvalidPointerType(e))?; + Ok(f) + } + + fn errno() -> Result> { + unsafe { asan_swap(false) }; + let errno_location = Self::get_errno_location()?; + unsafe { asan_swap(true) }; + let errno = unsafe { *errno_location() }; + Ok(errno) + } } impl MapReader for LibcMapReader { @@ -95,7 +128,7 @@ impl MapReader for LibcMapReader { }; unsafe { asan_swap(true) }; if fd < 0 { - let errno = errno(); + let errno = Self::errno(); return Err(LibcMapReaderError::FailedToOpen(errno)); } Ok(LibcMapReader { @@ -124,7 +157,7 @@ impl Drop for LibcMapReader { let ret = unsafe { fn_close(self.fd) }; unsafe { asan_swap(true) }; if ret < 0 { - let errno = errno(); + let errno = Self::errno(); panic!("Failed to close: {}, Errno: {}", self.fd, errno); } trace!("Closed fd: {}", self.fd); diff --git a/crates/libafl_asan/src/mmap/libc.rs b/crates/libafl_asan/src/mmap/libc.rs index 3615b6e3ca..daaa9ecaba 100644 --- a/crates/libafl_asan/src/mmap/libc.rs +++ b/crates/libafl_asan/src/mmap/libc.rs @@ -10,10 +10,11 @@ use core::{ ptr::null_mut, slice::{from_raw_parts, from_raw_parts_mut}, }; +use std::borrow::Cow; #[cfg(target_os = "linux")] use libc::{MADV_DONTDUMP, MADV_HUGEPAGE}; -use libc::{PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE, off_t, size_t}; +use libc::{PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE, c_char, off_t, size_t}; use log::trace; use thiserror::Error; @@ -48,7 +49,6 @@ impl Function for FunctionMprotect { const NAME: &'static CStr = c"mprotect"; } -#[cfg(target_os = "linux")] #[derive(Debug)] struct FunctionErrnoLocation; @@ -58,6 +58,20 @@ impl Function for FunctionErrnoLocation { const NAME: &'static CStr = c"__errno_location"; } +#[cfg(target_vendor = "apple")] +impl Function for FunctionErrnoLocation { + type Func = unsafe extern "C" fn() -> *mut c_int; + const NAME: &'static CStr = c"__error"; +} + +#[derive(Debug)] +struct FunctionStrError; + +impl Function for FunctionStrError { + type Func = unsafe extern "C" fn(errnum: c_int) -> *const c_char; + const NAME: &'static CStr = c"strerror"; +} + #[derive(Debug)] pub struct FunctionMadvise; @@ -96,6 +110,8 @@ impl Eq for LibcMmap {} static MMAP_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static MUNMAP_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); static MPROTECT_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); +static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); +static STRERROR_LOCATION: AtomicGuestAddr = AtomicGuestAddr::new(); static MADVISE_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); impl LibcMmap { @@ -123,6 +139,23 @@ impl LibcMmap { Ok(f) } + fn get_errno_location() -> Result<::Func, LibcMapError> { + let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { + S::lookup(FunctionErrnoLocation::NAME).map_err(|e| LibcMapError::FailedToFindSymbol(e)) + })?; + let f = + FunctionErrnoLocation::as_ptr(addr).map_err(|e| LibcMapError::InvalidPointerType(e))?; + Ok(f) + } + + fn get_strerror() -> Result<::Func, LibcMapError> { + let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { + S::lookup(FunctionStrError::NAME).map_err(|e| LibcMapError::FailedToFindSymbol(e)) + })?; + let f = FunctionStrError::as_ptr(addr).map_err(|e| LibcMapError::InvalidPointerType(e))?; + Ok(f) + } + pub fn get_madvise() -> Result<::Func, LibcMapError> { let addr = MADVISE_ADDR.try_get_or_insert_with(|| { S::lookup(FunctionMadvise::NAME).map_err(|e| LibcMapError::FailedToFindSymbol(e)) @@ -130,6 +163,28 @@ impl LibcMmap { let f = FunctionMadvise::as_ptr(addr).map_err(|e| LibcMapError::InvalidPointerType(e))?; Ok(f) } + + fn errno() -> Result> { + unsafe { asan_swap(false) }; + let errno_location = Self::get_errno_location()?; + unsafe { asan_swap(true) }; + let errno = unsafe { *errno_location() }; + Ok(errno) + } + + fn last_error_str<'a>() -> Result, LibcMapError> { + let errno = Self::errno()?; + unsafe { asan_swap(false) }; + let strerror = Self::get_strerror()?; + // # Safety + // Call to strerror fn should be safe (assuming we got a pointer to the right one). + let error_cstr = unsafe { strerror(errno) }; + unsafe { asan_swap(true) }; + + // # Safety + // calling the `strerror` libc functions with the correct `errno` + Ok(unsafe { CStr::from_ptr(error_cstr).to_string_lossy() }) + } } impl Mmap for LibcMmap { @@ -150,7 +205,7 @@ impl Mmap for LibcMmap { }; unsafe { asan_swap(true) }; if map == libc::MAP_FAILED { - let errno = errno(); + let errno = Self::errno()?; Err(LibcMapError::FailedToMap(len, errno)) } else { let addr = map as GuestAddr; diff --git a/crates/libafl_asan/src/shadow/guest.rs b/crates/libafl_asan/src/shadow/guest.rs index 9b7fbc748c..94f4288525 100644 --- a/crates/libafl_asan/src/shadow/guest.rs +++ b/crates/libafl_asan/src/shadow/guest.rs @@ -266,14 +266,14 @@ impl GuestShadow { pub const HIGH_MEM_LIMIT: usize = L::HIGH_MEM_OFFSET + (L::HIGH_MEM_SIZE - 1); pub fn new() -> Result, GuestShadowError> { - trace!( + println!( "Mapping low shadow: {:#x}-{:#x}", Self::LOW_SHADOW_OFFSET, Self::LOW_SHADOW_OFFSET + Self::LOW_SHADOW_SIZE ); let lo = Self::map_shadow(Self::LOW_SHADOW_OFFSET, Self::LOW_SHADOW_SIZE) .map_err(|e| GuestShadowError::MmapError(e))?; - trace!( + println!( "Mapping high shadow: {:#x}-{:#x}", Self::HIGH_SHADOW_OFFSET, Self::HIGH_SHADOW_OFFSET + Self::HIGH_SHADOW_SIZE @@ -288,9 +288,12 @@ impl GuestShadow { } fn map_shadow(addr: GuestAddr, size: usize) -> Result { + println!("MapAt"); let m = M::map_at(addr, size)?; M::huge_pages(addr, size)?; + println!("HugePages"); M::dont_dump(addr, size)?; + println!("Don'tDump"); Ok(m) } @@ -353,8 +356,8 @@ impl GuestShadow { pub fn get_shadow(&self, addr: GuestAddr, len: usize) -> Result<&[u8], GuestShadowError> { trace!("get_shadow - addr: {addr:#x}, len: {len:#x}"); - assert!(addr % Self::ALLOC_ALIGN_SIZE == 0); - assert!(len % Self::ALLOC_ALIGN_SIZE == 0); + assert!(addr.is_multiple_of(Self::ALLOC_ALIGN_SIZE)); + assert!(len.is_multiple_of(Self::ALLOC_ALIGN_SIZE)); let shadow_addr = (addr >> Self::ALLOC_ALIGN_POW) + Self::SHADOW_OFFSET; let shadow_len = len >> Self::ALLOC_ALIGN_POW; if Self::is_low_memory(addr, len) { @@ -374,8 +377,8 @@ impl GuestShadow { len: usize, ) -> Result<&mut [u8], GuestShadowError> { trace!("get_shadow_mut - addr: {addr:#x}, len: {len:#x}"); - assert!(addr % Self::ALLOC_ALIGN_SIZE == 0); - assert!(len % Self::ALLOC_ALIGN_SIZE == 0); + assert!(addr.is_multiple_of(Self::ALLOC_ALIGN_SIZE)); + assert!(len.is_multiple_of(Self::ALLOC_ALIGN_SIZE)); let shadow_addr = (addr >> Self::ALLOC_ALIGN_POW) + Self::SHADOW_OFFSET; let aligned_len = Self::align_up(len); let shadow_len = aligned_len >> Self::ALLOC_ALIGN_POW; diff --git a/crates/libafl_asan/src/symbols/mod.rs b/crates/libafl_asan/src/symbols/mod.rs index 90011e2489..4a9d3285e7 100644 --- a/crates/libafl_asan/src/symbols/mod.rs +++ b/crates/libafl_asan/src/symbols/mod.rs @@ -5,7 +5,7 @@ //! linked use alloc::fmt::Debug; use core::{ - ffi::{CStr, c_char, c_int, c_void}, + ffi::{CStr, c_char, c_void}, ptr::null_mut, sync::atomic::{AtomicPtr, Ordering}, }; @@ -19,8 +19,6 @@ pub mod dlsym; pub mod nop; -static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); - pub struct AtomicGuestAddr { addr: AtomicPtr, } @@ -122,31 +120,3 @@ pub enum FunctionPointerError { #[error("Patched address: {0}")] PatchedAddress(GuestAddr), } - -#[derive(Debug)] -struct FunctionErrnoLocation; - -impl Function for FunctionErrnoLocation { - #[cfg(target_os = "linux")] - const NAME: &CStr = c"__errno_location"; - #[cfg(target_vendor = "apple")] - const NAME: &CStr = c"___error"; - type Func = unsafe extern "C" fn() -> *mut c_int; -} - -fn get_errno_location() -> Result<::Func, ::Error> { - let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { - S::lookup(FunctionErrnoLocation::NAME) - })?; - let f = FunctionErrnoLocation::as_ptr(addr) - .map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; - Ok(f) -} - -pub fn errno() -> Result> { - unsafe { asan_swap(false) }; - let errno_location = get_errno_location()?; - unsafe { asan_swap(true) }; - let errno = unsafe { *errno_location() }; - Ok(errno) -} diff --git a/crates/libafl_asan/tests/guest_shadow_example.rs b/crates/libafl_asan/tests/guest_shadow_example.rs index f3ad61dc33..03fa7c86a7 100644 --- a/crates/libafl_asan/tests/guest_shadow_example.rs +++ b/crates/libafl_asan/tests/guest_shadow_example.rs @@ -30,7 +30,7 @@ mod tests { #[test] fn test_poison_example1() { let mut shadow = get_shadow(); - // poison - start: 0x7fff2bffff00, len: 0x100, pioson: AsanUser + // poison - start: 0x7fff2bffff00, len: 0x100, poison: AsanUser // is_poison - start: 0x7fff2bfffc01, len: 0x300 assert_eq!( shadow.poison(0x7fff2bffff00, 0x100, PoisonType::AsanUser), @@ -42,7 +42,7 @@ mod tests { #[test] fn test_poison_example2() { let mut shadow = get_shadow(); - // poison - start: 0x7dff13ffffff, len: 0x3b9, pioson: AsanUser + // poison - start: 0x7dff13ffffff, len: 0x3b9, poison: AsanUser // is_poison - start: 0x7dff14000302, len: 0x2 assert_eq!( shadow.poison(0x7dff13ffffff, 0x3b9, PoisonType::AsanUser), @@ -54,7 +54,7 @@ mod tests { #[test] fn test_poison_example3() { let mut shadow = get_shadow(); - // poison - start: 0x7fffffffff00, len: 0x100, pioson: AsanUser + // poison - start: 0x7fffffffff00, len: 0x100, poison: AsanUser // is_poison - start: 0x7fffffffff00, len: 0xff assert_eq!( shadow.poison(0x7fffffffff00, 0x100, PoisonType::AsanUser), diff --git a/utils/gdb_qemu/gdb_qemu/src/errno.rs b/utils/gdb_qemu/gdb_qemu/src/errno.rs index 9cc0dae35e..9bd7799d54 100644 --- a/utils/gdb_qemu/gdb_qemu/src/errno.rs +++ b/utils/gdb_qemu/gdb_qemu/src/errno.rs @@ -1,5 +1,21 @@ +#[cfg(target_os = "linux")] use libc::__errno_location; +#[cfg(target_vendor= "apple")] +use libc::__error; + +#[cfg(target_os = "linux")] pub fn errno() -> i32 { unsafe { *__errno_location() } } + +#[cfg(not(any(target_os = "linux", target_vendor = "apple")))] +pub fn errno() -> i32 { + unsafe { *__error() } +} + +#[cfg(not(any(target_os = "linux", target_vendor = "apple")))] +pub fn errno() -> i32 { + // TODO: Add support for more platforms. + 0 +} \ No newline at end of file