diff --git a/libafl_qemu/libafl_qemu_build/src/bindings.rs b/libafl_qemu/libafl_qemu_build/src/bindings.rs index 0b8f954291..7c76e8f0f9 100644 --- a/libafl_qemu/libafl_qemu_build/src/bindings.rs +++ b/libafl_qemu/libafl_qemu_build/src/bindings.rs @@ -61,6 +61,7 @@ const WRAPPER_HEADER: &str = r#" #include "sysemu/runstate.h" #include "sysemu/replay.h" +#include "libafl/qemu_snapshot.h" #include "libafl/syx-snapshot/device-save.h" #include "libafl/syx-snapshot/syx-snapshot.h" @@ -82,6 +83,8 @@ const WRAPPER_HEADER: &str = r#" #include "qemu/plugin-memory.h" +#include "libafl/cpu.h" +#include "libafl/gdb.h" #include "libafl/exit.h" #include "libafl/jit.h" #include "libafl/utils.h" diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index 8fcaf8bf1f..5954d93d44 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -11,7 +11,7 @@ use crate::cargo_add_rpath; pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; pub const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -pub const QEMU_REVISION: &str = "86d38fbfa7e632b3a4a14def14a11b9b9ba1642d"; +pub const QEMU_REVISION: &str = "7f468ebba6ec4b74d6ca6f4267f365f551c71fe4"; #[allow(clippy::module_name_repetitions)] pub struct BuildResult { diff --git a/libafl_qemu/libafl_qemu_build/src/lib.rs b/libafl_qemu/libafl_qemu_build/src/lib.rs index b98f499f08..da1545161f 100644 --- a/libafl_qemu/libafl_qemu_build/src/lib.rs +++ b/libafl_qemu/libafl_qemu_build/src/lib.rs @@ -421,6 +421,8 @@ pub fn maybe_generate_stub_bindings( force_regeneration, ); } + } else if env::var("CARGO_CFG_DOC").is_ok() { + println!("cargo:warning=Bindings regeneration has been skipped. Please rerun with x86_64 with usermode to trigger the bindings regeneration."); } } diff --git a/libafl_qemu/libafl_qemu_sys/src/lib.rs b/libafl_qemu/libafl_qemu_sys/src/lib.rs index 11020d04f2..a56a2eb35b 100644 --- a/libafl_qemu/libafl_qemu_sys/src/lib.rs +++ b/libafl_qemu/libafl_qemu_sys/src/lib.rs @@ -15,8 +15,11 @@ __Warning__: The documentation is built by default for `x86_64` in `usermode`. T #![allow(clippy::pedantic)] #![cfg_attr(nightly, feature(used_with_arg))] +#[cfg(target_os = "linux")] +use core::ops::BitAnd; +use std::ffi::c_void; + use num_enum::{IntoPrimitive, TryFromPrimitive}; -use paste::paste; use strum_macros::EnumIter; #[cfg(all(not(feature = "clippy"), target_os = "linux"))] @@ -40,6 +43,8 @@ pub use bindings::*; #[allow(dead_code)] #[rustfmt::skip] mod x86_64_stub_bindings; +#[cfg(any(feature = "clippy", not(target_os = "linux")))] +pub use x86_64_stub_bindings::*; #[cfg(emulation_mode = "usermode")] mod usermode; @@ -115,25 +120,18 @@ macro_rules! extern_c_checked { }; } -#[cfg(target_os = "linux")] -use core::ops::BitAnd; -use std::ffi::c_void; +pub type CPUStatePtr = *mut CPUState; +pub type CPUArchStatePtr = *mut CPUArchState; +pub type ExitReasonPtr = *mut libafl_exit_reason; -#[cfg(any(feature = "clippy", not(target_os = "linux")))] -pub use x86_64_stub_bindings::*; +pub type GuestUsize = target_ulong; +pub type GuestIsize = target_long; -pub type CPUStatePtr = *mut crate::CPUState; -pub type CPUArchStatePtr = *mut crate::CPUArchState; -pub type ExitReasonPtr = *mut crate::libafl_exit_reason; +pub type GuestAddr = target_ulong; +pub type GuestPhysAddr = hwaddr; +pub type GuestVirtAddr = vaddr; -pub type GuestUsize = crate::target_ulong; -pub type GuestIsize = crate::target_long; - -pub type GuestAddr = crate::target_ulong; -pub type GuestPhysAddr = crate::hwaddr; -pub type GuestVirtAddr = crate::vaddr; - -pub type GuestHwAddrInfo = crate::qemu_plugin_hwaddr; +pub type GuestHwAddrInfo = qemu_plugin_hwaddr; #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -177,37 +175,3 @@ pub fn make_plugin_meminfo(oi: MemOpIdx, rw: qemu_plugin_mem_rw) -> qemu_plugin_ pub fn cpu_env(cpu: *mut CPUState) -> *mut CPUArchState { unsafe { cpu.add(1) as *mut CPUArchState } } - -extern_c_checked! { - //static libafl_page_size: GuestUsize; - pub fn libafl_page_from_addr(addr: GuestAddr) -> GuestAddr; - - // CPUState* libafl_qemu_get_cpu(int cpu_index); - pub fn libafl_qemu_get_cpu(cpu_index: i32) -> CPUStatePtr; - // int libafl_qemu_num_cpus(void); - pub fn libafl_qemu_num_cpus() -> i32; - // CPUState* libafl_qemu_current_cpu(void); - pub fn libafl_qemu_current_cpu() -> CPUStatePtr; - - // struct libafl_exit_reason* libafl_get_exit_reason(void); - // fn libafl_get_exit_reason() -> ExitReasonPtr; - - pub fn libafl_qemu_cpu_index(cpu: CPUStatePtr) -> i32; - - pub fn libafl_qemu_write_reg(cpu: CPUStatePtr, reg: i32, val: *const u8) -> i32; - pub fn libafl_qemu_read_reg(cpu: CPUStatePtr, reg: i32, val: *mut u8) -> i32; - pub fn libafl_qemu_num_regs(cpu: CPUStatePtr) -> i32; - - // fn libafl_qemu_set_breakpoint(addr: u64) -> i32; - // fn libafl_qemu_remove_breakpoint(addr: u64) -> i32; - pub fn libafl_flush_jit(); - // fn libafl_qemu_trigger_breakpoint(cpu: CPUStatePtr); - - pub fn strlen(s: *const u8) -> usize; - - pub fn libafl_qemu_add_gdb_cmd( - callback: extern "C" fn(*const (), *const u8, usize) -> i32, - data: *const () - ); - pub fn libafl_qemu_gdb_reply(buf: *const u8, len: usize); -} diff --git a/libafl_qemu/libafl_qemu_sys/src/systemmode.rs b/libafl_qemu/libafl_qemu_sys/src/systemmode.rs index 85b02d58d4..d0d1c1d763 100644 --- a/libafl_qemu/libafl_qemu_sys/src/systemmode.rs +++ b/libafl_qemu/libafl_qemu_sys/src/systemmode.rs @@ -1,6 +1,6 @@ use paste::paste; -use crate::{extern_c_checked, CPUStatePtr, GuestPhysAddr}; +use crate::extern_c_checked; extern_c_checked! { pub fn qemu_init(argc: i32, argv: *const *const u8, envp: *const *const u8); @@ -8,9 +8,4 @@ extern_c_checked! { pub fn vm_start(); pub fn qemu_main_loop(); pub fn qemu_cleanup(); - - pub fn libafl_save_qemu_snapshot(name: *const u8, sync: bool); - pub fn libafl_load_qemu_snapshot(name: *const u8, sync: bool); - - pub fn libafl_qemu_current_paging_id(cpu: CPUStatePtr) -> GuestPhysAddr; } diff --git a/libafl_qemu/libafl_qemu_sys/src/usermode.rs b/libafl_qemu/libafl_qemu_sys/src/usermode.rs index dfbb2d6efa..54bb4d7523 100644 --- a/libafl_qemu/libafl_qemu_sys/src/usermode.rs +++ b/libafl_qemu/libafl_qemu_sys/src/usermode.rs @@ -1,22 +1,17 @@ use core::{slice::from_raw_parts, str::from_utf8_unchecked}; +use libc::{c_char, strlen}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use paste::paste; #[cfg(feature = "python")] use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python}; use strum_macros::EnumIter; -use crate::{extern_c_checked, libafl_mapinfo, strlen, GuestAddr, MmapPerms}; +use crate::{extern_c_checked, libafl_mapinfo, GuestAddr, MmapPerms}; extern_c_checked! { pub fn qemu_user_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32; - pub fn libafl_qemu_run() -> i32; - - pub fn libafl_load_addr() -> u64; - pub fn libafl_get_brk() -> u64; - pub fn libafl_set_brk(brk: u64) -> u64; - pub static exec_path: *const u8; pub static guest_base: usize; pub static mut mmap_next_start: GuestAddr; @@ -130,7 +125,7 @@ impl From for MapInfo { Some( from_utf8_unchecked(from_raw_parts( map_info.path as *const u8, - strlen(map_info.path as *const u8), + strlen(map_info.path as *const c_char), )) .to_string(), ) diff --git a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs index 647c70f3b3..2e529936fc 100644 --- a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs +++ b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs @@ -1,5 +1,5 @@ /* 1.82.0-nightly */ -/* qemu git hash: 8f61fadbec181bfcbd305ba92a86a41376a476f7 */ +/* qemu git hash: 31ee26f97071d5bed1ac1e7de75beea755b198d6 */ /* automatically generated by rust-bindgen 0.69.4 */ #[repr(C)] @@ -12631,6 +12631,408 @@ pub struct MemOp(pub ::std::os::raw::c_uint); pub type MemOpIdx = u32; #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct image_info { + pub load_bias: abi_ulong, + pub load_addr: abi_ulong, + pub start_code: abi_ulong, + pub end_code: abi_ulong, + pub start_data: abi_ulong, + pub end_data: abi_ulong, + pub brk: abi_ulong, + pub start_stack: abi_ulong, + pub stack_limit: abi_ulong, + pub vdso: abi_ulong, + pub entry: abi_ulong, + pub code_offset: abi_ulong, + pub data_offset: abi_ulong, + pub saved_auxv: abi_ulong, + pub auxv_len: abi_ulong, + pub argc: abi_ulong, + pub argv: abi_ulong, + pub envc: abi_ulong, + pub envp: abi_ulong, + pub file_string: abi_ulong, + pub elf_flags: u32, + pub personality: ::std::os::raw::c_int, + pub alignment: abi_ulong, + pub exec_stack: bool, + pub arg_strings: abi_ulong, + pub env_strings: abi_ulong, + pub loadmap_addr: abi_ulong, + pub nsegs: u16, + pub loadsegs: *mut ::std::os::raw::c_void, + pub pt_dynamic_addr: abi_ulong, + pub interpreter_loadmap_addr: abi_ulong, + pub interpreter_pt_dynamic_addr: abi_ulong, + pub other_info: *mut image_info, + pub note_flags: u32, +} +#[test] +fn bindgen_test_layout_image_info() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 264usize, + concat!("Size of: ", stringify!(image_info)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(image_info)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).load_bias) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(load_bias) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).load_addr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(load_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).start_code) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(start_code) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).end_code) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(end_code) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).start_data) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(start_data) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).end_data) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(end_data) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).brk) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(brk) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).start_stack) as usize - ptr as usize }, + 56usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(start_stack) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).stack_limit) as usize - ptr as usize }, + 64usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(stack_limit) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).vdso) as usize - ptr as usize }, + 72usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(vdso) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).entry) as usize - ptr as usize }, + 80usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(entry) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).code_offset) as usize - ptr as usize }, + 88usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(code_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).data_offset) as usize - ptr as usize }, + 96usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(data_offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).saved_auxv) as usize - ptr as usize }, + 104usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(saved_auxv) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).auxv_len) as usize - ptr as usize }, + 112usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(auxv_len) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).argc) as usize - ptr as usize }, + 120usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(argc) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).argv) as usize - ptr as usize }, + 128usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(argv) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).envc) as usize - ptr as usize }, + 136usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(envc) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).envp) as usize - ptr as usize }, + 144usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(envp) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).file_string) as usize - ptr as usize }, + 152usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(file_string) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).elf_flags) as usize - ptr as usize }, + 160usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(elf_flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).personality) as usize - ptr as usize }, + 164usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(personality) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).alignment) as usize - ptr as usize }, + 168usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(alignment) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).exec_stack) as usize - ptr as usize }, + 176usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(exec_stack) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).arg_strings) as usize - ptr as usize }, + 184usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(arg_strings) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).env_strings) as usize - ptr as usize }, + 192usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(env_strings) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).loadmap_addr) as usize - ptr as usize }, + 200usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(loadmap_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).nsegs) as usize - ptr as usize }, + 208usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(nsegs) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).loadsegs) as usize - ptr as usize }, + 216usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(loadsegs) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).pt_dynamic_addr) as usize - ptr as usize }, + 224usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(pt_dynamic_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).interpreter_loadmap_addr) as usize - ptr as usize }, + 232usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(interpreter_loadmap_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).interpreter_pt_dynamic_addr) as usize - ptr as usize }, + 240usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(interpreter_pt_dynamic_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).other_info) as usize - ptr as usize }, + 248usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(other_info) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).note_flags) as usize - ptr as usize }, + 256usize, + concat!( + "Offset of field: ", + stringify!(image_info), + "::", + stringify!(note_flags) + ) + ); +} +impl Default for image_info { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct tb_tc { pub ptr: *const ::std::os::raw::c_void, pub size: usize, @@ -12900,9 +13302,6 @@ extern "C" { #[doc = " free_self_maps:\n @info: an interval tree\n\n Free a tree of MapInfo structures."] pub fn free_self_maps(root: *mut IntervalTreeRoot); } -extern "C" { - pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong); -} extern "C" { pub fn libafl_qemu_set_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; } @@ -13330,6 +13729,9 @@ impl Default for libafl_mapinfo { } } } +extern "C" { + pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int); +} extern "C" { pub fn libafl_qemu_handle_crash( host_sig: ::std::os::raw::c_int, @@ -13347,6 +13749,18 @@ extern "C" { ret: *mut libafl_mapinfo, ) -> *mut IntervalTreeNode; } +extern "C" { + pub fn libafl_load_addr() -> u64; +} +extern "C" { + pub fn libafl_get_image_info() -> *mut image_info; +} +extern "C" { + pub fn libafl_get_brk() -> u64; +} +extern "C" { + pub fn libafl_set_brk(new_brk: u64) -> u64; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct AccelCPUClass { @@ -14389,6 +14803,71 @@ extern "C" { data: *mut qemu_plugin_hwaddr, ) -> bool; } +extern "C" { + pub fn libafl_page_from_addr(addr: target_ulong) -> target_ulong; +} +extern "C" { + pub fn libafl_qemu_get_cpu(cpu_index: ::std::os::raw::c_int) -> *mut CPUState; +} +extern "C" { + pub fn libafl_qemu_num_cpus() -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_current_cpu() -> *mut CPUState; +} +extern "C" { + pub fn libafl_qemu_cpu_index(arg1: *mut CPUState) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_write_reg( + cpu: *mut CPUState, + reg: ::std::os::raw::c_int, + val: *mut u8, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_read_reg( + cpu: *mut CPUState, + reg: ::std::os::raw::c_int, + val: *mut u8, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_num_regs(cpu: *mut CPUState) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_flush_jit(); +} +extern "C" { + pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong); +} +extern "C" { + pub fn libafl_qemu_main() -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_qemu_run() -> ::std::os::raw::c_int; +} +extern "C" { + pub fn libafl_set_qemu_env(env: *mut CPUArchState); +} +extern "C" { + pub fn libafl_qemu_add_gdb_cmd( + callback: ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut ::std::os::raw::c_void, + arg2: *mut u8, + arg3: usize, + ) -> bool, + >, + data: *mut ::std::os::raw::c_void, + ); +} +extern "C" { + pub fn libafl_qemu_gdb_reply(buf: *const u8, len: usize); +} +extern "C" { + pub fn libafl_qemu_gdb_exec() -> bool; +} extern "C" { pub fn libafl_jit_trace_edge_hitcount(data: u64, id: u64) -> usize; } diff --git a/libafl_qemu/src/breakpoint.rs b/libafl_qemu/src/breakpoint.rs index 3c7459b9e8..4a857b2f1c 100644 --- a/libafl_qemu/src/breakpoint.rs +++ b/libafl_qemu/src/breakpoint.rs @@ -9,14 +9,10 @@ use std::{ }, }; -use libafl::state::{HasExecutions, State}; +use libafl::inputs::UsesInput; use libafl_qemu_sys::GuestAddr; -use crate::{ - command::{CommandManager, IsCommand}, - modules::EmulatorModuleTuple, - EmulatorExitHandler, Qemu, -}; +use crate::{command::IsCommand, Qemu}; #[repr(transparent)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -26,10 +22,7 @@ pub struct BreakpointId(u64); #[derive(Debug)] pub struct Breakpoint where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { id: BreakpointId, addr: GuestAddr, @@ -56,10 +49,7 @@ impl Default for BreakpointId { impl Hash for Breakpoint where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn hash(&self, state: &mut H) { self.id.hash(state); @@ -68,31 +58,18 @@ where impl PartialEq for Breakpoint where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn eq(&self, other: &Self) -> bool { self.id == other.id } } -impl Eq for Breakpoint -where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, -{ -} +impl Eq for Breakpoint where S: UsesInput {} impl Display for Breakpoint where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "Breakpoint @vaddr 0x{:x}", self.addr) @@ -101,10 +78,7 @@ where impl Borrow for Breakpoint where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn borrow(&self) -> &BreakpointId { &self.id @@ -113,10 +87,7 @@ where impl Borrow for Breakpoint where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn borrow(&self) -> &GuestAddr { &self.addr @@ -125,10 +96,7 @@ where impl Breakpoint where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { // Emu will return with the breakpoint as exit reason. #[must_use] diff --git a/libafl_qemu/src/command/mod.rs b/libafl_qemu/src/command/mod.rs index 2f74072a91..c0d1626989 100644 --- a/libafl_qemu/src/command/mod.rs +++ b/libafl_qemu/src/command/mod.rs @@ -9,8 +9,7 @@ use hashbrown::HashMap; use hashbrown::HashSet; use libafl::{ executors::ExitKind, - inputs::HasTargetBytes, - state::{HasExecutions, State}, + inputs::{HasTargetBytes, UsesInput}, }; use libafl_bolts::AsSlice; use num_enum::TryFromPrimitive; @@ -25,12 +24,11 @@ use crate::{ }, get_exit_arch_regs, modules::{ - EmulatorModuleTuple, HasInstrumentationFilter, IsFilter, - QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter, + HasInstrumentationFilter, QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter, }, sync_exit::ExitArgs, - Emulator, EmulatorExitHandler, ExitHandlerError, ExitHandlerResult, GuestReg, InputLocation, - IsSnapshotManager, Qemu, QemuMemoryChunk, QemuRWError, Regs, StdEmulatorExitHandler, CPU, + Emulator, ExitHandlerError, ExitHandlerResult, GuestReg, InputLocation, IsSnapshotManager, + Qemu, QemuMemoryChunk, QemuRWError, Regs, StdEmulatorExitHandler, CPU, }; pub mod parser; @@ -55,10 +53,7 @@ macro_rules! define_std_command_manager { ($name:ident, [$($native_command_parser:ident),+]) => { pub struct $name where - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + S: UsesInput, { native_command_parsers: HashMap, ET, S>>>, @@ -66,8 +61,8 @@ macro_rules! define_std_command_manager { impl $name where - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + ET: StdInstrumentationFilter + Unpin, + S: UsesInput + Unpin, S::Input: HasTargetBytes, SM: IsSnapshotManager, { @@ -105,10 +100,7 @@ macro_rules! define_std_command_manager { impl CommandManager, ET, S> for $name where - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + S: UsesInput, { fn parse( &self, @@ -129,10 +121,7 @@ macro_rules! define_std_command_manager { impl Debug for $name where - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + S: UsesInput, { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { write!(f, stringify!($name)) @@ -141,8 +130,8 @@ macro_rules! define_std_command_manager { impl Default for $name where - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + ET: StdInstrumentationFilter + Unpin, + S: UsesInput + Unpin, S::Input: HasTargetBytes, SM: IsSnapshotManager, { @@ -157,9 +146,7 @@ pub struct NopCommandManager; impl CommandManager for NopCommandManager where - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn parse(&self, _qemu: Qemu) -> Result>, CommandError> { Ok(Rc::new(NopCommand)) @@ -183,9 +170,7 @@ define_std_command_manager!( pub trait CommandManager: Sized where - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn parse(&self, qemu: Qemu) -> Result>, CommandError>; } @@ -200,10 +185,7 @@ pub enum NativeExitKind { pub trait IsCommand: Debug + Display where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { /// Used to know whether the command can be run during a backdoor, or if it is necessary to go out of /// the QEMU VM to run the command. @@ -251,10 +233,7 @@ impl Display for NopCommand { impl IsCommand for NopCommand where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn usable_at_runtime(&self) -> bool { true @@ -275,10 +254,8 @@ pub struct SaveCommand; impl IsCommand, ET, S> for SaveCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, + ET: StdInstrumentationFilter + Unpin, + S: UsesInput + Unpin, SM: IsSnapshotManager, { fn usable_at_runtime(&self) -> bool { @@ -329,10 +306,7 @@ pub struct LoadCommand; impl IsCommand, ET, S> for LoadCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, + S: UsesInput, SM: IsSnapshotManager, { fn usable_at_runtime(&self) -> bool { @@ -374,11 +348,8 @@ pub struct InputCommand { impl IsCommand, ET, S> for InputCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + S: UsesInput, S::Input: HasTargetBytes, - SM: IsSnapshotManager, { fn usable_at_runtime(&self) -> bool { true @@ -410,9 +381,7 @@ pub struct StartCommand { impl IsCommand, ET, S> for StartCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + S: UsesInput, S::Input: HasTargetBytes, SM: IsSnapshotManager, { @@ -460,10 +429,7 @@ pub struct EndCommand(Option); impl IsCommand, ET, S> for EndCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, + S: UsesInput, SM: IsSnapshotManager, { fn usable_at_runtime(&self) -> bool { @@ -501,11 +467,7 @@ pub struct VersionCommand(u64); impl IsCommand, ET, S> for VersionCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + S: UsesInput, { fn usable_at_runtime(&self) -> bool { true @@ -531,21 +493,15 @@ where } #[derive(Debug, Clone)] -pub struct FilterCommand -where - T: IsFilter + Debug, -{ +pub struct FilterCommand { filter: T, } #[cfg(emulation_mode = "systemmode")] impl IsCommand, ET, S> for PagingFilterCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + ET: StdInstrumentationFilter + Unpin, + S: UsesInput + Unpin, { fn usable_at_runtime(&self) -> bool { true @@ -571,11 +527,7 @@ where impl IsCommand, ET, S> for AddressRangeFilterCommand where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + S: UsesInput, { fn usable_at_runtime(&self) -> bool { true @@ -609,10 +561,7 @@ impl VersionCommand { } } -impl FilterCommand -where - T: IsFilter + Debug, -{ +impl FilterCommand { pub fn new(filter: T) -> Self { Self { filter } } diff --git a/libafl_qemu/src/command/parser.rs b/libafl_qemu/src/command/parser.rs index 6a2d695cb5..a1331aef89 100644 --- a/libafl_qemu/src/command/parser.rs +++ b/libafl_qemu/src/command/parser.rs @@ -1,34 +1,27 @@ -use std::{fmt::Debug, rc::Rc, sync::OnceLock}; +use std::{rc::Rc, sync::OnceLock}; use enum_map::{enum_map, EnumMap}; use libafl::{ executors::ExitKind, - inputs::HasTargetBytes, - state::{HasExecutions, State}, + inputs::{HasTargetBytes, UsesInput}, }; use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr}; use crate::{ command::{ - bindings, CommandError, CommandManager, EndCommand, FilterCommand, InputCommand, IsCommand, - LoadCommand, NativeExitKind, SaveCommand, StartCommand, VersionCommand, - }, - modules::{ - EmulatorModuleTuple, QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter, + bindings, CommandError, EndCommand, FilterCommand, InputCommand, IsCommand, LoadCommand, + NativeExitKind, SaveCommand, StartCommand, VersionCommand, }, + modules::{QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter}, sync_exit::ExitArgs, - EmulatorExitHandler, GuestReg, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs, - StdEmulatorExitHandler, + GuestReg, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs, StdEmulatorExitHandler, }; pub static EMU_EXIT_KIND_MAP: OnceLock>> = OnceLock::new(); pub trait NativeCommandParser where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn command_id(&self) -> GuestReg; @@ -43,11 +36,8 @@ pub struct InputPhysCommandParser; impl NativeCommandParser, ET, S> for InputPhysCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + S: UsesInput, S::Input: HasTargetBytes, - SM: IsSnapshotManager, { fn command_id(&self) -> GuestReg { GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_PHYS.0) @@ -76,11 +66,8 @@ pub struct InputVirtCommandParser; impl NativeCommandParser, ET, S> for InputVirtCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + S: UsesInput, S::Input: HasTargetBytes, - SM: IsSnapshotManager, { fn command_id(&self) -> GuestReg { GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_VIRT.0) @@ -105,9 +92,7 @@ pub struct StartPhysCommandParser; impl NativeCommandParser, ET, S> for StartPhysCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + S: UsesInput, S::Input: HasTargetBytes, SM: IsSnapshotManager, { @@ -135,9 +120,7 @@ pub struct StartVirtCommandParser; impl NativeCommandParser, ET, S> for StartVirtCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + S: UsesInput, S::Input: HasTargetBytes, SM: IsSnapshotManager, { @@ -164,10 +147,8 @@ where pub struct SaveCommandParser; impl NativeCommandParser, ET, S> for SaveCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, + ET: StdInstrumentationFilter + Unpin, + S: UsesInput + Unpin, SM: IsSnapshotManager, { fn command_id(&self) -> GuestReg { @@ -186,10 +167,7 @@ where pub struct LoadCommandParser; impl NativeCommandParser, ET, S> for LoadCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, + S: UsesInput, SM: IsSnapshotManager, { fn command_id(&self) -> GuestReg { @@ -208,10 +186,7 @@ where pub struct EndCommandParser; impl NativeCommandParser, ET, S> for EndCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, + S: UsesInput, SM: IsSnapshotManager, { fn command_id(&self) -> GuestReg { @@ -244,11 +219,7 @@ pub struct VersionCommandParser; impl NativeCommandParser, ET, S> for VersionCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + S: UsesInput, { fn command_id(&self) -> GuestReg { GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VERSION.0) @@ -269,11 +240,7 @@ pub struct VaddrFilterAllowRangeCommandParser; impl NativeCommandParser, ET, S> for VaddrFilterAllowRangeCommandParser where - CM: CommandManager, ET, S>, - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, - S::Input: HasTargetBytes, - SM: IsSnapshotManager, + S: UsesInput, { fn command_id(&self) -> GuestReg { GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VADDR_FILTER_ALLOW.0) diff --git a/libafl_qemu/src/emu/hooks.rs b/libafl_qemu/src/emu/hooks.rs index 2de17a65ca..550417b62a 100644 --- a/libafl_qemu/src/emu/hooks.rs +++ b/libafl_qemu/src/emu/hooks.rs @@ -99,8 +99,7 @@ where #[derive(Debug)] pub struct EmulatorModules where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput, { qemu: Qemu, modules: Pin>, @@ -112,8 +111,7 @@ where #[derive(Debug)] pub struct EmulatorHooks where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput, { qemu_hooks: QemuHooks, phantom: PhantomData<(ET, S)>, @@ -143,8 +141,7 @@ where impl EmulatorHooks where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { #[must_use] pub fn new(qemu_hooks: QemuHooks) -> Self { @@ -886,7 +883,6 @@ where impl Default for EmulatorHooks where - ET: EmulatorModuleTuple, S: Unpin + UsesInput, { fn default() -> Self { @@ -896,112 +892,8 @@ where impl EmulatorModules where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput, { - pub(super) fn new(qemu: Qemu, modules: ET) -> Pin> { - let mut modules = Box::pin(Self { - qemu, - modules: Box::pin(modules), - hooks: EmulatorHooks::default(), - phantom: PhantomData, - }); - - // re-translate blocks with hooks - // qemu.flush_jit(); - // -> it should be useless, since EmulatorModules must be init before QEMU ever runs - - // Set global EmulatorModules pointer - unsafe { - if EMULATOR_TOOLS.is_null() { - EMULATOR_TOOLS = ptr::from_mut::(modules.as_mut().get_mut()) as *mut (); - } else { - panic!("Emulator Modules have already been set and is still active. It is not supported to have multiple instances of `EmulatorModules` at the same time yet.") - } - } - - unsafe { - // We give access to EmulatorModuleTuple during init, the compiler complains (for good reasons) - // TODO: We should find a way to be able to check for a module without giving full access to the tuple. - modules - .modules - .init_modules_all(Self::emulator_modules_mut_unchecked()); - } - - modules - } - - #[must_use] - pub fn qemu(&self) -> Qemu { - self.qemu - } - - #[must_use] - pub fn modules(&self) -> &ET { - self.modules.as_ref().get_ref() - } - - pub fn modules_mut(&mut self) -> &mut ET { - self.modules.as_mut().get_mut() - } - - pub fn hooks_mut(&mut self) -> &mut EmulatorHooks { - &mut self.hooks - } - - pub fn first_exec_all(&mut self) { - unsafe { - self.modules - .as_mut() - .get_mut() - .first_exec_all(Self::emulator_modules_mut_unchecked()); - } - } - - pub fn pre_exec_all(&mut self, input: &S::Input) { - unsafe { - self.modules - .as_mut() - .get_mut() - .pre_exec_all(Self::emulator_modules_mut_unchecked(), input); - } - } - - pub fn post_exec_all( - &mut self, - input: &S::Input, - observers: &mut OT, - exit_kind: &mut ExitKind, - ) where - OT: ObserversTuple, - { - unsafe { - self.modules.as_mut().get_mut().post_exec_all( - Self::emulator_modules_mut_unchecked(), - input, - observers, - exit_kind, - ); - } - } - - /// Get a reference to the first (type) matching member of the tuple. - #[must_use] - pub fn get(&self) -> Option<&T> - where - T: EmulatorModule, - { - self.modules.match_first_type::() - } - - /// Get a mutable reference to the first (type) matching member of the tuple. - pub fn get_mut(&mut self) -> Option<&mut T> - where - T: EmulatorModule, - { - self.modules.match_first_type_mut::() - } - /// Get a mutable reference to `EmulatorModules` (supposedly initialized beforehand). /// /// # Safety @@ -1037,6 +929,16 @@ where pub unsafe fn emulator_modules_mut<'a>() -> Option<&'a mut EmulatorModules> { unsafe { (EMULATOR_TOOLS as *mut EmulatorModules).as_mut() } } +} + +impl EmulatorModules +where + ET: Unpin, + S: UsesInput + Unpin, +{ + pub fn modules_mut(&mut self) -> &mut ET { + self.modules.as_mut().get_mut() + } pub fn instructions( &mut self, @@ -1154,6 +1056,113 @@ where } } +impl EmulatorModules +where + ET: EmulatorModuleTuple, + S: UsesInput + Unpin, +{ + pub(super) fn new(qemu: Qemu, modules: ET) -> Pin> { + let mut modules = Box::pin(Self { + qemu, + modules: Box::pin(modules), + hooks: EmulatorHooks::default(), + phantom: PhantomData, + }); + + // re-translate blocks with hooks + // qemu.flush_jit(); + // -> it should be useless, since EmulatorModules must be init before QEMU ever runs + // TODO: Check if this is true + + // Set global EmulatorModules pointer + unsafe { + if EMULATOR_TOOLS.is_null() { + EMULATOR_TOOLS = ptr::from_mut::(modules.as_mut().get_mut()) as *mut (); + } else { + panic!("Emulator Modules have already been set and is still active. It is not supported to have multiple instances of `EmulatorModules` at the same time yet.") + } + } + + unsafe { + // We give access to EmulatorModuleTuple during init, the compiler complains (for good reasons) + // TODO: We should find a way to be able to check for a module without giving full access to the tuple. + modules + .modules + .init_modules_all(Self::emulator_modules_mut_unchecked()); + } + + modules + } + + pub fn first_exec_all(&mut self) { + unsafe { + self.modules_mut() + .first_exec_all(Self::emulator_modules_mut_unchecked()); + } + } + + pub fn pre_exec_all(&mut self, input: &S::Input) { + unsafe { + self.modules_mut() + .pre_exec_all(Self::emulator_modules_mut_unchecked(), input); + } + } + + pub fn post_exec_all( + &mut self, + input: &S::Input, + observers: &mut OT, + exit_kind: &mut ExitKind, + ) where + OT: ObserversTuple, + { + unsafe { + self.modules_mut().post_exec_all( + Self::emulator_modules_mut_unchecked(), + input, + observers, + exit_kind, + ); + } + } + + /// Get a reference to the first (type) matching member of the tuple. + #[must_use] + pub fn get(&self) -> Option<&T> + where + T: EmulatorModule, + { + self.modules.match_first_type::() + } + + /// Get a mutable reference to the first (type) matching member of the tuple. + pub fn get_mut(&mut self) -> Option<&mut T> + where + T: EmulatorModule, + { + self.modules.match_first_type_mut::() + } +} + +impl EmulatorModules +where + S: UsesInput, +{ + #[must_use] + pub fn qemu(&self) -> Qemu { + self.qemu + } + + #[must_use] + pub fn modules(&self) -> &ET { + self.modules.as_ref().get_ref() + } + + pub fn hooks_mut(&mut self) -> &mut EmulatorHooks { + &mut self.hooks + } +} + /// Usermode-only high-level functions #[cfg(emulation_mode = "usermode")] impl EmulatorModules @@ -1290,8 +1299,7 @@ where impl Drop for EmulatorModules where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput, { fn drop(&mut self) { // Make the global pointer null at drop time diff --git a/libafl_qemu/src/emu/mod.rs b/libafl_qemu/src/emu/mod.rs index a0ec4efda5..60dde0c79a 100644 --- a/libafl_qemu/src/emu/mod.rs +++ b/libafl_qemu/src/emu/mod.rs @@ -17,24 +17,20 @@ use std::{ use hashbrown::HashMap; use libafl::{ executors::ExitKind, - inputs::HasTargetBytes, + inputs::{HasTargetBytes, UsesInput}, observers::ObserversTuple, - state::{HasExecutions, State}, }; use libafl_bolts::os::unix_signals::Signal; -use libafl_qemu_sys::GuestUsize; -pub use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr}; -#[cfg(emulation_mode = "usermode")] -pub use libafl_qemu_sys::{MapInfo, MmapPerms, MmapPermsIter}; -use num_traits::Num; +use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestUsize, GuestVirtAddr}; use typed_builder::TypedBuilder; use crate::{ - breakpoint::Breakpoint, - command::{CommandError, InputCommand, IsCommand}, + breakpoint::{Breakpoint, BreakpointId}, + command::{CommandError, CommandManager, InputCommand, IsCommand}, + modules::EmulatorModuleTuple, sync_exit::SyncExit, - GuestReg, Qemu, QemuExitError, QemuExitReason, QemuInitError, QemuMemoryChunk, QemuRWError, - QemuShutdownCause, QemuSnapshotCheckResult, Regs, CPU, + Qemu, QemuExitError, QemuExitReason, QemuInitError, QemuMemoryChunk, QemuShutdownCause, + QemuSnapshotCheckResult, Regs, CPU, }; mod hooks; @@ -48,15 +44,52 @@ mod systemmode; #[cfg(emulation_mode = "systemmode")] pub use systemmode::*; -use crate::{ - breakpoint::BreakpointId, - command::CommandManager, - modules::{EmulatorModuleTuple, StdInstrumentationFilter}, -}; - type CommandRef = Rc>; type BreakpointMutRef = Rc>>; +pub trait IsSnapshotManager: Clone + Debug { + fn save(&mut self, qemu: Qemu) -> SnapshotId; + fn restore(&mut self, snapshot_id: &SnapshotId, qemu: Qemu) + -> Result<(), SnapshotManagerError>; + fn do_check( + &self, + reference_snapshot_id: &SnapshotId, + qemu: Qemu, + ) -> Result; + + fn check( + &self, + reference_snapshot_id: &SnapshotId, + qemu: Qemu, + ) -> Result<(), SnapshotManagerCheckError> { + let check_result = self + .do_check(reference_snapshot_id, qemu) + .map_err(SnapshotManagerCheckError::SnapshotManagerError)?; + + if check_result == QemuSnapshotCheckResult::default() { + Ok(()) + } else { + Err(SnapshotManagerCheckError::SnapshotCheckError(check_result)) + } + } +} + +pub trait EmulatorExitHandler: Sized + Debug + Clone +where + S: UsesInput, +{ + fn qemu_pre_exec>( + emu: &mut Emulator, + input: &S::Input, + ); + + fn qemu_post_exec>( + emu: &mut Emulator, + exit_reason: Result, EmulatorExitError>, + input: &S::Input, + ) -> Result>, ExitHandlerError>; +} + #[derive(Clone, Copy)] pub enum GuestAddrKind { Physical(GuestPhysAddr), @@ -66,10 +99,7 @@ pub enum GuestAddrKind { #[derive(Debug, Clone)] pub enum EmulatorExitResult where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { QemuExit(QemuShutdownCause), // QEMU ended for some reason. Breakpoint(Rc>>), // Breakpoint triggered. Contains the address of the trigger. @@ -84,35 +114,6 @@ pub enum EmulatorExitError { BreakpointNotFound(GuestAddr), } -#[derive(Debug, Clone)] -pub enum ExitHandlerResult -where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, -{ - ReturnToHarness(EmulatorExitResult), // Return to the harness immediately. Can happen at any point of the run when the handler is not supposed to handle a request. - EndOfRun(ExitKind), // The run is over and the emulator is ready for the next iteration. -} - -impl ExitHandlerResult -where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, -{ - #[must_use] - #[allow(clippy::match_wildcard_for_single_variants)] - pub fn end_of_run(&self) -> Option { - match self { - ExitHandlerResult::EndOfRun(exit_kind) => Some(*exit_kind), - _ => None, - } - } -} - #[derive(Debug, Clone)] pub enum ExitHandlerError { QemuExitReasonError(EmulatorExitError), @@ -125,6 +126,15 @@ pub enum ExitHandlerError { SnapshotNotFound, } +#[derive(Debug, Clone)] +pub enum ExitHandlerResult +where + S: UsesInput, +{ + ReturnToHarness(EmulatorExitResult), // Return to the harness immediately. Can happen at any point of the run when the handler is not supposed to handle a request. + EndOfRun(ExitKind), // The run is over and the emulator is ready for the next iteration. +} + #[derive(Debug, Clone)] pub enum SnapshotManagerError { SnapshotIdNotFound(SnapshotId), @@ -137,12 +147,95 @@ pub enum SnapshotManagerCheckError { SnapshotCheckError(QemuSnapshotCheckResult), } +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct SnapshotId { + id: u64, +} + +/// Special kind of Exit handler with no data embedded. +/// As a result, it is safe to transmute from any `Emulator` implementing `EmuExitHandler` to this one, +/// since it won't use any data which could cause type confusion. +#[derive(Clone, Debug)] +pub struct NopEmulatorExitHandler; +impl EmulatorExitHandler for NopEmulatorExitHandler +where + S: UsesInput, +{ + fn qemu_pre_exec>( + _: &mut Emulator, + _: &S::Input, + ) { + } + + fn qemu_post_exec>( + _: &mut Emulator, + exit_reason: Result, EmulatorExitError>, + _: &S::Input, + ) -> Result>, ExitHandlerError> { + match exit_reason { + Ok(reason) => Ok(Some(ExitHandlerResult::ReturnToHarness(reason))), + Err(error) => Err(error)?, + } + } +} + +#[derive(Debug, Clone)] +pub struct InputLocation { + mem_chunk: QemuMemoryChunk, + cpu: CPU, + ret_register: Option, +} + +/// Synchronous Exit handler maintaining only one snapshot. +#[derive(Debug, Clone, TypedBuilder)] +pub struct StdEmulatorExitHandler { + snapshot_manager: RefCell, + #[builder(default)] + snapshot_id: OnceCell, + #[builder(default)] + input_location: OnceCell, +} + +// TODO: Replace TypedBuilder by something better, it does not work correctly with default and +// inter-dependent fields. +#[derive(Debug, TypedBuilder)] +pub struct Emulator +where + S: UsesInput, +{ + modules: Pin>>, + command_manager: CM, + exit_handler: RefCell, + #[builder(default)] + breakpoints_by_addr: RefCell>>, + #[builder(default)] + breakpoints_by_id: RefCell>>, + #[builder(setter(transform = |args: &[String], env: &[(String, String)]| Qemu::init(args, env).unwrap()))] + qemu: Qemu, + first_exec: bool, + _phantom: PhantomData<(ET, S)>, +} + +impl ExitHandlerResult +where + S: UsesInput, +{ + #[must_use] + #[allow(clippy::match_wildcard_for_single_variants)] + pub fn end_of_run(&self) -> Option { + match self { + ExitHandlerResult::EndOfRun(exit_kind) => Some(*exit_kind), + _ => None, + } + } +} + impl TryFrom> for ExitKind where - CM: CommandManager + Debug, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple + Debug, - S: Unpin + State + HasExecutions + Debug, + CM: Debug, + EH: Debug, + ET: Debug, + S: UsesInput + Debug, { type Error = String; @@ -197,91 +290,6 @@ impl From for ExitHandlerError { } } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct SnapshotId { - id: u64, -} - -pub trait IsSnapshotManager: Debug + Clone { - fn save(&mut self, qemu: Qemu) -> SnapshotId; - fn restore(&mut self, snapshot_id: &SnapshotId, qemu: Qemu) - -> Result<(), SnapshotManagerError>; - fn do_check( - &self, - reference_snapshot_id: &SnapshotId, - qemu: Qemu, - ) -> Result; - - fn check( - &self, - reference_snapshot_id: &SnapshotId, - qemu: Qemu, - ) -> Result<(), SnapshotManagerCheckError> { - let check_result = self - .do_check(reference_snapshot_id, qemu) - .map_err(SnapshotManagerCheckError::SnapshotManagerError)?; - - if check_result == QemuSnapshotCheckResult::default() { - Ok(()) - } else { - Err(SnapshotManagerCheckError::SnapshotCheckError(check_result)) - } - } -} - -pub trait EmulatorExitHandler: Sized + Debug + Clone -where - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, -{ - fn qemu_pre_exec>( - emu: &mut Emulator, - input: &S::Input, - ); - - fn qemu_post_exec>( - emu: &mut Emulator, - exit_reason: Result, EmulatorExitError>, - input: &S::Input, - ) -> Result>, ExitHandlerError>; -} - -/// Special kind of Exit handler with no data embedded. -/// As a result, it is safe to transmute from any `Emulator` implementing `EmuExitHandler` to this one, -/// since it won't use any data which could cause type confusion. -#[derive(Clone, Debug)] -pub struct NopEmulatorExitHandler; - -impl EmulatorExitHandler for NopEmulatorExitHandler -where - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, -{ - fn qemu_pre_exec>( - _: &mut Emulator, - _: &S::Input, - ) { - } - - fn qemu_post_exec>( - _: &mut Emulator, - exit_reason: Result, EmulatorExitError>, - _: &S::Input, - ) -> Result>, ExitHandlerError> { - match exit_reason { - Ok(reason) => Ok(Some(ExitHandlerResult::ReturnToHarness(reason))), - Err(error) => Err(error)?, - } - } -} - -#[derive(Debug, Clone)] -pub struct InputLocation { - mem_chunk: QemuMemoryChunk, - cpu: CPU, - ret_register: Option, -} - impl InputLocation { #[must_use] pub fn new(mem_chunk: QemuMemoryChunk, cpu: CPU, ret_register: Option) -> Self { @@ -293,23 +301,7 @@ impl InputLocation { } } -/// Synchronous Exit handler maintaining only one snapshot. -#[derive(Debug, Clone, TypedBuilder)] -pub struct StdEmulatorExitHandler -where - SM: IsSnapshotManager + Clone, -{ - snapshot_manager: RefCell, - #[builder(default)] - snapshot_id: OnceCell, - #[builder(default)] - input_location: OnceCell, -} - -impl StdEmulatorExitHandler -where - SM: IsSnapshotManager, -{ +impl StdEmulatorExitHandler { pub fn new(snapshot_manager: SM) -> Self { Self { snapshot_manager: RefCell::new(snapshot_manager), @@ -342,8 +334,7 @@ where // TODO: replace handlers with generics to permit compile-time customization of handlers impl EmulatorExitHandler for StdEmulatorExitHandler where - ET: EmulatorModuleTuple + StdInstrumentationFilter + Debug, - S: Unpin + State + HasExecutions, + S: UsesInput, S::Input: HasTargetBytes, SM: IsSnapshotManager, { @@ -436,10 +427,7 @@ impl From for ExitHandlerError { impl Display for EmulatorExitResult where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -458,36 +446,20 @@ impl From for EmulatorExitError { } } -// TODO: Replace TypedBuilder by something better, it does not work correctly with default and -// inter-dependent fields. -#[derive(Debug, TypedBuilder)] -pub struct Emulator -where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, -{ - modules: Pin>>, - command_manager: CM, - exit_handler: RefCell, - #[builder(default)] - breakpoints_by_addr: RefCell>>, - #[builder(default)] - breakpoints_by_id: RefCell>>, - #[builder(setter(transform = |args: &[String], env: &[(String, String)]| Qemu::init(args, env).unwrap()))] - qemu: Qemu, - first_exec: bool, - _phantom: PhantomData<(ET, S)>, -} - -#[allow(clippy::unused_self)] impl Emulator where - CM: CommandManager, - EH: EmulatorExitHandler, + ET: Unpin, + S: UsesInput + Unpin, +{ + pub fn modules_mut(&mut self) -> &mut EmulatorModules { + self.modules.as_mut().get_mut() + } +} + +impl Emulator +where ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput + Unpin, { #[allow(clippy::must_use_candidate, clippy::similar_names)] pub fn new( @@ -520,12 +492,35 @@ where }) } - pub fn modules(&self) -> &EmulatorModules { - &self.modules + pub fn first_exec_all(&mut self) { + if self.first_exec { + self.modules.first_exec_all(); + self.first_exec = false; + } } - pub fn modules_mut(&mut self) -> &mut EmulatorModules { - self.modules.as_mut().get_mut() + pub fn pre_exec_all(&mut self, input: &S::Input) { + self.modules.pre_exec_all(input); + } + + pub fn post_exec_all( + &mut self, + input: &S::Input, + observers: &mut OT, + exit_kind: &mut ExitKind, + ) where + OT: ObserversTuple, + { + self.modules.post_exec_all(input, observers, exit_kind); + } +} + +impl Emulator +where + S: UsesInput, +{ + pub fn modules(&self) -> &EmulatorModules { + &self.modules } #[must_use] @@ -537,91 +532,85 @@ where pub fn exit_handler(&self) -> &RefCell { &self.exit_handler } +} - #[must_use] - #[allow(clippy::cast_possible_wrap)] - #[allow(clippy::cast_sign_loss)] - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn num_cpus(&self) -> usize { - self.qemu.num_cpus() +impl Emulator +where + EH: EmulatorExitHandler, + CM: CommandManager, + S: UsesInput, +{ + /// This function will run the emulator until the exit handler decides to stop the execution for + /// whatever reason, depending on the choosen handler. + /// It is a higher-level abstraction of [`Emulator::run`] that will take care of some part of the runtime logic, + /// returning only when something interesting happen. + /// + /// # Safety + /// Should, in general, be safe to call. + /// Of course, the emulated target is not contained securely and can corrupt state or interact with the operating system. + pub unsafe fn run( + &mut self, + input: &S::Input, + ) -> Result, ExitHandlerError> { + loop { + // if self.first_exec { + // self.modules_mut().first_exec_all(); + // self.first_exec = false; + // } + + // // First run modules callback functions + // self.modules_mut().pre_exec_all(input); + + // Insert input if the location is already known + EH::qemu_pre_exec(self, input); + + // Run QEMU + let exit_reason = self.run_qemu(); + + // Handle QEMU exit + if let Some(exit_handler_result) = EH::qemu_post_exec(self, exit_reason, input)? { + return Ok(exit_handler_result); + } + } } - #[must_use] - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn current_cpu(&self) -> Option { - self.qemu.current_cpu() - } - - #[must_use] - #[allow(clippy::cast_possible_wrap)] - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn cpu_from_index(&self, index: usize) -> CPU { - self.qemu.cpu_from_index(index) - } - - #[must_use] - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn page_from_addr(&self, addr: GuestAddr) -> GuestAddr { - self.qemu.page_from_addr(addr) - } - - //#[must_use] - /*pub fn page_size() -> GuestUsize { - unsafe { libafl_page_size } - }*/ - - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub unsafe fn write_mem(&self, addr: GuestAddr, buf: &[u8]) { - self.qemu.write_mem(addr, buf); - } - - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub unsafe fn read_mem(&self, addr: GuestAddr, buf: &mut [u8]) { - self.qemu.read_mem(addr, buf); - } - - #[must_use] - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn num_regs(&self) -> i32 { - self.qemu.num_regs() - } - - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn write_reg(&self, reg: R, val: T) -> Result<(), QemuRWError> - where - T: Num + PartialOrd + Copy + Into, - R: Into + Clone, - { - self.qemu.write_reg(reg, val) - } - - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn read_reg(&self, reg: R) -> Result - where - T: Num + PartialOrd + Copy + From, - R: Into + Clone, - { - self.qemu.read_reg(reg) + /// This function will run the emulator until the next breakpoint, or until finish. + /// # Safety + /// + /// Should, in general, be safe to call. + /// Of course, the emulated target is not contained securely and can corrupt state or interact with the operating system. + pub unsafe fn run_qemu(&self) -> Result, EmulatorExitError> { + match self.qemu.run() { + Ok(qemu_exit_reason) => Ok(match qemu_exit_reason { + QemuExitReason::End(qemu_shutdown_cause) => { + EmulatorExitResult::QemuExit(qemu_shutdown_cause) + } + QemuExitReason::Breakpoint(bp_addr) => { + let bp = self + .breakpoints_by_addr + .borrow() + .get(&bp_addr) + .ok_or(EmulatorExitError::BreakpointNotFound(bp_addr))? + .clone(); + EmulatorExitResult::Breakpoint(bp.clone()) + } + QemuExitReason::SyncExit => EmulatorExitResult::SyncExit(Rc::new(RefCell::new( + SyncExit::new(self.command_manager.parse(self.qemu)?), + ))), + }), + Err(qemu_exit_reason_error) => Err(match qemu_exit_reason_error { + QemuExitError::UnexpectedExit => EmulatorExitError::UnexpectedExit, + QemuExitError::UnknownKind => EmulatorExitError::UnknownKind, + }), + } } +} +#[allow(clippy::unused_self)] +impl Emulator +where + S: UsesInput, +{ pub fn add_breakpoint(&self, mut bp: Breakpoint, enable: bool) -> BreakpointId { if enable { bp.enable(self.qemu); @@ -671,120 +660,4 @@ where .remove(&bp_addr) .expect("Could not remove bp"); } - - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn entry_break(&self, addr: GuestAddr) { - self.qemu.entry_break(addr); - } - - pub fn first_exec_all(&mut self) { - if self.first_exec { - self.modules.first_exec_all(); - self.first_exec = false; - } - } - - pub fn pre_exec_all(&mut self, input: &S::Input) { - self.modules.pre_exec_all(input); - } - - pub fn post_exec_all( - &mut self, - input: &S::Input, - observers: &mut OT, - exit_kind: &mut ExitKind, - ) where - OT: ObserversTuple, - { - self.modules.post_exec_all(input, observers, exit_kind); - } - - /// This function will run the emulator until the next breakpoint, or until finish. - /// # Safety - /// - /// Should, in general, be safe to call. - /// Of course, the emulated target is not contained securely and can corrupt state or interact with the operating system. - pub unsafe fn run_qemu(&self) -> Result, EmulatorExitError> { - match self.qemu.run() { - Ok(qemu_exit_reason) => Ok(match qemu_exit_reason { - QemuExitReason::End(qemu_shutdown_cause) => { - EmulatorExitResult::QemuExit(qemu_shutdown_cause) - } - QemuExitReason::Breakpoint(bp_addr) => { - let bp = self - .breakpoints_by_addr - .borrow() - .get(&bp_addr) - .ok_or(EmulatorExitError::BreakpointNotFound(bp_addr))? - .clone(); - EmulatorExitResult::Breakpoint(bp.clone()) - } - QemuExitReason::SyncExit => EmulatorExitResult::SyncExit(Rc::new(RefCell::new( - SyncExit::new(self.command_manager.parse(self.qemu)?), - ))), - }), - Err(qemu_exit_reason_error) => Err(match qemu_exit_reason_error { - QemuExitError::UnexpectedExit => EmulatorExitError::UnexpectedExit, - QemuExitError::UnknownKind => EmulatorExitError::UnknownKind, - }), - } - } - - /// This function will run the emulator until the exit handler decides to stop the execution for - /// whatever reason, depending on the choosen handler. - /// It is a higher-level abstraction of [`Emulator::run`] that will take care of some part of the runtime logic, - /// returning only when something interesting happen. - /// - /// # Safety - /// Should, in general, be safe to call. - /// Of course, the emulated target is not contained securely and can corrupt state or interact with the operating system. - pub unsafe fn run( - &mut self, - input: &S::Input, - ) -> Result, ExitHandlerError> { - loop { - // if self.first_exec { - // self.modules_mut().first_exec_all(); - // self.first_exec = false; - // } - - // // First run modules callback functions - // self.modules_mut().pre_exec_all(input); - - // Insert input if the location is already known - EH::qemu_pre_exec(self, input); - - // Run QEMU - let exit_reason = self.run_qemu(); - - // Handle QEMU exit - if let Some(exit_handler_result) = EH::qemu_post_exec(self, exit_reason, input)? { - return Ok(exit_handler_result); - } - } - } - - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn flush_jit(&self) { - self.qemu.flush_jit(); - } - - #[allow(clippy::type_complexity)] - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn add_gdb_cmd(&self, callback: Box bool>) { - self.qemu.add_gdb_cmd(callback); - } - - #[deprecated( - note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." - )] - pub fn gdb_reply(&self, output: &str) { - self.qemu.gdb_reply(output); - } } diff --git a/libafl_qemu/src/emu/systemmode.rs b/libafl_qemu/src/emu/systemmode.rs index f831a31f42..a3a4487602 100644 --- a/libafl_qemu/src/emu/systemmode.rs +++ b/libafl_qemu/src/emu/systemmode.rs @@ -4,13 +4,12 @@ use std::{ }; use hashbrown::HashMap; -use libafl::state::{HasExecutions, State}; +use libafl::inputs::UsesInput; use libafl_qemu_sys::GuestPhysAddr; use crate::{ - command::CommandManager, emu::IsSnapshotManager, modules::EmulatorModuleTuple, - DeviceSnapshotFilter, Emulator, EmulatorExitHandler, Qemu, QemuSnapshotCheckResult, SnapshotId, - SnapshotManagerError, + emu::IsSnapshotManager, DeviceSnapshotFilter, Emulator, Qemu, QemuSnapshotCheckResult, + SnapshotId, SnapshotManagerError, }; impl SnapshotId { @@ -173,10 +172,7 @@ impl IsSnapshotManager for FastSnapshotManager { impl Emulator where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { /// Write a value to a phsical guest address, including ROM areas. pub unsafe fn write_phys_mem(&self, paddr: GuestPhysAddr, buf: &[u8]) { diff --git a/libafl_qemu/src/emu/usermode.rs b/libafl_qemu/src/emu/usermode.rs index e28a8eb58a..f6c34f1afa 100644 --- a/libafl_qemu/src/emu/usermode.rs +++ b/libafl_qemu/src/emu/usermode.rs @@ -1,18 +1,11 @@ +use libafl::inputs::UsesInput; use libafl_qemu_sys::{GuestAddr, MmapPerms, VerifyAccess}; -use crate::{ - command::CommandManager, - emu::{HasExecutions, State}, - modules::EmulatorModuleTuple, - Emulator, EmulatorExitHandler, GuestMaps, -}; +use crate::{Emulator, GuestMaps}; impl Emulator where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { /// This function gets the memory mappings from the emulator. #[must_use] diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index d97772dcc3..0d178923e4 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -20,6 +20,7 @@ use libafl::{ }, feedbacks::Feedback, fuzzer::HasObjective, + inputs::UsesInput, observers::{ObserversTuple, UsesObservers}, state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState}, Error, ExecutionProcessor, HasScheduler, @@ -27,28 +28,26 @@ use libafl::{ #[cfg(feature = "fork")] use libafl_bolts::shmem::ShMemProvider; use libafl_bolts::{ - os::unix_signals::{siginfo_t, ucontext_t, Signal}, + os::unix_signals::{ucontext_t, Signal}, tuples::RefIndexable, }; +#[cfg(emulation_mode = "usermode")] +use libafl_qemu_sys::libafl_qemu_handle_crash; #[cfg(emulation_mode = "systemmode")] use libafl_qemu_sys::qemu_system_debug_request; +#[cfg(emulation_mode = "usermode")] +use libafl_qemu_sys::siginfo_t; +#[cfg(emulation_mode = "systemmode")] +use libc::siginfo_t; #[cfg(emulation_mode = "usermode")] use crate::EmulatorModules; use crate::{command::CommandManager, modules::EmulatorModuleTuple, Emulator, EmulatorExitHandler}; -#[cfg(emulation_mode = "usermode")] -extern "C" { - // Original QEMU user signal handler - fn libafl_qemu_handle_crash(signal: i32, info: *mut siginfo_t, puc: *mut c_void); -} - pub struct QemuExecutor<'a, CM, EH, H, OT, ET, S> where - CM: CommandManager, - EH: EmulatorExitHandler, H: FnMut(&mut Emulator, &S::Input) -> ExitKind, - S: Unpin + State + HasExecutions, + S: State, OT: ObserversTuple, ET: EmulatorModuleTuple, { @@ -56,41 +55,33 @@ where } #[cfg(emulation_mode = "usermode")] -pub unsafe fn inproc_qemu_crash_handler<'a, E, EM, OF, Z, ET, S>( +pub unsafe fn inproc_qemu_crash_handler( signal: Signal, - info: &'a mut siginfo_t, - mut context: Option<&'a mut ucontext_t>, - _data: &'a mut InProcessExecutorHandlerData, -) where - E: Executor + HasObservers, - EM: EventFirer + EventRestarter, - OF: Feedback, - E::State: HasExecutions + HasSolutions + HasCorpus, - Z: HasObjective, - ET: EmulatorModuleTuple + Debug + 'a, - S: Unpin + State + HasExecutions + 'a, -{ + info: &mut siginfo_t, + mut context: Option<&mut ucontext_t>, + _data: &mut InProcessExecutorHandlerData, +) { let puc = match &mut context { Some(v) => ptr::from_mut::(*v) as *mut c_void, None => ptr::null_mut(), }; - libafl_qemu_handle_crash(signal as i32, std::ptr::from_mut::(info), puc); + libafl_qemu_handle_crash(signal as i32, ptr::from_mut::(info), puc); } #[cfg(emulation_mode = "systemmode")] pub(crate) static mut BREAK_ON_TMOUT: bool = false; #[cfg(emulation_mode = "systemmode")] -pub unsafe fn inproc_qemu_timeout_handler<'a, E, EM, OF, Z>( +pub unsafe fn inproc_qemu_timeout_handler( signal: Signal, - info: &'a mut siginfo_t, - context: Option<&'a mut ucontext_t>, - data: &'a mut InProcessExecutorHandlerData, + info: &mut siginfo_t, + context: Option<&mut ucontext_t>, + data: &mut InProcessExecutorHandlerData, ) where - E: Executor + HasObservers + HasInProcessHooks, + E: HasObservers + HasInProcessHooks, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasCorpus + HasExecutions, + E::State: HasExecutions + HasSolutions + HasCorpus, Z: HasObjective + ExecutionProcessor + HasScheduler, { if BREAK_ON_TMOUT { @@ -104,10 +95,8 @@ pub unsafe fn inproc_qemu_timeout_handler<'a, E, EM, OF, Z>( impl<'a, CM, EH, H, OT, ET, S> Debug for QemuExecutor<'a, CM, EH, H, OT, ET, S> where - CM: CommandManager, - EH: EmulatorExitHandler, H: FnMut(&mut Emulator, &S::Input) -> ExitKind, - S: Unpin + State + HasExecutions, + S: State, OT: ObserversTuple + Debug, ET: EmulatorModuleTuple + Debug, { @@ -120,12 +109,10 @@ where impl<'a, CM, EH, H, OT, ET, S> QemuExecutor<'a, CM, EH, H, OT, ET, S> where - CM: CommandManager, - EH: EmulatorExitHandler, H: FnMut(&mut Emulator, &S::Input) -> ExitKind, - S: Unpin + State + HasExecutions, + S: State, OT: ObserversTuple, - ET: EmulatorModuleTuple + Debug, + ET: EmulatorModuleTuple, { pub fn new( emulator: Emulator, @@ -140,7 +127,7 @@ where EM: EventFirer + EventRestarter, OF: Feedback, S: Unpin + State + HasExecutions + HasCorpus + HasSolutions, - Z: HasObjective + HasScheduler + ExecutionProcessor, + Z: HasObjective + HasScheduler + ExecutionProcessor, { let mut inner = StatefulInProcessExecutor::with_timeout( harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout, @@ -148,14 +135,7 @@ where #[cfg(emulation_mode = "usermode")] { - inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler::< - StatefulInProcessExecutor<'a, H, OT, S, Emulator>, - EM, - OF, - Z, - ET, - S, - > as *const c_void; + inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler as *const c_void; let handler = |emulator_modules: &mut EmulatorModules, host_sig| { eprintln!("Crashed with signal {host_sig}"); @@ -204,17 +184,14 @@ where } } -impl<'a, CM, EH, EM, H, OT, OF, ET, S, Z> Executor for QemuExecutor<'a, CM, EH, H, OT, ET, S> +impl<'a, CM, EH, EM, H, OT, ET, S, Z> Executor for QemuExecutor<'a, CM, EH, H, OT, ET, S> where - CM: CommandManager, - EH: EmulatorExitHandler, - EM: EventFirer + EventRestarter, + EM: UsesState, + ET: EmulatorModuleTuple, H: FnMut(&mut Emulator, &S::Input) -> ExitKind, - S: Unpin + State + HasExecutions + HasCorpus + HasSolutions, OT: ObserversTuple, - OF: Feedback, - ET: EmulatorModuleTuple + Debug, - Z: HasObjective, + S: State + HasExecutions + Unpin, + Z: UsesState, { fn run_target( &mut self, @@ -241,34 +218,28 @@ where impl<'a, CM, EH, H, OT, ET, S> UsesState for QemuExecutor<'a, CM, EH, H, OT, ET, S> where - CM: CommandManager, - EH: EmulatorExitHandler, H: FnMut(&mut Emulator, &S::Input) -> ExitKind, + S: State, OT: ObserversTuple, ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, { type State = S; } impl<'a, CM, EH, H, OT, ET, S> UsesObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S> where - CM: CommandManager, - EH: EmulatorExitHandler, H: FnMut(&mut Emulator, &S::Input) -> ExitKind, + S: State, OT: ObserversTuple, ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, { type Observers = OT; } impl<'a, CM, EH, H, OT, ET, S> HasObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S> where - CM: CommandManager, - EH: EmulatorExitHandler, H: FnMut(&mut Emulator, &S::Input) -> ExitKind, - S: Unpin + State + HasExecutions, + S: State, OT: ObserversTuple, ET: EmulatorModuleTuple, { @@ -286,14 +257,12 @@ where #[cfg(feature = "fork")] pub struct QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> where - CM: CommandManager, - EH: EmulatorExitHandler, - H: FnMut(&S::Input) -> ExitKind, - S: Unpin + State + HasExecutions, - OT: ObserversTuple, - ET: EmulatorModuleTuple, - SP: ShMemProvider, EM: UsesState, + ET: EmulatorModuleTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, Z: UsesState, { inner: InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>, @@ -304,14 +273,14 @@ where impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> Debug for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> where - CM: CommandManager + Debug, - EH: EmulatorExitHandler, - H: FnMut(&S::Input) -> ExitKind, - S: Unpin + State + HasExecutions + Debug, - OT: ObserversTuple + Debug, - ET: EmulatorModuleTuple + Debug, - SP: ShMemProvider, + CM: Debug, EM: UsesState, + EH: Debug, + ET: EmulatorModuleTuple + Debug, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple + Debug, + S: UsesInput + Debug, + SP: ShMemProvider, Z: UsesState, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -323,19 +292,15 @@ where } #[cfg(feature = "fork")] -impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z, OF> QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> +impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> where - CM: CommandManager, - EH: EmulatorExitHandler, - H: FnMut(&S::Input) -> ExitKind, - S: Unpin + State + HasExecutions, - OT: ObserversTuple, + EM: EventFirer + EventRestarter, ET: EmulatorModuleTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: State + HasSolutions, SP: ShMemProvider, - EM: EventFirer + EventRestarter, - OF: Feedback, - S: Unpin + HasSolutions, - Z: HasObjective, + Z: HasObjective, { pub fn new( emulator: Emulator, @@ -410,14 +375,12 @@ where impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesObservers for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> where - CM: CommandManager, - EH: EmulatorExitHandler, - H: FnMut(&S::Input) -> ExitKind, - OT: ObserversTuple, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, - SP: ShMemProvider, EM: UsesState, + ET: EmulatorModuleTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: State, + SP: ShMemProvider, Z: UsesState, { type Observers = OT; @@ -427,14 +390,12 @@ where impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesState for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> where - CM: CommandManager, - EH: EmulatorExitHandler, - H: FnMut(&S::Input) -> ExitKind, - OT: ObserversTuple, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, - SP: ShMemProvider, EM: UsesState, + ET: EmulatorModuleTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: State, + SP: ShMemProvider, Z: UsesState, { type State = S; @@ -444,14 +405,12 @@ where impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> HasObservers for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> where - CM: CommandManager, - EH: EmulatorExitHandler, - H: FnMut(&S::Input) -> ExitKind, - S: Unpin + State + HasExecutions, - OT: ObserversTuple, - ET: EmulatorModuleTuple, - SP: ShMemProvider, EM: UsesState, + ET: EmulatorModuleTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: State, + SP: ShMemProvider, Z: UsesState, { #[inline] diff --git a/libafl_qemu/src/lib.rs b/libafl_qemu/src/lib.rs index 68efb0ff02..771eece838 100644 --- a/libafl_qemu/src/lib.rs +++ b/libafl_qemu/src/lib.rs @@ -55,6 +55,10 @@ pub mod breakpoint; pub mod command; pub mod sync_exit; +pub use libafl_qemu_sys::{GuestAddr, MmapPerms}; +#[cfg(emulation_mode = "systemmode")] +pub use libafl_qemu_sys::{GuestPhysAddr, GuestVirtAddr}; + #[must_use] pub fn filter_qemu_args() -> Vec { let mut args = vec![env::args().next().unwrap()]; @@ -90,7 +94,7 @@ pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_submodule(®sm)?; let mmapm = PyModule::new_bound(m.py(), "mmap")?; - for r in sys::MmapPerms::iter() { + for r in MmapPerms::iter() { let v: i32 = r.into(); mmapm.add(PyString::new_bound(m.py(), &format!("{r:?}")), v)?; } @@ -99,10 +103,10 @@ pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; #[cfg(emulation_mode = "usermode")] - m.add_class::()?; + m.add_class::()?; - m.add_class::()?; - m.add_class::()?; + m.add_class::()?; + m.add_class::()?; Ok(()) } diff --git a/libafl_qemu/src/modules/mod.rs b/libafl_qemu/src/modules/mod.rs index f9a5157e9e..2f13f9015b 100644 --- a/libafl_qemu/src/modules/mod.rs +++ b/libafl_qemu/src/modules/mod.rs @@ -37,7 +37,7 @@ use crate::emu::EmulatorModules; // TODO remove 'static when specialization will be stable pub trait EmulatorModule: 'static + Debug where - S: Unpin + UsesInput, + S: UsesInput, { const HOOKS_DO_SIDE_EFFECTS: bool = true; @@ -76,7 +76,7 @@ where pub trait EmulatorModuleTuple: MatchFirstType + for<'a> SplitBorrowExtractFirstType<'a> + Unpin where - S: Unpin + UsesInput, + S: UsesInput, { const HOOKS_DO_SIDE_EFFECTS: bool; @@ -108,7 +108,7 @@ where impl EmulatorModuleTuple for () where - S: Unpin + UsesInput, + S: UsesInput, { const HOOKS_DO_SIDE_EFFECTS: bool = false; @@ -150,7 +150,7 @@ impl EmulatorModuleTuple for (Head, Tail) where Head: EmulatorModule + Unpin, Tail: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS; diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index 0917b52ad4..ef7f8552c5 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -19,7 +19,7 @@ use crate::{ }, qemu::{MemAccessInfo, QemuInitError}, sys::TCGTemp, - GuestAddr, Qemu, Regs, + Qemu, Regs, }; // TODO at some point, merge parts with libafl_frida @@ -149,6 +149,7 @@ impl AllocTreeItem { } use std::pin::Pin; +use libafl_qemu_sys::GuestAddr; use object::{Object, ObjectSection}; use crate::{ diff --git a/libafl_qemu/src/modules/usermode/asan_guest.rs b/libafl_qemu/src/modules/usermode/asan_guest.rs index cadb1a9bc9..f8ebdd2623 100644 --- a/libafl_qemu/src/modules/usermode/asan_guest.rs +++ b/libafl_qemu/src/modules/usermode/asan_guest.rs @@ -8,6 +8,7 @@ use std::{ }; use libafl::inputs::UsesInput; +use libafl_qemu_sys::{GuestAddr, MapInfo}; #[cfg(not(feature = "clippy"))] use crate::sys::libafl_tcg_gen_asan; @@ -19,7 +20,6 @@ use crate::{ }, qemu::{Hook, MemAccessInfo, Qemu, QemuInitError}, sys::TCGTemp, - GuestAddr, MapInfo, }; static mut ASAN_GUEST_INITED: bool = false; diff --git a/libafl_qemu/src/qemu/hooks.rs b/libafl_qemu/src/qemu/hooks.rs index 9e40461c79..b76ecac00a 100644 --- a/libafl_qemu/src/qemu/hooks.rs +++ b/libafl_qemu/src/qemu/hooks.rs @@ -12,7 +12,6 @@ use pyo3::{pyclass, pymethods, FromPyObject}; use crate::{ emu::EmulatorModules, - modules::EmulatorModuleTuple, qemu::{MemAccessInfo, Qemu}, sys::TCGTemp, HookData, HookId, @@ -98,8 +97,7 @@ macro_rules! create_wrapper { paste::paste! { pub extern "C" fn [](hook: &mut c_void, $($param: $param_type),*) where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); @@ -110,7 +108,6 @@ macro_rules! create_wrapper { pub extern "C" fn [](hook: &mut FatPtr, $($param: $param_type),*) where - ET: EmulatorModuleTuple, S: Unpin + UsesInput, { unsafe { @@ -125,8 +122,7 @@ macro_rules! create_wrapper { paste::paste! { pub extern "C" fn [](hook: &mut c_void, $($param: $param_type),*) -> $ret_type where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); @@ -137,8 +133,7 @@ macro_rules! create_wrapper { pub extern "C" fn [](hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); @@ -155,8 +150,7 @@ macro_rules! create_pre_exec_wrapper { paste::paste! { pub extern "C" fn [<$name _pre_exec_hook_wrapper>](hook: &mut HookState<$hook_id>, $($param: $param_type),*) where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); @@ -186,8 +180,7 @@ macro_rules! create_post_exec_wrapper { paste::paste! { pub extern "C" fn [<$name _post_exec_hook_wrapper>](hook: &mut HookState<$hook_id>, $($param: $param_type),*) where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); @@ -217,8 +210,7 @@ macro_rules! create_gen_wrapper { paste::paste! { pub extern "C" fn [<$name _gen_hook_wrapper>](hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); @@ -248,8 +240,7 @@ macro_rules! create_post_gen_wrapper { paste::paste! { pub extern "C" fn [<$name _post_gen_hook_wrapper>](hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); @@ -278,8 +269,7 @@ macro_rules! create_exec_wrapper { paste::paste! { pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>](hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) where - ET: EmulatorModuleTuple, - S: Unpin + UsesInput, + S: UsesInput + Unpin, { unsafe { let modules = EmulatorModules::::emulator_modules_mut_unchecked(); diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index d9d0472c1f..7ae0735dd8 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -6,7 +6,7 @@ use core::fmt; use std::{ cmp::{Ordering, PartialOrd}, - ffi::CString, + ffi::{c_void, CString}, fmt::{Display, Formatter}, intrinsics::{copy_nonoverlapping, transmute}, mem::MaybeUninit, @@ -156,12 +156,12 @@ pub struct QemuMemoryChunk { #[allow(clippy::vec_box)] static mut GDB_COMMANDS: Vec> = vec![]; -extern "C" fn gdb_cmd(data: *const (), buf: *const u8, len: usize) -> i32 { +unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool { unsafe { let closure = &mut *(data as *mut Box FnMut(&Qemu, &'r str) -> bool>); let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); let qemu = Qemu::get_unchecked(); - i32::from(closure(&qemu, cmd)) + closure(&qemu, cmd) } } @@ -366,7 +366,7 @@ impl CPU { let val = GuestReg::to_le(val.into()); let success = - unsafe { libafl_qemu_write_reg(self.ptr, reg_id, ptr::addr_of!(val) as *const u8) }; + unsafe { libafl_qemu_write_reg(self.ptr, reg_id, ptr::addr_of!(val) as *mut u8) }; if success == 0 { Err(QemuRWError { kind: QemuRWErrorKind::Write, @@ -780,7 +780,7 @@ impl Qemu { Box FnMut(&'a Qemu, &'b str) -> bool>, FatPtr, >(callback)); - libafl_qemu_add_gdb_cmd(gdb_cmd, ptr::from_ref(&*fat) as *const ()); + libafl_qemu_add_gdb_cmd(Some(gdb_cmd), ptr::from_ref(&*fat) as *mut c_void); GDB_COMMANDS.push(fat); } } diff --git a/libafl_qemu/src/qemu/systemmode.rs b/libafl_qemu/src/qemu/systemmode.rs index d7d489db95..338e3701b6 100644 --- a/libafl_qemu/src/qemu/systemmode.rs +++ b/libafl_qemu/src/qemu/systemmode.rs @@ -207,12 +207,12 @@ impl Qemu { pub fn save_snapshot(&self, name: &str, sync: bool) { let s = CString::new(name).expect("Invalid snapshot name"); - unsafe { libafl_save_qemu_snapshot(s.as_ptr() as *const _, sync) }; + unsafe { libafl_save_qemu_snapshot(s.as_ptr() as *mut i8, sync) }; } pub fn load_snapshot(&self, name: &str, sync: bool) { let s = CString::new(name).expect("Invalid snapshot name"); - unsafe { libafl_load_qemu_snapshot(s.as_ptr() as *const _, sync) }; + unsafe { libafl_load_qemu_snapshot(s.as_ptr() as *mut i8, sync) }; } #[must_use] diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index c754973594..c95763582a 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -6,10 +6,10 @@ use std::{ use libafl_qemu_sys::{ exec_path, free_self_maps, guest_base, libafl_force_dfl, libafl_get_brk, libafl_load_addr, libafl_maps_first, libafl_maps_next, libafl_qemu_run, libafl_set_brk, mmap_next_start, - pageflags_get_root, read_self_maps, strlen, GuestAddr, GuestUsize, IntervalTreeNode, - IntervalTreeRoot, MapInfo, MmapPerms, VerifyAccess, + pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot, + MapInfo, MmapPerms, VerifyAccess, }; -use libc::c_int; +use libc::{c_char, c_int, strlen}; #[cfg(feature = "python")] use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python}; @@ -138,7 +138,12 @@ impl Qemu { #[must_use] pub fn binary_path<'a>(&self) -> &'a str { - unsafe { from_utf8_unchecked(from_raw_parts(exec_path, strlen(exec_path))) } + unsafe { + from_utf8_unchecked(from_raw_parts( + exec_path, + strlen(exec_path as *const c_char), + )) + } } #[must_use] diff --git a/libafl_qemu/src/sync_exit.rs b/libafl_qemu/src/sync_exit.rs index 5bdb9df88b..82f58ab927 100644 --- a/libafl_qemu/src/sync_exit.rs +++ b/libafl_qemu/src/sync_exit.rs @@ -4,14 +4,9 @@ use std::{ }; use enum_map::Enum; -use libafl::state::{HasExecutions, State}; +use libafl::inputs::UsesInput; -use crate::{ - command::{CommandManager, IsCommand}, - get_exit_arch_regs, - modules::EmulatorModuleTuple, - EmulatorExitHandler, GuestReg, Regs, CPU, -}; +use crate::{command::IsCommand, get_exit_arch_regs, GuestReg, Regs, CPU}; #[derive(Debug, Clone, Enum)] pub enum ExitArgs { @@ -28,20 +23,14 @@ pub enum ExitArgs { #[derive(Debug)] pub struct SyncExit where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { command: Rc>, } impl SyncExit where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { #[must_use] pub fn new(command: Rc>) -> Self { @@ -66,10 +55,7 @@ where impl Display for SyncExit where - CM: CommandManager, - EH: EmulatorExitHandler, - ET: EmulatorModuleTuple, - S: Unpin + State + HasExecutions, + S: UsesInput, { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.command)