From 41d24ca375b0d0e277f0726216c602e712a3303c Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 7 Feb 2024 15:03:27 +0100 Subject: [PATCH] Fix broken closure hooks in libafl_qemu (#1839) * Fix broken crash hook * fix hooks * clippy * pin --- libafl_qemu/Cargo.toml | 4 +- libafl_qemu/build_linux.rs | 2 +- libafl_qemu/libafl_qemu_build/Cargo.toml | 1 + libafl_qemu/libafl_qemu_build/src/build.rs | 276 +++++++++++---------- libafl_qemu/libafl_qemu_build/src/lib.rs | 12 +- libafl_qemu/libafl_qemu_sys/Cargo.toml | 1 + libafl_qemu/src/hooks.rs | 192 ++++++++++---- 7 files changed, 303 insertions(+), 185 deletions(-) diff --git a/libafl_qemu/Cargo.toml b/libafl_qemu/Cargo.toml index 9244d2821b..8dcc30d4e7 100644 --- a/libafl_qemu/Cargo.toml +++ b/libafl_qemu/Cargo.toml @@ -56,9 +56,11 @@ systemmode = ["libafl_qemu_sys/systemmode"] ## Automatically register all `#[derive(SerdeAny)]` types at startup. serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"] -## Automatically register all `#[derive(SerdeAny)]` types at startup. slirp = [ "systemmode", "libafl_qemu_sys/slirp" ] # build qemu with host libslirp (for user networking) +# disabled atm, enabled when fixed with dynamic list +# shared = [ "libafl_qemu_sys/shared" ] + [dependencies] libafl = { path = "../libafl", version = "0.11.2", default-features = false, features = ["std", "derive", "regex"] } libafl_bolts = { path = "../libafl_bolts", version = "0.11.2", default-features = false, features = ["std", "derive"] } diff --git a/libafl_qemu/build_linux.rs b/libafl_qemu/build_linux.rs index 516089432a..7ba941bfd8 100644 --- a/libafl_qemu/build_linux.rs +++ b/libafl_qemu/build_linux.rs @@ -95,6 +95,6 @@ pub fn build() { .status() .expect("make failed") .success()); - println!("cargo:rerun-if-changed={}/libqasan.so", target_dir.display()); + // println!("cargo:rerun-if-changed={}/libqasan.so", target_dir.display()); } } diff --git a/libafl_qemu/libafl_qemu_build/Cargo.toml b/libafl_qemu/libafl_qemu_build/Cargo.toml index 9da7ea1cb7..6a3b1aa51a 100644 --- a/libafl_qemu/libafl_qemu_build/Cargo.toml +++ b/libafl_qemu/libafl_qemu_build/Cargo.toml @@ -21,6 +21,7 @@ categories = [ all-features = true [features] +shared = [] slirp = [] # build qemu with host libslirp (for user networking) clippy = [] # special feature for clippy, don't use in normal projects§ diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index 2d183a1081..cec7203f40 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -10,6 +10,11 @@ const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; const QEMU_REVISION: &str = "75d15d54f4417a4766d2dcb493982d9df0e8eac4"; +pub struct BuildResult { + pub qemu_path: PathBuf, + pub build_dir: PathBuf, +} + fn build_dep_check(tools: &[&str]) { for tool in tools { which(tool).unwrap_or_else(|_| panic!("Build tool {tool} not found")); @@ -23,7 +28,7 @@ pub fn build( is_big_endian: bool, is_usermode: bool, jobs: Option, -) -> (PathBuf, PathBuf) { +) -> BuildResult { let mut cpu_target = cpu_target.to_string(); // qemu-system-arm supports both big and little endian configurations and so // therefore the "be" feature should ignored in this configuration. Also @@ -120,13 +125,19 @@ pub fn build( "softmmu".to_string() }; - let output_lib = if is_usermode { - build_dir.join(format!("libqemu-{cpu_target}.so")) + let (output_lib, output_lib_link) = if is_usermode { + ( + build_dir.join(format!("libqemu-{cpu_target}.so")), + format!("qemu-{cpu_target}"), + ) } else { - build_dir.join(format!("libqemu-system-{cpu_target}.so")) + ( + build_dir.join(format!("libqemu-system-{cpu_target}.so")), + format!("qemu-system-{cpu_target}"), + ) }; - println!("cargo:rerun-if-changed={}", output_lib.to_string_lossy()); + // println!("cargo:rerun-if-changed={}", output_lib.to_string_lossy()); if !output_lib.is_file() || (custom_qemu_dir.is_some() && !custom_qemu_no_build) { /*drop( @@ -337,137 +348,145 @@ pub fn build( } */ - let compile_commands_string = - &fs::read_to_string(build_dir.join("linkinfo.json")).expect("Failed to read linkinfo.json"); - - let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json"); - - let mut cmd = vec![]; - for arg in linkinfo["cmd"].members() { - cmd.push( - arg.as_str() - .expect("linkinfo.json `cmd` values must be strings"), + if cfg!(feature = "shared") { + println!( + "cargo:rustc-link-search=native={}", + build_dir.to_string_lossy() ); - } - - assert!(cpp_compiler - .to_command() - .current_dir(&build_dir) - .arg("-o") - .arg("libqemu-partially-linked.o") - .arg("-r") - .args(cmd) - .status() - .expect("Partial linked failure") - .success()); - - /* // Old manual linking, kept here for reference and debugging - if is_usermode { - Command::new("ld") - .current_dir(out_dir_path) - .arg("-o") - .arg("libqemu-partially-linked.o") - .arg("-r") - .args(objects) - .arg("--start-group") - .arg("--whole-archive") - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/libevent-loop-base.a", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display())) - .arg("--no-whole-archive") - .arg(format!("{}/libqemuutil.a", build_dir.display())) - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display())) - .arg(format!( - "--dynamic-list={}/plugins/qemu-plugins.symbols", - qemu_path.display() - )) - .arg("--end-group") - .status() - .expect("Partial linked failure"); + println!("cargo:rustc-link-lib=dylib={output_lib_link}"); } else { - Command::new("ld") - .current_dir(out_dir_path) + let compile_commands_string = &fs::read_to_string(build_dir.join("linkinfo.json")) + .expect("Failed to read linkinfo.json"); + + let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json"); + + let mut cmd = vec![]; + for arg in linkinfo["cmd"].members() { + cmd.push( + arg.as_str() + .expect("linkinfo.json `cmd` values must be strings"), + ); + } + + assert!(cpp_compiler + .to_command() + .current_dir(&build_dir) .arg("-o") .arg("libqemu-partially-linked.o") .arg("-r") - .args(objects) - .arg("--start-group") - .arg("--whole-archive") - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/libevent-loop-base.a", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display())) - .arg(format!("{}/libio.fa", build_dir.display())) - .arg(format!("{}/libcrypto.fa", build_dir.display())) - .arg(format!("{}/libauthz.fa", build_dir.display())) - .arg(format!("{}/libblockdev.fa", build_dir.display())) - .arg(format!("{}/libblock.fa", build_dir.display())) - .arg(format!("{}/libchardev.fa", build_dir.display())) - .arg(format!("{}/libqmp.fa", build_dir.display())) - .arg("--no-whole-archive") - .arg(format!("{}/libqemuutil.a", build_dir.display())) - .arg(format!( - "{}/subprojects/dtc/libfdt/libfdt.a", - build_dir.display() - )) - .arg(format!( - "{}/subprojects/libvhost-user/libvhost-user-glib.a", - build_dir.display() - )) - .arg(format!( - "{}/subprojects/libvhost-user/libvhost-user.a", - build_dir.display() - )) - .arg(format!( - "{}/subprojects/libvduse/libvduse.a", - build_dir.display() - )) - .arg(format!("{}/libmigration.fa", build_dir.display())) - .arg(format!("{}/libhwcore.fa", build_dir.display())) - .arg(format!("{}/libqom.fa", build_dir.display())) - .arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display())) - .arg(format!("{}/libio.fa", build_dir.display())) - .arg(format!("{}/libcrypto.fa", build_dir.display())) - .arg(format!("{}/libauthz.fa", build_dir.display())) - .arg(format!("{}/libblockdev.fa", build_dir.display())) - .arg(format!("{}/libblock.fa", build_dir.display())) - .arg(format!("{}/libchardev.fa", build_dir.display())) - .arg(format!("{}/libqmp.fa", build_dir.display())) - .arg(format!( - "--dynamic-list={}/plugins/qemu-plugins.symbols", - qemu_path.display() - )) - .arg("--end-group") + .args(cmd) .status() - .expect("Partial linked failure"); - }*/ + .expect("Partial linked failure") + .success()); - Command::new("ar") - .current_dir(out_dir_path) - .arg("crs") - .arg("libqemu-partially-linked.a") - .arg(build_dir.join("libqemu-partially-linked.o")) - .status() - .expect("Ar creation"); + /* // Old manual linking, kept here for reference and debugging + if is_usermode { + Command::new("ld") + .current_dir(out_dir_path) + .arg("-o") + .arg("libqemu-partially-linked.o") + .arg("-r") + .args(objects) + .arg("--start-group") + .arg("--whole-archive") + .arg(format!("{}/libhwcore.fa", build_dir.display())) + .arg(format!("{}/libqom.fa", build_dir.display())) + .arg(format!("{}/libevent-loop-base.a", build_dir.display())) + .arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display())) + .arg("--no-whole-archive") + .arg(format!("{}/libqemuutil.a", build_dir.display())) + .arg(format!("{}/libhwcore.fa", build_dir.display())) + .arg(format!("{}/libqom.fa", build_dir.display())) + .arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display())) + .arg(format!( + "--dynamic-list={}/plugins/qemu-plugins.symbols", + qemu_path.display() + )) + .arg("--end-group") + .status() + .expect("Partial linked failure"); + } else { + Command::new("ld") + .current_dir(out_dir_path) + .arg("-o") + .arg("libqemu-partially-linked.o") + .arg("-r") + .args(objects) + .arg("--start-group") + .arg("--whole-archive") + .arg(format!("{}/libhwcore.fa", build_dir.display())) + .arg(format!("{}/libqom.fa", build_dir.display())) + .arg(format!("{}/libevent-loop-base.a", build_dir.display())) + .arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display())) + .arg(format!("{}/libio.fa", build_dir.display())) + .arg(format!("{}/libcrypto.fa", build_dir.display())) + .arg(format!("{}/libauthz.fa", build_dir.display())) + .arg(format!("{}/libblockdev.fa", build_dir.display())) + .arg(format!("{}/libblock.fa", build_dir.display())) + .arg(format!("{}/libchardev.fa", build_dir.display())) + .arg(format!("{}/libqmp.fa", build_dir.display())) + .arg("--no-whole-archive") + .arg(format!("{}/libqemuutil.a", build_dir.display())) + .arg(format!( + "{}/subprojects/dtc/libfdt/libfdt.a", + build_dir.display() + )) + .arg(format!( + "{}/subprojects/libvhost-user/libvhost-user-glib.a", + build_dir.display() + )) + .arg(format!( + "{}/subprojects/libvhost-user/libvhost-user.a", + build_dir.display() + )) + .arg(format!( + "{}/subprojects/libvduse/libvduse.a", + build_dir.display() + )) + .arg(format!("{}/libmigration.fa", build_dir.display())) + .arg(format!("{}/libhwcore.fa", build_dir.display())) + .arg(format!("{}/libqom.fa", build_dir.display())) + .arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display())) + .arg(format!("{}/libio.fa", build_dir.display())) + .arg(format!("{}/libcrypto.fa", build_dir.display())) + .arg(format!("{}/libauthz.fa", build_dir.display())) + .arg(format!("{}/libblockdev.fa", build_dir.display())) + .arg(format!("{}/libblock.fa", build_dir.display())) + .arg(format!("{}/libchardev.fa", build_dir.display())) + .arg(format!("{}/libqmp.fa", build_dir.display())) + .arg(format!( + "--dynamic-list={}/plugins/qemu-plugins.symbols", + qemu_path.display() + )) + .arg("--end-group") + .status() + .expect("Partial linked failure"); + }*/ - println!("cargo:rustc-link-search=native={out_dir}"); - println!("cargo:rustc-link-lib=static=qemu-partially-linked"); + Command::new("ar") + .current_dir(out_dir_path) + .arg("crs") + .arg("libqemu-partially-linked.a") + .arg(build_dir.join("libqemu-partially-linked.o")) + .status() + .expect("Ar creation"); - for arg in linkinfo["search"].members() { - let val = arg - .as_str() - .expect("linkinfo.json `search` values must be strings"); - println!("cargo:rustc-link-search={val}"); - } + println!("cargo:rustc-link-search=native={out_dir}"); + println!("cargo:rustc-link-lib=static=qemu-partially-linked"); - for arg in linkinfo["libs"].members() { - let val = arg - .as_str() - .expect("linkinfo.json `libs` values must be strings"); - println!("cargo:rustc-link-lib={val}"); + for arg in linkinfo["search"].members() { + let val = arg + .as_str() + .expect("linkinfo.json `search` values must be strings"); + println!("cargo:rustc-link-search={val}"); + } + + for arg in linkinfo["libs"].members() { + let val = arg + .as_str() + .expect("linkinfo.json `libs` values must be strings"); + println!("cargo:rustc-link-lib={val}"); + } } /* @@ -500,5 +519,8 @@ pub fn build( } } - (qemu_path, build_dir) + BuildResult { + qemu_path, + build_dir, + } } diff --git a/libafl_qemu/libafl_qemu_build/src/lib.rs b/libafl_qemu/libafl_qemu_build/src/lib.rs index a6fedff623..c112adf678 100644 --- a/libafl_qemu/libafl_qemu_build/src/lib.rs +++ b/libafl_qemu/libafl_qemu_build/src/lib.rs @@ -22,10 +22,16 @@ pub fn build_with_bindings( jobs: Option, bindings_file: &Path, ) { - let (qemu_dir, build_dir) = build::build(cpu_target, is_big_endian, is_usermode, jobs); - let clang_args = qemu_bindgen_clang_args(&qemu_dir, &build_dir, cpu_target, is_usermode); + let build_result = build::build(cpu_target, is_big_endian, is_usermode, jobs); - let bind = bindings::generate(&build_dir, cpu_target, clang_args) + let clang_args = qemu_bindgen_clang_args( + &build_result.qemu_path, + &build_result.build_dir, + cpu_target, + is_usermode, + ); + + let bind = bindings::generate(&build_result.build_dir, cpu_target, clang_args) .expect("Failed to generate the bindings"); bind.write_to_file(bindings_file) .expect("Faield to write to the bindings file"); diff --git a/libafl_qemu/libafl_qemu_sys/Cargo.toml b/libafl_qemu/libafl_qemu_sys/Cargo.toml index f96f182499..d04c6a69ab 100644 --- a/libafl_qemu/libafl_qemu_sys/Cargo.toml +++ b/libafl_qemu/libafl_qemu_sys/Cargo.toml @@ -31,6 +31,7 @@ usermode = [] systemmode = [] slirp = [ "systemmode", "libafl_qemu_build/slirp" ] # build qemu with host libslirp (for user networking) +shared = [ "libafl_qemu_build/shared" ] clippy = [ "libafl_qemu_build/clippy" ] # special feature for clippy, don't use in normal projects§ diff --git a/libafl_qemu/src/hooks.rs b/libafl_qemu/src/hooks.rs index b6ba387518..a1a6aad8be 100644 --- a/libafl_qemu/src/hooks.rs +++ b/libafl_qemu/src/hooks.rs @@ -6,6 +6,7 @@ use core::{ fmt::{self, Debug, Formatter}, marker::PhantomData, mem::transmute, + pin::Pin, ptr::{self, addr_of, addr_of_mut}, }; @@ -25,7 +26,7 @@ use crate::{ #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub(crate) enum Hook { Function(*const c_void), - Closure(Box), + Closure(FatPtr), #[cfg(emulation_mode = "usermode")] Once(Box), Empty, @@ -36,7 +37,7 @@ pub(crate) enum Hook { #[derive(Clone, PartialEq, Eq, Debug)] pub(crate) enum HookRepr { Function(*const c_void), - Closure(Box), + Closure(FatPtr), Empty, } @@ -77,7 +78,7 @@ macro_rules! hook_to_repr { ($h:expr) => { match $h { Hook::Function(f) => HookRepr::Function(f as *const libc::c_void), - Hook::Closure(c) => HookRepr::Closure(Box::new(transmute(c))), + Hook::Closure(c) => HookRepr::Closure(transmute(c)), Hook::Raw(_) => HookRepr::Empty, // managed by emu Hook::Empty => HookRepr::Empty, } @@ -242,13 +243,13 @@ macro_rules! create_exec_wrapper { } } -static mut GENERIC_HOOKS: Vec<(InstructionHookId, Box)> = vec![]; +static mut GENERIC_HOOKS: Vec>> = vec![]; create_wrapper!(generic, (pc: GuestAddr)); -static mut BACKDOOR_HOOKS: Vec<(BackdoorHookId, Box)> = vec![]; +static mut BACKDOOR_HOOKS: Vec>> = vec![]; create_wrapper!(backdoor, (pc: GuestAddr)); #[cfg(emulation_mode = "usermode")] -static mut PRE_SYSCALL_HOOKS: Vec<(PreSyscallHookId, Box)> = vec![]; +static mut PRE_SYSCALL_HOOKS: Vec>> = vec![]; #[cfg(emulation_mode = "usermode")] create_wrapper!(pre_syscall, (sys_num: i32, a0: GuestAddr, @@ -260,7 +261,7 @@ create_wrapper!(pre_syscall, (sys_num: i32, a6: GuestAddr, a7: GuestAddr), SyscallHookResult); #[cfg(emulation_mode = "usermode")] -static mut POST_SYSCALL_HOOKS: Vec<(PostSyscallHookId, Box)> = vec![]; +static mut POST_SYSCALL_HOOKS: Vec>> = vec![]; #[cfg(emulation_mode = "usermode")] create_wrapper!(post_syscall, (res: GuestAddr, sys_num: i32, a0: GuestAddr, @@ -272,20 +273,20 @@ create_wrapper!(post_syscall, (res: GuestAddr, sys_num: i32, a6: GuestAddr, a7: GuestAddr), GuestAddr); #[cfg(emulation_mode = "usermode")] -static mut NEW_THREAD_HOOKS: Vec<(NewThreadHookId, Box)> = vec![]; +static mut NEW_THREAD_HOOKS: Vec>> = vec![]; #[cfg(emulation_mode = "usermode")] create_wrapper!(new_thread, (tid: u32), bool); -static mut EDGE_HOOKS: Vec> = vec![]; +static mut EDGE_HOOKS: Vec>>> = vec![]; create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId); create_exec_wrapper!(edge, (id: u64), 0, 1, EdgeHookId); -static mut BLOCK_HOOKS: Vec> = vec![]; +static mut BLOCK_HOOKS: Vec>>> = vec![]; create_gen_wrapper!(block, (addr: GuestAddr), u64, 1, BlockHookId); create_post_gen_wrapper!(block, (addr: GuestAddr, len: GuestUsize), 1, BlockHookId); create_exec_wrapper!(block, (id: u64), 0, 1, BlockHookId); -static mut READ_HOOKS: Vec> = vec![]; +static mut READ_HOOKS: Vec>>> = vec![]; create_gen_wrapper!(read, (pc: GuestAddr, info: MemAccessInfo), u64, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 0, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 1, 5, ReadHookId); @@ -293,7 +294,7 @@ create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 2, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr), 3, 5, ReadHookId); create_exec_wrapper!(read, (id: u64, addr: GuestAddr, size: usize), 4, 5, ReadHookId); -static mut WRITE_HOOKS: Vec> = vec![]; +static mut WRITE_HOOKS: Vec>>> = vec![]; create_gen_wrapper!(write, (pc: GuestAddr, info: MemAccessInfo), u64, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 0, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 1, 5, WriteHookId); @@ -301,7 +302,7 @@ create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 2, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr), 3, 5, WriteHookId); create_exec_wrapper!(write, (id: u64, addr: GuestAddr, size: usize), 4, 5, WriteHookId); -static mut CMP_HOOKS: Vec> = vec![]; +static mut CMP_HOOKS: Vec>>> = vec![]; create_gen_wrapper!(cmp, (pc: GuestAddr, size: usize), u64, 4, CmpHookId); create_exec_wrapper!(cmp, (id: u64, v0: u8, v1: u8), 0, 4, CmpHookId); create_exec_wrapper!(cmp, (id: u64, v0: u16, v1: u16), 1, 4, CmpHookId); @@ -459,14 +460,25 @@ where invalidate_block: bool, ) -> InstructionHookId { unsafe { - let mut fat: Box = Box::new(transmute(hook)); + let fat: FatPtr = transmute(hook); + GENERIC_HOOKS.push(Box::pin((InstructionHookId(0), fat))); let id = self.emulator.set_hook( - transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime + &mut GENERIC_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .1, addr, closure_generic_hook_wrapper::, invalidate_block, ); - GENERIC_HOOKS.push((id, fat)); + GENERIC_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .0 = id; id } } @@ -506,16 +518,23 @@ where edge_0_exec_hook_wrapper::, extern "C" fn(&mut HookState<1, EdgeHookId>, id: u64) ); - EDGE_HOOKS.push(HookState { + EDGE_HOOKS.push(Box::pin(HookState { id: EdgeHookId(0), gen: hook_to_repr!(generation_hook), post_gen: HookRepr::Empty, execs: [hook_to_repr!(execution_hook)], - }); - let id = self - .emulator - .add_edge_hooks(EDGE_HOOKS.last_mut().unwrap(), gen, exec); - EDGE_HOOKS.last_mut().unwrap().id = id; + })); + let id = self.emulator.add_edge_hooks( + EDGE_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(), + gen, + exec, + ); + EDGE_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .id = id; id } } @@ -558,16 +577,24 @@ where block_0_exec_hook_wrapper::, extern "C" fn(&mut HookState<1, BlockHookId>, id: u64) ); - BLOCK_HOOKS.push(HookState { + BLOCK_HOOKS.push(Box::pin(HookState { id: BlockHookId(0), gen: hook_to_repr!(generation_hook), post_gen: hook_to_repr!(post_generation_hook), execs: [hook_to_repr!(execution_hook)], - }); - let id = - self.emulator - .add_block_hooks(BLOCK_HOOKS.last_mut().unwrap(), gen, postgen, exec); - BLOCK_HOOKS.last_mut().unwrap().id = id; + })); + let id = self.emulator.add_block_hooks( + BLOCK_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(), + gen, + postgen, + exec, + ); + BLOCK_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .id = id; id } } @@ -648,7 +675,7 @@ where read_4_exec_hook_wrapper::, extern "C" fn(&mut HookState<5, ReadHookId>, id: u64, addr: GuestAddr, size: usize) ); - READ_HOOKS.push(HookState { + READ_HOOKS.push(Box::pin(HookState { id: ReadHookId(0), gen: hook_to_repr!(generation_hook), post_gen: HookRepr::Empty, @@ -659,9 +686,9 @@ where hook_to_repr!(execution_hook_8), hook_to_repr!(execution_hook_n), ], - }); + })); let id = self.emulator.add_read_hooks( - READ_HOOKS.last_mut().unwrap(), + READ_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(), gen, exec1, exec2, @@ -669,7 +696,12 @@ where exec8, execn, ); - READ_HOOKS.last_mut().unwrap().id = id; + READ_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .id = id; id } } @@ -755,7 +787,7 @@ where size: usize, ) ); - WRITE_HOOKS.push(HookState { + WRITE_HOOKS.push(Box::pin(HookState { id: WriteHookId(0), gen: hook_to_repr!(generation_hook), post_gen: HookRepr::Empty, @@ -766,9 +798,9 @@ where hook_to_repr!(execution_hook_8), hook_to_repr!(execution_hook_n), ], - }); + })); let id = self.emulator.add_write_hooks( - WRITE_HOOKS.last_mut().unwrap(), + WRITE_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(), gen, exec1, exec2, @@ -776,7 +808,12 @@ where exec8, execn, ); - WRITE_HOOKS.last_mut().unwrap().id = id; + WRITE_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .id = id; id } } @@ -837,7 +874,7 @@ where cmp_3_exec_hook_wrapper::, extern "C" fn(&mut HookState<4, CmpHookId>, id: u64, v0: u64, v1: u64) ); - CMP_HOOKS.push(HookState { + CMP_HOOKS.push(Box::pin(HookState { id: CmpHookId(0), gen: hook_to_repr!(generation_hook), post_gen: HookRepr::Empty, @@ -847,16 +884,21 @@ where hook_to_repr!(execution_hook_4), hook_to_repr!(execution_hook_8), ], - }); + })); let id = self.emulator.add_cmp_hooks( - CMP_HOOKS.last_mut().unwrap(), + CMP_HOOKS.last_mut().unwrap().as_mut().get_unchecked_mut(), gen, exec1, exec2, exec4, exec8, ); - CMP_HOOKS.last_mut().unwrap().id = id; + CMP_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .id = id; id } } @@ -895,12 +937,23 @@ where hook: Box FnMut(&'a mut Self, Option<&'a mut S>, GuestAddr)>, ) -> BackdoorHookId { unsafe { - let mut fat: Box = Box::new(transmute(hook)); + let fat: FatPtr = transmute(hook); + BACKDOOR_HOOKS.push(Box::pin((BackdoorHookId(0), fat))); let id = self.emulator.add_backdoor_hook( - transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime + &mut BACKDOOR_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .1, closure_backdoor_hook_wrapper::, ); - BACKDOOR_HOOKS.push((id, fat)); + BACKDOOR_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .0 = id; id } } @@ -1008,12 +1061,23 @@ where >, ) -> PreSyscallHookId { unsafe { - let mut fat: Box = Box::new(transmute(hook)); + let fat: FatPtr = transmute(hook); + PRE_SYSCALL_HOOKS.push(Box::pin((PreSyscallHookId(0), fat))); let id = self.emulator.add_pre_syscall_hook( - transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime + &mut PRE_SYSCALL_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .1, closure_pre_syscall_hook_wrapper::, ); - PRE_SYSCALL_HOOKS.push((id, fat)); + PRE_SYSCALL_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .0 = id; id } } @@ -1126,12 +1190,23 @@ where >, ) -> PostSyscallHookId { unsafe { - let mut fat: Box = Box::new(transmute(hook)); + let fat: FatPtr = transmute(hook); + POST_SYSCALL_HOOKS.push(Box::pin((PostSyscallHookId(0), fat))); let id = self.emulator.add_post_syscall_hook( - transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime + &mut POST_SYSCALL_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .1, closure_post_syscall_hook_wrapper::, ); - POST_SYSCALL_HOOKS.push((id, fat)); + POST_SYSCALL_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .0 = id; id } } @@ -1173,12 +1248,23 @@ where hook: Box FnMut(&'a mut Self, Option<&'a mut S>, u32) -> bool>, ) -> NewThreadHookId { unsafe { - let mut fat: Box = Box::new(transmute(hook)); + let fat: FatPtr = transmute(hook); + NEW_THREAD_HOOKS.push(Box::pin((NewThreadHookId(0), fat))); let id = self.emulator.add_new_thread_hook( - transmute::<&mut FatPtr, &mut FatPtr>(&mut *fat), //transmute satisfy the lifetime + &mut NEW_THREAD_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .1, closure_new_thread_hook_wrapper::, ); - NEW_THREAD_HOOKS.push((id, fat)); + NEW_THREAD_HOOKS + .last_mut() + .unwrap() + .as_mut() + .get_unchecked_mut() + .0 = id; id } } @@ -1195,7 +1281,7 @@ where pub fn crash_closure(&self, hook: Box) { unsafe { self.emulator.set_crash_hook(crash_hook_wrapper::); - CRASH_HOOKS.push(HookRepr::Closure(Box::new(transmute(hook)))); + CRASH_HOOKS.push(HookRepr::Closure(transmute(hook))); } } }