[libafl_qemu] GuestAddr type (#501)

Guest addresses now represented by correct sized integers.

Previously u64 was used to represent guest addresses. This is great for
64-bit targets, but clunky for other architectures. This introduces a
GuestAddr type alias that is defined based on the selected emulation
architecture.

Note: This changes only the user-facing Rust interface. Before
traversing the FFI boundary, all GuestAddrs are sized back to u64.

Another Note: Guest addresses _from_ the FFI boundary are completely
trusted. Values that are too large are truncated to fit into a GuestAddr
using the `as GuestAddr` cast. This may not be ideal, as errors could be
masked. If desired and the performance is ok, a non-breaking update
could change all `as` casts to `.try_into().unwrap()` so that critical
failures in FFI are always checked.
This commit is contained in:
Evan Richter 2022-01-28 02:42:23 -06:00 committed by GitHub
parent efb5e25411
commit 4e3e31df4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 206 additions and 150 deletions

View File

@ -6,7 +6,7 @@ use crate::{
emu::{Emulator, SyscallHookResult},
executor::QemuExecutor,
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
Regs,
GuestAddr, Regs,
};
// TODO at some point, merge parts with libafl_frida
@ -231,16 +231,16 @@ impl QemuAsanHelper {
#[allow(clippy::unused_self)]
#[must_use]
pub fn is_poisoned(&self, emulator: &Emulator, addr: u64, size: usize) -> bool {
pub fn is_poisoned(&self, emulator: &Emulator, addr: GuestAddr, size: usize) -> bool {
unsafe { asan_giovese_loadN(emulator.g2h(addr), size) != 0 }
}
pub fn read_1(&mut self, emulator: &Emulator, addr: u64) {
pub fn read_1(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_load1(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
0,
addr,
addr.into(),
1,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -250,12 +250,12 @@ impl QemuAsanHelper {
}
}
pub fn read_2(&mut self, emulator: &Emulator, addr: u64) {
pub fn read_2(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_load2(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
0,
addr,
addr.into(),
2,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -265,12 +265,12 @@ impl QemuAsanHelper {
}
}
pub fn read_4(&mut self, emulator: &Emulator, addr: u64) {
pub fn read_4(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_load4(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
0,
addr,
addr.into(),
4,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -280,12 +280,12 @@ impl QemuAsanHelper {
}
}
pub fn read_8(&mut self, emulator: &Emulator, addr: u64) {
pub fn read_8(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_load8(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
0,
addr,
addr.into(),
8,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -295,12 +295,12 @@ impl QemuAsanHelper {
}
}
pub fn read_n(&mut self, emulator: &Emulator, addr: u64, size: usize) {
pub fn read_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
unsafe {
if self.enabled() && asan_giovese_loadN(emulator.g2h(addr), size) != 0 {
asan_giovese_report_and_crash(
0,
addr,
addr.into(),
size,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -310,12 +310,12 @@ impl QemuAsanHelper {
}
}
pub fn write_1(&mut self, emulator: &Emulator, addr: u64) {
pub fn write_1(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_store1(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
1,
addr,
addr.into(),
1,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -325,12 +325,12 @@ impl QemuAsanHelper {
}
}
pub fn write_2(&mut self, emulator: &Emulator, addr: u64) {
pub fn write_2(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_store2(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
1,
addr,
addr.into(),
2,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -340,12 +340,12 @@ impl QemuAsanHelper {
}
}
pub fn write_4(&mut self, emulator: &Emulator, addr: u64) {
pub fn write_4(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_store4(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
1,
addr,
addr.into(),
4,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -355,12 +355,12 @@ impl QemuAsanHelper {
}
}
pub fn write_8(&mut self, emulator: &Emulator, addr: u64) {
pub fn write_8(&mut self, emulator: &Emulator, addr: GuestAddr) {
unsafe {
if self.enabled() && asan_giovese_store8(emulator.g2h(addr)) != 0 {
asan_giovese_report_and_crash(
1,
addr,
addr.into(),
8,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -370,12 +370,12 @@ impl QemuAsanHelper {
}
}
pub fn write_n(&mut self, emulator: &Emulator, addr: u64, size: usize) {
pub fn write_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
unsafe {
if self.enabled() && asan_giovese_storeN(emulator.g2h(addr), size) != 0 {
asan_giovese_report_and_crash(
1,
addr,
addr.into(),
size,
emulator.read_reg(Regs::Pc).unwrap_or(u64::MAX),
0,
@ -386,12 +386,18 @@ impl QemuAsanHelper {
}
#[allow(clippy::unused_self)]
pub fn poison(&mut self, emulator: &Emulator, addr: u64, size: usize, poison: PoisonKind) {
pub fn poison(
&mut self,
emulator: &Emulator,
addr: GuestAddr,
size: usize,
poison: PoisonKind,
) {
unsafe { asan_giovese_poison_region(emulator.g2h(addr), size, poison.into()) };
}
#[allow(clippy::unused_self)]
pub fn unpoison(&mut self, emulator: &Emulator, addr: u64, size: usize) {
pub fn unpoison(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
unsafe { asan_giovese_unpoison_region(emulator.g2h(addr), size) };
}
@ -465,7 +471,7 @@ pub fn trace_read1_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -479,7 +485,7 @@ pub fn trace_read2_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -493,7 +499,7 @@ pub fn trace_read4_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -507,7 +513,7 @@ pub fn trace_read8_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -521,7 +527,7 @@ pub fn trace_read_n_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
size: usize,
) where
I: Input,
@ -536,7 +542,7 @@ pub fn trace_write1_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -550,7 +556,7 @@ pub fn trace_write2_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -564,7 +570,7 @@ pub fn trace_write4_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -578,7 +584,7 @@ pub fn trace_write8_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -592,7 +598,7 @@ pub fn trace_write_n_asan<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
size: usize,
) where
I: Input,
@ -626,27 +632,27 @@ where
let mut r = 0;
match QasanAction::try_from(a0).expect("Invalid QASan action number") {
QasanAction::CheckLoad => {
h.read_n(emulator, a1, a2 as usize);
h.read_n(emulator, a1 as GuestAddr, a2 as usize);
}
QasanAction::CheckStore => {
h.write_n(emulator, a1, a2 as usize);
h.write_n(emulator, a1 as GuestAddr, a2 as usize);
}
QasanAction::Poison => {
h.poison(
emulator,
a1,
a1 as GuestAddr,
a2 as usize,
PoisonKind::try_from(a3 as u8).unwrap(),
);
}
QasanAction::UserPoison => {
h.poison(emulator, a1, a2 as usize, PoisonKind::User);
h.poison(emulator, a1 as GuestAddr, a2 as usize, PoisonKind::User);
}
QasanAction::UnPoison => {
h.unpoison(emulator, a1, a2 as usize);
h.unpoison(emulator, a1 as GuestAddr, a2 as usize);
}
QasanAction::IsPoison => {
if h.is_poisoned(emulator, a1, a2 as usize) {
if h.is_poisoned(emulator, a1 as GuestAddr, a2 as usize) {
r = 1;
}
}

View File

@ -12,6 +12,16 @@ use num_traits::Num;
use std::{slice::from_raw_parts, str::from_utf8_unchecked};
use strum_macros::EnumIter;
#[cfg(not(any(feature = "x86_64", feature = "aarch64")))]
/// `GuestAddr` is u32 for 32-bit targets
pub type GuestAddr = u32;
#[cfg(any(feature = "x86_64", feature = "aarch64"))]
/// `GuestAddr` is u64 for 64-bit targets
pub type GuestAddr = u64;
pub type GuestUsize = GuestAddr;
#[cfg(feature = "python")]
use pyo3::{prelude::*, PyIterProtocol};
@ -120,9 +130,9 @@ impl SyscallHookResult {
#[repr(C)]
#[cfg_attr(feature = "python", pyclass(unsendable))]
pub struct MapInfo {
start: u64,
end: u64,
offset: u64,
start: GuestAddr,
end: GuestAddr,
offset: GuestAddr,
path: *const u8,
flags: i32,
is_priv: i32,
@ -131,17 +141,17 @@ pub struct MapInfo {
#[cfg_attr(feature = "python", pymethods)]
impl MapInfo {
#[must_use]
pub fn start(&self) -> u64 {
pub fn start(&self) -> GuestAddr {
self.start
}
#[must_use]
pub fn end(&self) -> u64 {
pub fn end(&self) -> GuestAddr {
self.end
}
#[must_use]
pub fn offset(&self) -> u64 {
pub fn offset(&self) -> GuestAddr {
self.offset
}
@ -349,7 +359,7 @@ impl Emulator {
/// This will write to a translated guest address (using `g2h`).
/// It just adds `guest_base` and writes to that location, without checking the bounds.
/// This may only be safely used for valid guest addresses!
pub unsafe fn write_mem(&self, addr: u64, buf: &[u8]) {
pub unsafe fn write_mem(&self, addr: GuestAddr, buf: &[u8]) {
let host_addr = self.g2h(addr);
copy_nonoverlapping(buf.as_ptr(), host_addr, buf.len());
}
@ -360,7 +370,7 @@ impl Emulator {
/// This will read from a translated guest address (using `g2h`).
/// It just adds `guest_base` and writes to that location, without checking the bounds.
/// This may only be safely used for valid guest addresses!
pub unsafe fn read_mem(&self, addr: u64, buf: &mut [u8]) {
pub unsafe fn read_mem(&self, addr: GuestAddr, buf: &mut [u8]) {
let host_addr = self.g2h(addr);
copy_nonoverlapping(host_addr, buf.as_mut_ptr(), buf.len());
}
@ -399,27 +409,27 @@ impl Emulator {
}
}
pub fn set_breakpoint(&self, addr: u64) {
pub fn set_breakpoint(&self, addr: GuestAddr) {
unsafe {
libafl_qemu_set_breakpoint(addr);
libafl_qemu_set_breakpoint(addr.into());
}
}
pub fn remove_breakpoint(&self, addr: u64) {
pub fn remove_breakpoint(&self, addr: GuestAddr) {
unsafe {
libafl_qemu_remove_breakpoint(addr);
libafl_qemu_remove_breakpoint(addr.into());
}
}
pub fn set_hook(&self, addr: u64, callback: extern "C" fn(u64), val: u64) {
pub fn set_hook(&self, addr: GuestAddr, callback: extern "C" fn(u64), val: u64) {
unsafe {
libafl_qemu_set_hook(addr, callback, val);
libafl_qemu_set_hook(addr.into(), callback, val);
}
}
pub fn remove_hook(&self, addr: u64) {
pub fn remove_hook(&self, addr: GuestAddr) {
unsafe {
libafl_qemu_remove_hook(addr);
libafl_qemu_remove_hook(addr.into());
}
}
@ -433,13 +443,13 @@ impl Emulator {
}
#[must_use]
pub fn g2h<T>(&self, addr: u64) -> *mut T {
unsafe { transmute(addr + guest_base as u64) }
pub fn g2h<T>(&self, addr: GuestAddr) -> *mut T {
unsafe { transmute(addr as usize + guest_base) }
}
#[must_use]
pub fn h2g<T>(&self, addr: *const T) -> u64 {
unsafe { (addr as usize - guest_base) as u64 }
pub fn h2g<T>(&self, addr: *const T) -> GuestAddr {
unsafe { (addr as usize - guest_base) as GuestAddr }
}
#[must_use]
@ -448,21 +458,27 @@ impl Emulator {
}
#[must_use]
pub fn load_addr(&self) -> u64 {
unsafe { libafl_load_addr() }
pub fn load_addr(&self) -> GuestAddr {
unsafe { libafl_load_addr() as GuestAddr }
}
#[must_use]
pub fn get_brk(&self) -> u64 {
unsafe { libafl_get_brk() }
pub fn get_brk(&self) -> GuestAddr {
unsafe { libafl_get_brk() as GuestAddr }
}
pub fn set_brk(&self, brk: u64) {
unsafe { libafl_set_brk(brk) };
pub fn set_brk(&self, brk: GuestAddr) {
unsafe { libafl_set_brk(brk.into()) };
}
fn mmap(&self, addr: u64, size: usize, perms: MmapPerms, flags: c_int) -> Result<u64, ()> {
let res = unsafe { target_mmap(addr, size as u64, perms.into(), flags, -1, 0) };
fn mmap(
&self,
addr: GuestAddr,
size: usize,
perms: MmapPerms,
flags: c_int,
) -> Result<u64, ()> {
let res = unsafe { target_mmap(addr.into(), size as u64, perms.into(), flags, -1, 0) };
if res == 0 {
Err(())
} else {
@ -470,12 +486,23 @@ impl Emulator {
}
}
pub fn map_private(&self, addr: u64, size: usize, perms: MmapPerms) -> Result<u64, String> {
pub fn map_private(
&self,
addr: GuestAddr,
size: usize,
perms: MmapPerms,
) -> Result<GuestAddr, String> {
self.mmap(addr, size, perms, libc::MAP_PRIVATE | libc::MAP_ANONYMOUS)
.map_err(|_| format!("Failed to map {}", addr))
.map(|addr| addr as GuestAddr)
}
pub fn map_fixed(&self, addr: u64, size: usize, perms: MmapPerms) -> Result<u64, String> {
pub fn map_fixed(
&self,
addr: GuestAddr,
size: usize,
perms: MmapPerms,
) -> Result<GuestAddr, String> {
self.mmap(
addr,
size,
@ -483,10 +510,11 @@ impl Emulator {
libc::MAP_FIXED | libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
)
.map_err(|_| format!("Failed to map {}", addr))
.map(|addr| addr as GuestAddr)
}
pub fn mprotect(&self, addr: u64, size: usize, perms: MmapPerms) -> Result<(), String> {
let res = unsafe { target_mprotect(addr, size as u64, perms.into()) };
pub fn mprotect(&self, addr: GuestAddr, size: usize, perms: MmapPerms) -> Result<(), String> {
let res = unsafe { target_mprotect(addr.into(), size as u64, perms.into()) };
if res == 0 {
Ok(())
} else {
@ -494,8 +522,8 @@ impl Emulator {
}
}
pub fn unmap(&self, addr: u64, size: usize) -> Result<(), String> {
if unsafe { target_munmap(addr, size as u64) } == 0 {
pub fn unmap(&self, addr: GuestAddr, size: usize) -> Result<(), String> {
if unsafe { target_munmap(addr.into(), size as u64) } == 0 {
Ok(())
} else {
Err(format!("Failed to unmap {}", addr))
@ -652,14 +680,14 @@ impl Emulator {
#[cfg(feature = "python")]
pub mod pybind {
use super::{MmapPerms, SyscallHookResult};
use super::{GuestAddr, GuestUsize, MmapPerms, SyscallHookResult};
use core::mem::transmute;
use pyo3::exceptions::PyValueError;
use pyo3::{prelude::*, types::PyInt};
use std::convert::TryFrom;
static mut PY_SYSCALL_HOOK: Option<PyObject> = None;
static mut PY_GENERIC_HOOKS: Vec<(u64, PyObject)> = vec![];
static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![];
extern "C" fn py_syscall_hook_wrapper(
sys_num: i32,
@ -719,13 +747,13 @@ pub mod pybind {
}
}
fn write_mem(&self, addr: u64, buf: &[u8]) {
fn write_mem(&self, addr: GuestAddr, buf: &[u8]) {
unsafe {
self.emu.write_mem(addr, buf);
}
}
fn read_mem(&self, addr: u64, size: usize) -> Vec<u8> {
fn read_mem(&self, addr: GuestAddr, size: usize) -> Vec<u8> {
let mut buf = vec![0; size];
unsafe {
self.emu.read_mem(addr, &mut buf);
@ -737,19 +765,19 @@ pub mod pybind {
self.emu.num_regs()
}
fn write_reg(&self, reg: i32, val: u64) -> PyResult<()> {
fn write_reg(&self, reg: i32, val: GuestUsize) -> PyResult<()> {
self.emu.write_reg(reg, val).map_err(PyValueError::new_err)
}
fn read_reg(&self, reg: i32) -> PyResult<u64> {
fn read_reg(&self, reg: i32) -> PyResult<GuestUsize> {
self.emu.read_reg(reg).map_err(PyValueError::new_err)
}
fn set_breakpoint(&self, addr: u64) {
fn set_breakpoint(&self, addr: GuestAddr) {
self.emu.set_breakpoint(addr);
}
fn remove_breakpoint(&self, addr: u64) {
fn remove_breakpoint(&self, addr: GuestAddr) {
self.emu.remove_breakpoint(addr);
}
@ -759,11 +787,11 @@ pub mod pybind {
}
}
fn g2h(&self, addr: u64) -> u64 {
fn g2h(&self, addr: GuestAddr) -> u64 {
self.emu.g2h::<*const u8>(addr) as u64
}
fn h2g(&self, addr: u64) -> u64 {
fn h2g(&self, addr: u64) -> GuestAddr {
self.emu.h2g(unsafe { transmute::<_, *const u8>(addr) })
}
@ -771,11 +799,11 @@ pub mod pybind {
self.emu.binary_path().to_owned()
}
fn load_addr(&self) -> u64 {
fn load_addr(&self) -> GuestAddr {
self.emu.load_addr()
}
fn map_private(&self, addr: u64, size: usize, perms: i32) -> PyResult<u64> {
fn map_private(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<GuestAddr> {
if let Ok(p) = MmapPerms::try_from(perms) {
self.emu
.map_private(addr, size, p)
@ -785,7 +813,7 @@ pub mod pybind {
}
}
fn map_fixed(&self, addr: u64, size: usize, perms: i32) -> PyResult<u64> {
fn map_fixed(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<GuestAddr> {
if let Ok(p) = MmapPerms::try_from(perms) {
self.emu
.map_fixed(addr, size, p)
@ -795,7 +823,7 @@ pub mod pybind {
}
}
fn mprotect(&self, addr: u64, size: usize, perms: i32) -> PyResult<()> {
fn mprotect(&self, addr: GuestAddr, size: usize, perms: i32) -> PyResult<()> {
if let Ok(p) = MmapPerms::try_from(perms) {
self.emu
.mprotect(addr, size, p)
@ -805,7 +833,7 @@ pub mod pybind {
}
}
fn unmap(&self, addr: u64, size: usize) -> PyResult<()> {
fn unmap(&self, addr: GuestAddr, size: usize) -> PyResult<()> {
self.emu.unmap(addr, size).map_err(PyValueError::new_err)
}
@ -816,7 +844,7 @@ pub mod pybind {
self.emu.set_pre_syscall_hook(py_syscall_hook_wrapper);
}
fn set_hook(&self, addr: u64, hook: PyObject) {
fn set_hook(&self, addr: GuestAddr, hook: PyObject) {
unsafe {
let idx = PY_GENERIC_HOOKS.len();
PY_GENERIC_HOOKS.push((addr, hook));
@ -824,7 +852,7 @@ pub mod pybind {
}
}
fn remove_hook(&self, addr: u64) {
fn remove_hook(&self, addr: GuestAddr) {
unsafe {
PY_GENERIC_HOOKS.retain(|(a, _)| *a != addr);
}

View File

@ -23,6 +23,7 @@ pub use crate::emu::SyscallHookResult;
use crate::{
emu::{Emulator, SKIP_EXEC_HOOK},
helper::QemuHelperTuple,
GuestAddr,
};
static mut QEMU_HELPERS_PTR: *const c_void = ptr::null();
@ -120,6 +121,12 @@ where
}
}
// function signature for Read or Write hook functions with known length (1, 2, 4, 8)
type FixedLenHook<QT, S> = fn(&Emulator, &mut QT, &mut S, u64, GuestAddr);
// function signature for Read or Write hook functions with runtime length n
type DynamicLenHook<QT, S> = fn(&Emulator, &mut QT, &mut S, u64, GuestAddr, usize);
static mut READ1_HOOKS: Vec<*const c_void> = vec![];
extern "C" fn read1_hooks_wrapper<I, QT, S>(id: u64, addr: u64)
where
@ -130,8 +137,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &READ1_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -145,8 +152,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &READ2_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -160,8 +167,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &READ4_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -175,8 +182,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &READ8_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -190,8 +197,15 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &READ_N_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64, usize) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr, size as usize);
let func: DynamicLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(
&emulator,
helpers,
state,
id,
addr as GuestAddr,
size as usize,
);
}
}
@ -205,8 +219,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE1_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -220,8 +234,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE2_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -235,8 +249,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE4_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -250,8 +264,8 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE8_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr);
let func: FixedLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr as GuestAddr);
}
}
@ -265,8 +279,15 @@ where
let state = inprocess_get_state::<S>().unwrap();
let emulator = Emulator::new_empty();
for hook in unsafe { &WRITE_N_HOOKS } {
let func: fn(&Emulator, &mut QT, &mut S, u64, u64, usize) = unsafe { transmute(*hook) };
(func)(&emulator, helpers, state, id, addr, size as usize);
let func: DynamicLenHook<QT, S> = unsafe { transmute(*hook) };
(func)(
&emulator,
helpers,
state,
id,
addr as GuestAddr,
size as usize,
);
}
}
@ -564,7 +585,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_read1_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_read1_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
READ1_HOOKS.push(hook as *const _);
}
@ -573,7 +594,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_read2_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_read2_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
READ2_HOOKS.push(hook as *const _);
}
@ -582,7 +603,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_read4_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_read4_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
READ4_HOOKS.push(hook as *const _);
}
@ -591,7 +612,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_read8_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_read8_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
READ8_HOOKS.push(hook as *const _);
}
@ -600,10 +621,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_read_n_execution(
&self,
hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64, size: usize),
) {
pub fn hook_read_n_execution(&self, hook: DynamicLenHook<QT, S>) {
unsafe {
READ_N_HOOKS.push(hook as *const _);
}
@ -624,7 +642,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_write1_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_write1_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
WRITE1_HOOKS.push(hook as *const _);
}
@ -633,7 +651,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_write2_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_write2_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
WRITE2_HOOKS.push(hook as *const _);
}
@ -642,7 +660,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_write4_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_write4_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
WRITE4_HOOKS.push(hook as *const _);
}
@ -651,7 +669,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_write8_execution(&self, hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64)) {
pub fn hook_write8_execution(&self, hook: FixedLenHook<QT, S>) {
unsafe {
WRITE8_HOOKS.push(hook as *const _);
}
@ -660,10 +678,7 @@ where
}
#[allow(clippy::unused_self)]
pub fn hook_write_n_execution(
&self,
hook: fn(&Emulator, &mut QT, &mut S, id: u64, addr: u64, size: usize),
) {
pub fn hook_write_n_execution(&self, hook: DynamicLenHook<QT, S>) {
unsafe {
WRITE_N_HOOKS.push(hook as *const _);
}

View File

@ -1,3 +1,10 @@
// This lint triggers too often on the current GuestAddr type when emulating 64-bit targets because
// u64::from(GuestAddr) is a no-op, but the .into() call is needed when GuestAddr is u32.
#![cfg_attr(
any(feature = "x86_64", feature = "aarch64"),
allow(clippy::useless_conversion)
)]
use std::env;
#[cfg(cpu_target = "aarch64")]

View File

@ -5,14 +5,14 @@ use crate::{
emu::Emulator,
executor::QemuExecutor,
helper::{QemuHelper, QemuHelperTuple},
SYS_mmap, SYS_mremap,
GuestAddr, SYS_mmap, SYS_mremap,
};
pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
#[derive(Debug)]
pub struct SnapshotPageInfo {
pub addr: u64,
pub addr: GuestAddr,
pub dirty: bool,
pub data: [u8; SNAPSHOT_PAGE_SIZE],
}
@ -20,12 +20,12 @@ pub struct SnapshotPageInfo {
#[derive(Debug)]
// TODO be thread-safe maybe with https://amanieu.github.io/thread_local-rs/thread_local/index.html
pub struct QemuSnapshotHelper {
pub access_cache: [u64; 4],
pub access_cache: [GuestAddr; 4],
pub access_cache_idx: usize,
pub pages: HashMap<u64, SnapshotPageInfo>,
pub dirty: Vec<u64>,
pub brk: u64,
pub new_maps: Vec<(u64, usize)>,
pub pages: HashMap<GuestAddr, SnapshotPageInfo>,
pub dirty: Vec<GuestAddr>,
pub brk: GuestAddr,
pub new_maps: Vec<(GuestAddr, usize)>,
pub empty: bool,
}
@ -33,7 +33,7 @@ impl QemuSnapshotHelper {
#[must_use]
pub fn new() -> Self {
Self {
access_cache: [u64::MAX; 4],
access_cache: [GuestAddr::MAX; 4],
access_cache_idx: 0,
pages: HashMap::default(),
dirty: vec![],
@ -60,13 +60,13 @@ impl QemuSnapshotHelper {
};
unsafe { emulator.read_mem(addr, &mut info.data) };
self.pages.insert(addr, info);
addr += SNAPSHOT_PAGE_SIZE as u64;
addr += SNAPSHOT_PAGE_SIZE as GuestAddr;
}
}
self.empty = false;
}
pub fn page_access(&mut self, page: u64) {
pub fn page_access(&mut self, page: GuestAddr) {
if self.access_cache[0] == page
|| self.access_cache[1] == page
|| self.access_cache[2] == page
@ -85,18 +85,18 @@ impl QemuSnapshotHelper {
self.dirty.push(page);
}
pub fn access(&mut self, addr: u64, size: usize) {
pub fn access(&mut self, addr: GuestAddr, size: usize) {
debug_assert!(size > 0);
let page = addr & (SNAPSHOT_PAGE_SIZE as u64 - 1);
let page = addr & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
self.page_access(page);
let second_page = (addr + size as u64 - 1) & (SNAPSHOT_PAGE_SIZE as u64 - 1);
let second_page = (addr + size as GuestAddr - 1) & (SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
if page != second_page {
self.page_access(second_page);
}
}
pub fn reset(&mut self, emulator: &Emulator) {
self.access_cache = [u64::MAX; 4];
self.access_cache = [GuestAddr::MAX; 4];
self.access_cache_idx = 0;
while let Some(page) = self.dirty.pop() {
if let Some(info) = self.pages.get_mut(&page) {
@ -108,7 +108,7 @@ impl QemuSnapshotHelper {
self.reset_maps(emulator);
}
pub fn add_mapped(&mut self, start: u64, size: usize) {
pub fn add_mapped(&mut self, start: GuestAddr, size: usize) {
self.new_maps.push((start, size));
}
@ -160,7 +160,7 @@ pub fn trace_write1_snapshot<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -176,7 +176,7 @@ pub fn trace_write2_snapshot<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -192,7 +192,7 @@ pub fn trace_write4_snapshot<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -208,7 +208,7 @@ pub fn trace_write8_snapshot<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
) where
I: Input,
QT: QemuHelperTuple<I, S>,
@ -224,7 +224,7 @@ pub fn trace_write_n_snapshot<I, QT, S>(
helpers: &mut QT,
_state: &mut S,
_id: u64,
addr: u64,
addr: GuestAddr,
size: usize,
) where
I: Input,
@ -256,7 +256,7 @@ where
I: Input,
QT: QemuHelperTuple<I, S>,
{
if result == u64::MAX
if result as GuestAddr == GuestAddr::MAX
/* -1 */
{
return result;
@ -265,12 +265,12 @@ where
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(result, a1 as usize);
h.add_mapped(result as GuestAddr, a1 as usize);
} else if i64::from(sys_num) == SYS_mremap {
let h = helpers
.match_first_type_mut::<QemuSnapshotHelper>()
.unwrap();
h.add_mapped(a0, a2 as usize);
h.add_mapped(a0 as GuestAddr, a2 as usize);
}
result
}