Qemu generics cleanup (#2484)

* cleanup generics

* remove most extern C

* update qemu to latest revision

* executor trait bounds minimization
This commit is contained in:
Romain Malmain 2024-08-14 12:55:43 +02:00 committed by GitHub
parent 13ba32ed2a
commit 6979032ad9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 1064 additions and 927 deletions

View File

@ -61,6 +61,7 @@ const WRAPPER_HEADER: &str = r#"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "libafl/qemu_snapshot.h"
#include "libafl/syx-snapshot/device-save.h" #include "libafl/syx-snapshot/device-save.h"
#include "libafl/syx-snapshot/syx-snapshot.h" #include "libafl/syx-snapshot/syx-snapshot.h"
@ -82,6 +83,8 @@ const WRAPPER_HEADER: &str = r#"
#include "qemu/plugin-memory.h" #include "qemu/plugin-memory.h"
#include "libafl/cpu.h"
#include "libafl/gdb.h"
#include "libafl/exit.h" #include "libafl/exit.h"
#include "libafl/jit.h" #include "libafl/jit.h"
#include "libafl/utils.h" #include "libafl/utils.h"

View File

@ -11,7 +11,7 @@ use crate::cargo_add_rpath;
pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
pub const QEMU_DIRNAME: &str = "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)] #[allow(clippy::module_name_repetitions)]
pub struct BuildResult { pub struct BuildResult {

View File

@ -421,6 +421,8 @@ pub fn maybe_generate_stub_bindings(
force_regeneration, 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.");
} }
} }

View File

@ -15,8 +15,11 @@ __Warning__: The documentation is built by default for `x86_64` in `usermode`. T
#![allow(clippy::pedantic)] #![allow(clippy::pedantic)]
#![cfg_attr(nightly, feature(used_with_arg))] #![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 num_enum::{IntoPrimitive, TryFromPrimitive};
use paste::paste;
use strum_macros::EnumIter; use strum_macros::EnumIter;
#[cfg(all(not(feature = "clippy"), target_os = "linux"))] #[cfg(all(not(feature = "clippy"), target_os = "linux"))]
@ -40,6 +43,8 @@ pub use bindings::*;
#[allow(dead_code)] #[allow(dead_code)]
#[rustfmt::skip] #[rustfmt::skip]
mod x86_64_stub_bindings; mod x86_64_stub_bindings;
#[cfg(any(feature = "clippy", not(target_os = "linux")))]
pub use x86_64_stub_bindings::*;
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
mod usermode; mod usermode;
@ -115,25 +120,18 @@ macro_rules! extern_c_checked {
}; };
} }
#[cfg(target_os = "linux")] pub type CPUStatePtr = *mut CPUState;
use core::ops::BitAnd; pub type CPUArchStatePtr = *mut CPUArchState;
use std::ffi::c_void; pub type ExitReasonPtr = *mut libafl_exit_reason;
#[cfg(any(feature = "clippy", not(target_os = "linux")))] pub type GuestUsize = target_ulong;
pub use x86_64_stub_bindings::*; pub type GuestIsize = target_long;
pub type CPUStatePtr = *mut crate::CPUState; pub type GuestAddr = target_ulong;
pub type CPUArchStatePtr = *mut crate::CPUArchState; pub type GuestPhysAddr = hwaddr;
pub type ExitReasonPtr = *mut crate::libafl_exit_reason; pub type GuestVirtAddr = vaddr;
pub type GuestUsize = crate::target_ulong; pub type GuestHwAddrInfo = qemu_plugin_hwaddr;
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;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[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 { pub fn cpu_env(cpu: *mut CPUState) -> *mut CPUArchState {
unsafe { cpu.add(1) as *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);
}

View File

@ -1,6 +1,6 @@
use paste::paste; use paste::paste;
use crate::{extern_c_checked, CPUStatePtr, GuestPhysAddr}; use crate::extern_c_checked;
extern_c_checked! { extern_c_checked! {
pub fn qemu_init(argc: i32, argv: *const *const u8, envp: *const *const u8); 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 vm_start();
pub fn qemu_main_loop(); pub fn qemu_main_loop();
pub fn qemu_cleanup(); 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;
} }

View File

@ -1,22 +1,17 @@
use core::{slice::from_raw_parts, str::from_utf8_unchecked}; use core::{slice::from_raw_parts, str::from_utf8_unchecked};
use libc::{c_char, strlen};
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
use paste::paste; use paste::paste;
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python}; use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python};
use strum_macros::EnumIter; 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! { extern_c_checked! {
pub fn qemu_user_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32; 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 exec_path: *const u8;
pub static guest_base: usize; pub static guest_base: usize;
pub static mut mmap_next_start: GuestAddr; pub static mut mmap_next_start: GuestAddr;
@ -130,7 +125,7 @@ impl From<libafl_mapinfo> for MapInfo {
Some( Some(
from_utf8_unchecked(from_raw_parts( from_utf8_unchecked(from_raw_parts(
map_info.path as *const u8, map_info.path as *const u8,
strlen(map_info.path as *const u8), strlen(map_info.path as *const c_char),
)) ))
.to_string(), .to_string(),
) )

View File

@ -1,5 +1,5 @@
/* 1.82.0-nightly */ /* 1.82.0-nightly */
/* qemu git hash: 8f61fadbec181bfcbd305ba92a86a41376a476f7 */ /* qemu git hash: 31ee26f97071d5bed1ac1e7de75beea755b198d6 */
/* automatically generated by rust-bindgen 0.69.4 */ /* automatically generated by rust-bindgen 0.69.4 */
#[repr(C)] #[repr(C)]
@ -12631,6 +12631,408 @@ pub struct MemOp(pub ::std::os::raw::c_uint);
pub type MemOpIdx = u32; pub type MemOpIdx = u32;
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[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<image_info> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<image_info>(),
264usize,
concat!("Size of: ", stringify!(image_info))
);
assert_eq!(
::std::mem::align_of::<image_info>(),
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::<Self>::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 struct tb_tc {
pub ptr: *const ::std::os::raw::c_void, pub ptr: *const ::std::os::raw::c_void,
pub size: usize, 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."] #[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); pub fn free_self_maps(root: *mut IntervalTreeRoot);
} }
extern "C" {
pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong);
}
extern "C" { extern "C" {
pub fn libafl_qemu_set_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int; 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" { extern "C" {
pub fn libafl_qemu_handle_crash( pub fn libafl_qemu_handle_crash(
host_sig: ::std::os::raw::c_int, host_sig: ::std::os::raw::c_int,
@ -13347,6 +13749,18 @@ extern "C" {
ret: *mut libafl_mapinfo, ret: *mut libafl_mapinfo,
) -> *mut IntervalTreeNode; ) -> *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)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct AccelCPUClass { pub struct AccelCPUClass {
@ -14389,6 +14803,71 @@ extern "C" {
data: *mut qemu_plugin_hwaddr, data: *mut qemu_plugin_hwaddr,
) -> bool; ) -> 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" { extern "C" {
pub fn libafl_jit_trace_edge_hitcount(data: u64, id: u64) -> usize; pub fn libafl_jit_trace_edge_hitcount(data: u64, id: u64) -> usize;
} }

View File

@ -9,14 +9,10 @@ use std::{
}, },
}; };
use libafl::state::{HasExecutions, State}; use libafl::inputs::UsesInput;
use libafl_qemu_sys::GuestAddr; use libafl_qemu_sys::GuestAddr;
use crate::{ use crate::{command::IsCommand, Qemu};
command::{CommandManager, IsCommand},
modules::EmulatorModuleTuple,
EmulatorExitHandler, Qemu,
};
#[repr(transparent)] #[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@ -26,10 +22,7 @@ pub struct BreakpointId(u64);
#[derive(Debug)] #[derive(Debug)]
pub struct Breakpoint<CM, EH, ET, S> pub struct Breakpoint<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
id: BreakpointId, id: BreakpointId,
addr: GuestAddr, addr: GuestAddr,
@ -56,10 +49,7 @@ impl Default for BreakpointId {
impl<CM, EH, ET, S> Hash for Breakpoint<CM, EH, ET, S> impl<CM, EH, ET, S> Hash for Breakpoint<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state); self.id.hash(state);
@ -68,31 +58,18 @@ where
impl<CM, EH, ET, S> PartialEq for Breakpoint<CM, EH, ET, S> impl<CM, EH, ET, S> PartialEq for Breakpoint<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.id == other.id self.id == other.id
} }
} }
impl<CM, EH, ET, S> Eq for Breakpoint<CM, EH, ET, S> impl<CM, EH, ET, S> Eq for Breakpoint<CM, EH, ET, S> where S: UsesInput {}
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
}
impl<CM, EH, ET, S> Display for Breakpoint<CM, EH, ET, S> impl<CM, EH, ET, S> Display for Breakpoint<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Breakpoint @vaddr 0x{:x}", self.addr) write!(f, "Breakpoint @vaddr 0x{:x}", self.addr)
@ -101,10 +78,7 @@ where
impl<CM, EH, ET, S> Borrow<BreakpointId> for Breakpoint<CM, EH, ET, S> impl<CM, EH, ET, S> Borrow<BreakpointId> for Breakpoint<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn borrow(&self) -> &BreakpointId { fn borrow(&self) -> &BreakpointId {
&self.id &self.id
@ -113,10 +87,7 @@ where
impl<CM, EH, ET, S> Borrow<GuestAddr> for Breakpoint<CM, EH, ET, S> impl<CM, EH, ET, S> Borrow<GuestAddr> for Breakpoint<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn borrow(&self) -> &GuestAddr { fn borrow(&self) -> &GuestAddr {
&self.addr &self.addr
@ -125,10 +96,7 @@ where
impl<CM, EH, ET, S> Breakpoint<CM, EH, ET, S> impl<CM, EH, ET, S> Breakpoint<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
// Emu will return with the breakpoint as exit reason. // Emu will return with the breakpoint as exit reason.
#[must_use] #[must_use]

View File

@ -9,8 +9,7 @@ use hashbrown::HashMap;
use hashbrown::HashSet; use hashbrown::HashSet;
use libafl::{ use libafl::{
executors::ExitKind, executors::ExitKind,
inputs::HasTargetBytes, inputs::{HasTargetBytes, UsesInput},
state::{HasExecutions, State},
}; };
use libafl_bolts::AsSlice; use libafl_bolts::AsSlice;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
@ -25,12 +24,11 @@ use crate::{
}, },
get_exit_arch_regs, get_exit_arch_regs,
modules::{ modules::{
EmulatorModuleTuple, HasInstrumentationFilter, IsFilter, HasInstrumentationFilter, QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter,
QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter,
}, },
sync_exit::ExitArgs, sync_exit::ExitArgs,
Emulator, EmulatorExitHandler, ExitHandlerError, ExitHandlerResult, GuestReg, InputLocation, Emulator, ExitHandlerError, ExitHandlerResult, GuestReg, InputLocation, IsSnapshotManager,
IsSnapshotManager, Qemu, QemuMemoryChunk, QemuRWError, Regs, StdEmulatorExitHandler, CPU, Qemu, QemuMemoryChunk, QemuRWError, Regs, StdEmulatorExitHandler, CPU,
}; };
pub mod parser; pub mod parser;
@ -55,10 +53,7 @@ macro_rules! define_std_command_manager {
($name:ident, [$($native_command_parser:ident),+]) => { ($name:ident, [$($native_command_parser:ident),+]) => {
pub struct $name<ET, S, SM> pub struct $name<ET, S, SM>
where where
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, S: UsesInput,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
native_command_parsers: native_command_parsers:
HashMap<GuestReg, Box<dyn NativeCommandParser<Self, StdEmulatorExitHandler<SM>, ET, S>>>, HashMap<GuestReg, Box<dyn NativeCommandParser<Self, StdEmulatorExitHandler<SM>, ET, S>>>,
@ -66,8 +61,8 @@ macro_rules! define_std_command_manager {
impl<ET, S, SM> $name<ET, S, SM> impl<ET, S, SM> $name<ET, S, SM>
where where
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, ET: StdInstrumentationFilter + Unpin,
S: Unpin + State + HasExecutions, S: UsesInput + Unpin,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
@ -105,10 +100,7 @@ macro_rules! define_std_command_manager {
impl<ET, S, SM> CommandManager<StdEmulatorExitHandler<SM>, ET, S> for $name<ET, S, SM> impl<ET, S, SM> CommandManager<StdEmulatorExitHandler<SM>, ET, S> for $name<ET, S, SM>
where where
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, S: UsesInput,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn parse( fn parse(
&self, &self,
@ -129,10 +121,7 @@ macro_rules! define_std_command_manager {
impl<ET, S, SM> Debug for $name<ET, S, SM> impl<ET, S, SM> Debug for $name<ET, S, SM>
where where
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, S: UsesInput,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(f, stringify!($name)) write!(f, stringify!($name))
@ -141,8 +130,8 @@ macro_rules! define_std_command_manager {
impl<ET, S, SM> Default for $name<ET, S, SM> impl<ET, S, SM> Default for $name<ET, S, SM>
where where
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, ET: StdInstrumentationFilter + Unpin,
S: Unpin + State + HasExecutions, S: UsesInput + Unpin,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
@ -157,9 +146,7 @@ pub struct NopCommandManager;
impl<EH, ET, S> CommandManager<EH, ET, S> for NopCommandManager impl<EH, ET, S> CommandManager<EH, ET, S> for NopCommandManager
where where
EH: EmulatorExitHandler<ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn parse(&self, _qemu: Qemu) -> Result<Rc<dyn IsCommand<Self, EH, ET, S>>, CommandError> { fn parse(&self, _qemu: Qemu) -> Result<Rc<dyn IsCommand<Self, EH, ET, S>>, CommandError> {
Ok(Rc::new(NopCommand)) Ok(Rc::new(NopCommand))
@ -183,9 +170,7 @@ define_std_command_manager!(
pub trait CommandManager<EH, ET, S>: Sized pub trait CommandManager<EH, ET, S>: Sized
where where
EH: EmulatorExitHandler<ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn parse(&self, qemu: Qemu) -> Result<Rc<dyn IsCommand<Self, EH, ET, S>>, CommandError>; fn parse(&self, qemu: Qemu) -> Result<Rc<dyn IsCommand<Self, EH, ET, S>>, CommandError>;
} }
@ -200,10 +185,7 @@ pub enum NativeExitKind {
pub trait IsCommand<CM, EH, ET, S>: Debug + Display pub trait IsCommand<CM, EH, ET, S>: Debug + Display
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
/// Used to know whether the command can be run during a backdoor, or if it is necessary to go out of /// 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. /// the QEMU VM to run the command.
@ -251,10 +233,7 @@ impl Display for NopCommand {
impl<CM, EH, ET, S> IsCommand<CM, EH, ET, S> for NopCommand impl<CM, EH, ET, S> IsCommand<CM, EH, ET, S> for NopCommand
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
true true
@ -275,10 +254,8 @@ pub struct SaveCommand;
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for SaveCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for SaveCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, ET: StdInstrumentationFilter + Unpin,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, S: UsesInput + Unpin,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
@ -329,10 +306,7 @@ pub struct LoadCommand;
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for LoadCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for LoadCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
@ -374,11 +348,8 @@ pub struct InputCommand {
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for InputCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for InputCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
true true
@ -410,9 +381,7 @@ pub struct StartCommand {
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for StartCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for StartCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
@ -460,10 +429,7 @@ pub struct EndCommand(Option<ExitKind>);
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for EndCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for EndCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
@ -501,11 +467,7 @@ pub struct VersionCommand(u64);
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for VersionCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for VersionCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
true true
@ -531,21 +493,15 @@ where
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FilterCommand<T> pub struct FilterCommand<T> {
where
T: IsFilter + Debug,
{
filter: T, filter: T,
} }
#[cfg(emulation_mode = "systemmode")] #[cfg(emulation_mode = "systemmode")]
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for PagingFilterCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for PagingFilterCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, ET: StdInstrumentationFilter + Unpin,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, S: UsesInput + Unpin,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
true true
@ -571,11 +527,7 @@ where
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for AddressRangeFilterCommand impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for AddressRangeFilterCommand
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn usable_at_runtime(&self) -> bool { fn usable_at_runtime(&self) -> bool {
true true
@ -609,10 +561,7 @@ impl VersionCommand {
} }
} }
impl<T> FilterCommand<T> impl<T> FilterCommand<T> {
where
T: IsFilter + Debug,
{
pub fn new(filter: T) -> Self { pub fn new(filter: T) -> Self {
Self { filter } Self { filter }
} }

View File

@ -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 enum_map::{enum_map, EnumMap};
use libafl::{ use libafl::{
executors::ExitKind, executors::ExitKind,
inputs::HasTargetBytes, inputs::{HasTargetBytes, UsesInput},
state::{HasExecutions, State},
}; };
use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr}; use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr};
use crate::{ use crate::{
command::{ command::{
bindings, CommandError, CommandManager, EndCommand, FilterCommand, InputCommand, IsCommand, bindings, CommandError, EndCommand, FilterCommand, InputCommand, IsCommand, LoadCommand,
LoadCommand, NativeExitKind, SaveCommand, StartCommand, VersionCommand, NativeExitKind, SaveCommand, StartCommand, VersionCommand,
},
modules::{
EmulatorModuleTuple, QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter,
}, },
modules::{QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter},
sync_exit::ExitArgs, sync_exit::ExitArgs,
EmulatorExitHandler, GuestReg, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs, GuestReg, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs, StdEmulatorExitHandler,
StdEmulatorExitHandler,
}; };
pub static EMU_EXIT_KIND_MAP: OnceLock<EnumMap<NativeExitKind, Option<ExitKind>>> = OnceLock::new(); pub static EMU_EXIT_KIND_MAP: OnceLock<EnumMap<NativeExitKind, Option<ExitKind>>> = OnceLock::new();
pub trait NativeCommandParser<CM, EH, ET, S> pub trait NativeCommandParser<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn command_id(&self) -> GuestReg; fn command_id(&self) -> GuestReg;
@ -43,11 +36,8 @@ pub struct InputPhysCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
for InputPhysCommandParser for InputPhysCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn command_id(&self) -> GuestReg { fn command_id(&self) -> GuestReg {
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_PHYS.0) GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_PHYS.0)
@ -76,11 +66,8 @@ pub struct InputVirtCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
for InputVirtCommandParser for InputVirtCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn command_id(&self) -> GuestReg { fn command_id(&self) -> GuestReg {
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_VIRT.0) GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_VIRT.0)
@ -105,9 +92,7 @@ pub struct StartPhysCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
for StartPhysCommandParser for StartPhysCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
@ -135,9 +120,7 @@ pub struct StartVirtCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
for StartVirtCommandParser for StartVirtCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
@ -164,10 +147,8 @@ where
pub struct SaveCommandParser; pub struct SaveCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for SaveCommandParser impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for SaveCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, ET: StdInstrumentationFilter + Unpin,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, S: UsesInput + Unpin,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
fn command_id(&self) -> GuestReg { fn command_id(&self) -> GuestReg {
@ -186,10 +167,7 @@ where
pub struct LoadCommandParser; pub struct LoadCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for LoadCommandParser impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for LoadCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
fn command_id(&self) -> GuestReg { fn command_id(&self) -> GuestReg {
@ -208,10 +186,7 @@ where
pub struct EndCommandParser; pub struct EndCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for EndCommandParser impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for EndCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
fn command_id(&self) -> GuestReg { fn command_id(&self) -> GuestReg {
@ -244,11 +219,7 @@ pub struct VersionCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
for VersionCommandParser for VersionCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn command_id(&self) -> GuestReg { fn command_id(&self) -> GuestReg {
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VERSION.0) GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VERSION.0)
@ -269,11 +240,7 @@ pub struct VaddrFilterAllowRangeCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
for VaddrFilterAllowRangeCommandParser for VaddrFilterAllowRangeCommandParser
where where
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>, S: UsesInput,
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes,
SM: IsSnapshotManager,
{ {
fn command_id(&self) -> GuestReg { fn command_id(&self) -> GuestReg {
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VADDR_FILTER_ALLOW.0) GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VADDR_FILTER_ALLOW.0)

View File

@ -99,8 +99,7 @@ where
#[derive(Debug)] #[derive(Debug)]
pub struct EmulatorModules<ET, S> pub struct EmulatorModules<ET, S>
where where
ET: EmulatorModuleTuple<S>, S: UsesInput,
S: Unpin + UsesInput,
{ {
qemu: Qemu, qemu: Qemu,
modules: Pin<Box<ET>>, modules: Pin<Box<ET>>,
@ -112,8 +111,7 @@ where
#[derive(Debug)] #[derive(Debug)]
pub struct EmulatorHooks<ET, S> pub struct EmulatorHooks<ET, S>
where where
ET: EmulatorModuleTuple<S>, S: UsesInput,
S: Unpin + UsesInput,
{ {
qemu_hooks: QemuHooks, qemu_hooks: QemuHooks,
phantom: PhantomData<(ET, S)>, phantom: PhantomData<(ET, S)>,
@ -143,8 +141,7 @@ where
impl<ET, S> EmulatorHooks<ET, S> impl<ET, S> EmulatorHooks<ET, S>
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
#[must_use] #[must_use]
pub fn new(qemu_hooks: QemuHooks) -> Self { pub fn new(qemu_hooks: QemuHooks) -> Self {
@ -886,7 +883,6 @@ where
impl<ET, S> Default for EmulatorHooks<ET, S> impl<ET, S> Default for EmulatorHooks<ET, S>
where where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput, S: Unpin + UsesInput,
{ {
fn default() -> Self { fn default() -> Self {
@ -896,112 +892,8 @@ where
impl<ET, S> EmulatorModules<ET, S> impl<ET, S> EmulatorModules<ET, S>
where where
ET: EmulatorModuleTuple<S>, S: UsesInput,
S: Unpin + UsesInput,
{ {
pub(super) fn new(qemu: Qemu, modules: ET) -> Pin<Box<Self>> {
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::<Self>(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<S> 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<ET, S> {
&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<OT>(
&mut self,
input: &S::Input,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S>,
{
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<T>(&self) -> Option<&T>
where
T: EmulatorModule<S>,
{
self.modules.match_first_type::<T>()
}
/// Get a mutable reference to the first (type) matching member of the tuple.
pub fn get_mut<T>(&mut self) -> Option<&mut T>
where
T: EmulatorModule<S>,
{
self.modules.match_first_type_mut::<T>()
}
/// Get a mutable reference to `EmulatorModules` (supposedly initialized beforehand). /// Get a mutable reference to `EmulatorModules` (supposedly initialized beforehand).
/// ///
/// # Safety /// # Safety
@ -1037,6 +929,16 @@ where
pub unsafe fn emulator_modules_mut<'a>() -> Option<&'a mut EmulatorModules<ET, S>> { pub unsafe fn emulator_modules_mut<'a>() -> Option<&'a mut EmulatorModules<ET, S>> {
unsafe { (EMULATOR_TOOLS as *mut EmulatorModules<ET, S>).as_mut() } unsafe { (EMULATOR_TOOLS as *mut EmulatorModules<ET, S>).as_mut() }
} }
}
impl<ET, S> EmulatorModules<ET, S>
where
ET: Unpin,
S: UsesInput + Unpin,
{
pub fn modules_mut(&mut self) -> &mut ET {
self.modules.as_mut().get_mut()
}
pub fn instructions( pub fn instructions(
&mut self, &mut self,
@ -1154,6 +1056,113 @@ where
} }
} }
impl<ET, S> EmulatorModules<ET, S>
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
{
pub(super) fn new(qemu: Qemu, modules: ET) -> Pin<Box<Self>> {
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::<Self>(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<S> 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<OT>(
&mut self,
input: &S::Input,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S>,
{
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<T>(&self) -> Option<&T>
where
T: EmulatorModule<S>,
{
self.modules.match_first_type::<T>()
}
/// Get a mutable reference to the first (type) matching member of the tuple.
pub fn get_mut<T>(&mut self) -> Option<&mut T>
where
T: EmulatorModule<S>,
{
self.modules.match_first_type_mut::<T>()
}
}
impl<ET, S> EmulatorModules<ET, S>
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<ET, S> {
&mut self.hooks
}
}
/// Usermode-only high-level functions /// Usermode-only high-level functions
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
impl<ET, S> EmulatorModules<ET, S> impl<ET, S> EmulatorModules<ET, S>
@ -1290,8 +1299,7 @@ where
impl<ET, S> Drop for EmulatorModules<ET, S> impl<ET, S> Drop for EmulatorModules<ET, S>
where where
ET: EmulatorModuleTuple<S>, S: UsesInput,
S: Unpin + UsesInput,
{ {
fn drop(&mut self) { fn drop(&mut self) {
// Make the global pointer null at drop time // Make the global pointer null at drop time

View File

@ -17,24 +17,20 @@ use std::{
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl::{ use libafl::{
executors::ExitKind, executors::ExitKind,
inputs::HasTargetBytes, inputs::{HasTargetBytes, UsesInput},
observers::ObserversTuple, observers::ObserversTuple,
state::{HasExecutions, State},
}; };
use libafl_bolts::os::unix_signals::Signal; use libafl_bolts::os::unix_signals::Signal;
use libafl_qemu_sys::GuestUsize; use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestUsize, GuestVirtAddr};
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 typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use crate::{ use crate::{
breakpoint::Breakpoint, breakpoint::{Breakpoint, BreakpointId},
command::{CommandError, InputCommand, IsCommand}, command::{CommandError, CommandManager, InputCommand, IsCommand},
modules::EmulatorModuleTuple,
sync_exit::SyncExit, sync_exit::SyncExit,
GuestReg, Qemu, QemuExitError, QemuExitReason, QemuInitError, QemuMemoryChunk, QemuRWError, Qemu, QemuExitError, QemuExitReason, QemuInitError, QemuMemoryChunk, QemuShutdownCause,
QemuShutdownCause, QemuSnapshotCheckResult, Regs, CPU, QemuSnapshotCheckResult, Regs, CPU,
}; };
mod hooks; mod hooks;
@ -48,15 +44,52 @@ mod systemmode;
#[cfg(emulation_mode = "systemmode")] #[cfg(emulation_mode = "systemmode")]
pub use systemmode::*; pub use systemmode::*;
use crate::{
breakpoint::BreakpointId,
command::CommandManager,
modules::{EmulatorModuleTuple, StdInstrumentationFilter},
};
type CommandRef<CM, E, ET, S> = Rc<dyn IsCommand<CM, E, ET, S>>; type CommandRef<CM, E, ET, S> = Rc<dyn IsCommand<CM, E, ET, S>>;
type BreakpointMutRef<CM, E, ET, S> = Rc<RefCell<Breakpoint<CM, E, ET, S>>>; type BreakpointMutRef<CM, E, ET, S> = Rc<RefCell<Breakpoint<CM, E, ET, S>>>;
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<QemuSnapshotCheckResult, SnapshotManagerError>;
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<ET, S>: Sized + Debug + Clone
where
S: UsesInput,
{
fn qemu_pre_exec<CM: CommandManager<Self, ET, S>>(
emu: &mut Emulator<CM, Self, ET, S>,
input: &S::Input,
);
fn qemu_post_exec<CM: CommandManager<Self, ET, S>>(
emu: &mut Emulator<CM, Self, ET, S>,
exit_reason: Result<EmulatorExitResult<CM, Self, ET, S>, EmulatorExitError>,
input: &S::Input,
) -> Result<Option<ExitHandlerResult<CM, Self, ET, S>>, ExitHandlerError>;
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum GuestAddrKind { pub enum GuestAddrKind {
Physical(GuestPhysAddr), Physical(GuestPhysAddr),
@ -66,10 +99,7 @@ pub enum GuestAddrKind {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum EmulatorExitResult<CM, EH, ET, S> pub enum EmulatorExitResult<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
QemuExit(QemuShutdownCause), // QEMU ended for some reason. QemuExit(QemuShutdownCause), // QEMU ended for some reason.
Breakpoint(Rc<RefCell<Breakpoint<CM, EH, ET, S>>>), // Breakpoint triggered. Contains the address of the trigger. Breakpoint(Rc<RefCell<Breakpoint<CM, EH, ET, S>>>), // Breakpoint triggered. Contains the address of the trigger.
@ -84,35 +114,6 @@ pub enum EmulatorExitError {
BreakpointNotFound(GuestAddr), BreakpointNotFound(GuestAddr),
} }
#[derive(Debug, Clone)]
pub enum ExitHandlerResult<CM, EH, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
ReturnToHarness(EmulatorExitResult<CM, EH, ET, S>), // 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<CM, EH, ET, S> ExitHandlerResult<CM, EH, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
#[must_use]
#[allow(clippy::match_wildcard_for_single_variants)]
pub fn end_of_run(&self) -> Option<ExitKind> {
match self {
ExitHandlerResult::EndOfRun(exit_kind) => Some(*exit_kind),
_ => None,
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ExitHandlerError { pub enum ExitHandlerError {
QemuExitReasonError(EmulatorExitError), QemuExitReasonError(EmulatorExitError),
@ -125,6 +126,15 @@ pub enum ExitHandlerError {
SnapshotNotFound, SnapshotNotFound,
} }
#[derive(Debug, Clone)]
pub enum ExitHandlerResult<CM, EH, ET, S>
where
S: UsesInput,
{
ReturnToHarness(EmulatorExitResult<CM, EH, ET, S>), // 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)] #[derive(Debug, Clone)]
pub enum SnapshotManagerError { pub enum SnapshotManagerError {
SnapshotIdNotFound(SnapshotId), SnapshotIdNotFound(SnapshotId),
@ -137,12 +147,95 @@ pub enum SnapshotManagerCheckError {
SnapshotCheckError(QemuSnapshotCheckResult), 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<ET, S> EmulatorExitHandler<ET, S> for NopEmulatorExitHandler
where
S: UsesInput,
{
fn qemu_pre_exec<CM: CommandManager<Self, ET, S>>(
_: &mut Emulator<CM, Self, ET, S>,
_: &S::Input,
) {
}
fn qemu_post_exec<CM: CommandManager<Self, ET, S>>(
_: &mut Emulator<CM, Self, ET, S>,
exit_reason: Result<EmulatorExitResult<CM, Self, ET, S>, EmulatorExitError>,
_: &S::Input,
) -> Result<Option<ExitHandlerResult<CM, Self, ET, S>>, 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<Regs>,
}
/// Synchronous Exit handler maintaining only one snapshot.
#[derive(Debug, Clone, TypedBuilder)]
pub struct StdEmulatorExitHandler<SM> {
snapshot_manager: RefCell<SM>,
#[builder(default)]
snapshot_id: OnceCell<SnapshotId>,
#[builder(default)]
input_location: OnceCell<InputLocation>,
}
// TODO: Replace TypedBuilder by something better, it does not work correctly with default and
// inter-dependent fields.
#[derive(Debug, TypedBuilder)]
pub struct Emulator<CM, EH, ET, S>
where
S: UsesInput,
{
modules: Pin<Box<EmulatorModules<ET, S>>>,
command_manager: CM,
exit_handler: RefCell<EH>,
#[builder(default)]
breakpoints_by_addr: RefCell<HashMap<GuestAddr, BreakpointMutRef<CM, EH, ET, S>>>,
#[builder(default)]
breakpoints_by_id: RefCell<HashMap<BreakpointId, BreakpointMutRef<CM, EH, ET, S>>>,
#[builder(setter(transform = |args: &[String], env: &[(String, String)]| Qemu::init(args, env).unwrap()))]
qemu: Qemu,
first_exec: bool,
_phantom: PhantomData<(ET, S)>,
}
impl<CM, EH, ET, S> ExitHandlerResult<CM, EH, ET, S>
where
S: UsesInput,
{
#[must_use]
#[allow(clippy::match_wildcard_for_single_variants)]
pub fn end_of_run(&self) -> Option<ExitKind> {
match self {
ExitHandlerResult::EndOfRun(exit_kind) => Some(*exit_kind),
_ => None,
}
}
}
impl<CM, EH, ET, S> TryFrom<ExitHandlerResult<CM, EH, ET, S>> for ExitKind impl<CM, EH, ET, S> TryFrom<ExitHandlerResult<CM, EH, ET, S>> for ExitKind
where where
CM: CommandManager<EH, ET, S> + Debug, CM: Debug,
EH: EmulatorExitHandler<ET, S>, EH: Debug,
ET: EmulatorModuleTuple<S> + Debug, ET: Debug,
S: Unpin + State + HasExecutions + Debug, S: UsesInput + Debug,
{ {
type Error = String; type Error = String;
@ -197,91 +290,6 @@ impl From<SnapshotManagerCheckError> 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<QemuSnapshotCheckResult, SnapshotManagerError>;
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<ET, S>: Sized + Debug + Clone
where
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
fn qemu_pre_exec<CM: CommandManager<Self, ET, S>>(
emu: &mut Emulator<CM, Self, ET, S>,
input: &S::Input,
);
fn qemu_post_exec<CM: CommandManager<Self, ET, S>>(
emu: &mut Emulator<CM, Self, ET, S>,
exit_reason: Result<EmulatorExitResult<CM, Self, ET, S>, EmulatorExitError>,
input: &S::Input,
) -> Result<Option<ExitHandlerResult<CM, Self, ET, S>>, 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<ET, S> EmulatorExitHandler<ET, S> for NopEmulatorExitHandler
where
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
fn qemu_pre_exec<CM: CommandManager<Self, ET, S>>(
_: &mut Emulator<CM, Self, ET, S>,
_: &S::Input,
) {
}
fn qemu_post_exec<CM: CommandManager<Self, ET, S>>(
_: &mut Emulator<CM, Self, ET, S>,
exit_reason: Result<EmulatorExitResult<CM, Self, ET, S>, EmulatorExitError>,
_: &S::Input,
) -> Result<Option<ExitHandlerResult<CM, Self, ET, S>>, 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<Regs>,
}
impl InputLocation { impl InputLocation {
#[must_use] #[must_use]
pub fn new(mem_chunk: QemuMemoryChunk, cpu: CPU, ret_register: Option<Regs>) -> Self { pub fn new(mem_chunk: QemuMemoryChunk, cpu: CPU, ret_register: Option<Regs>) -> Self {
@ -293,23 +301,7 @@ impl InputLocation {
} }
} }
/// Synchronous Exit handler maintaining only one snapshot. impl<SM> StdEmulatorExitHandler<SM> {
#[derive(Debug, Clone, TypedBuilder)]
pub struct StdEmulatorExitHandler<SM>
where
SM: IsSnapshotManager + Clone,
{
snapshot_manager: RefCell<SM>,
#[builder(default)]
snapshot_id: OnceCell<SnapshotId>,
#[builder(default)]
input_location: OnceCell<InputLocation>,
}
impl<SM> StdEmulatorExitHandler<SM>
where
SM: IsSnapshotManager,
{
pub fn new(snapshot_manager: SM) -> Self { pub fn new(snapshot_manager: SM) -> Self {
Self { Self {
snapshot_manager: RefCell::new(snapshot_manager), snapshot_manager: RefCell::new(snapshot_manager),
@ -342,8 +334,7 @@ where
// TODO: replace handlers with generics to permit compile-time customization of handlers // TODO: replace handlers with generics to permit compile-time customization of handlers
impl<ET, S, SM> EmulatorExitHandler<ET, S> for StdEmulatorExitHandler<SM> impl<ET, S, SM> EmulatorExitHandler<ET, S> for StdEmulatorExitHandler<SM>
where where
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug, S: UsesInput,
S: Unpin + State + HasExecutions,
S::Input: HasTargetBytes, S::Input: HasTargetBytes,
SM: IsSnapshotManager, SM: IsSnapshotManager,
{ {
@ -436,10 +427,7 @@ impl From<CommandError> for ExitHandlerError {
impl<CM, EH, ET, S> Display for EmulatorExitResult<CM, EH, ET, S> impl<CM, EH, ET, S> Display for EmulatorExitResult<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
@ -458,36 +446,20 @@ impl From<CommandError> 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<CM, EH, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
modules: Pin<Box<EmulatorModules<ET, S>>>,
command_manager: CM,
exit_handler: RefCell<EH>,
#[builder(default)]
breakpoints_by_addr: RefCell<HashMap<GuestAddr, BreakpointMutRef<CM, EH, ET, S>>>,
#[builder(default)]
breakpoints_by_id: RefCell<HashMap<BreakpointId, BreakpointMutRef<CM, EH, ET, S>>>,
#[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<CM, EH, ET, S> Emulator<CM, EH, ET, S> impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, ET: Unpin,
EH: EmulatorExitHandler<ET, S>, S: UsesInput + Unpin,
{
pub fn modules_mut(&mut self) -> &mut EmulatorModules<ET, S> {
self.modules.as_mut().get_mut()
}
}
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
where
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions, S: UsesInput + Unpin,
{ {
#[allow(clippy::must_use_candidate, clippy::similar_names)] #[allow(clippy::must_use_candidate, clippy::similar_names)]
pub fn new( pub fn new(
@ -520,12 +492,35 @@ where
}) })
} }
pub fn modules(&self) -> &EmulatorModules<ET, S> { pub fn first_exec_all(&mut self) {
&self.modules if self.first_exec {
self.modules.first_exec_all();
self.first_exec = false;
}
} }
pub fn modules_mut(&mut self) -> &mut EmulatorModules<ET, S> { pub fn pre_exec_all(&mut self, input: &S::Input) {
self.modules.as_mut().get_mut() self.modules.pre_exec_all(input);
}
pub fn post_exec_all<OT>(
&mut self,
input: &S::Input,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S>,
{
self.modules.post_exec_all(input, observers, exit_kind);
}
}
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
where
S: UsesInput,
{
pub fn modules(&self) -> &EmulatorModules<ET, S> {
&self.modules
} }
#[must_use] #[must_use]
@ -537,91 +532,85 @@ where
pub fn exit_handler(&self) -> &RefCell<EH> { pub fn exit_handler(&self) -> &RefCell<EH> {
&self.exit_handler &self.exit_handler
} }
}
#[must_use] impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
#[allow(clippy::cast_possible_wrap)] where
#[allow(clippy::cast_sign_loss)] EH: EmulatorExitHandler<ET, S>,
#[deprecated( CM: CommandManager<EH, ET, S>,
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." S: UsesInput,
)] {
pub fn num_cpus(&self) -> usize { /// This function will run the emulator until the exit handler decides to stop the execution for
self.qemu.num_cpus() /// 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<ExitHandlerResult<CM, EH, ET, S>, 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] /// This function will run the emulator until the next breakpoint, or until finish.
#[deprecated( /// # Safety
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." ///
)] /// Should, in general, be safe to call.
pub fn current_cpu(&self) -> Option<CPU> { /// Of course, the emulated target is not contained securely and can corrupt state or interact with the operating system.
self.qemu.current_cpu() pub unsafe fn run_qemu(&self) -> Result<EmulatorExitResult<CM, EH, ET, S>, EmulatorExitError> {
} match self.qemu.run() {
Ok(qemu_exit_reason) => Ok(match qemu_exit_reason {
#[must_use] QemuExitReason::End(qemu_shutdown_cause) => {
#[allow(clippy::cast_possible_wrap)] EmulatorExitResult::QemuExit(qemu_shutdown_cause)
#[deprecated( }
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." QemuExitReason::Breakpoint(bp_addr) => {
)] let bp = self
pub fn cpu_from_index(&self, index: usize) -> CPU { .breakpoints_by_addr
self.qemu.cpu_from_index(index) .borrow()
} .get(&bp_addr)
.ok_or(EmulatorExitError::BreakpointNotFound(bp_addr))?
#[must_use] .clone();
#[deprecated( EmulatorExitResult::Breakpoint(bp.clone())
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`." }
)] QemuExitReason::SyncExit => EmulatorExitResult::SyncExit(Rc::new(RefCell::new(
pub fn page_from_addr(&self, addr: GuestAddr) -> GuestAddr { SyncExit::new(self.command_manager.parse(self.qemu)?),
self.qemu.page_from_addr(addr) ))),
} }),
Err(qemu_exit_reason_error) => Err(match qemu_exit_reason_error {
//#[must_use] QemuExitError::UnexpectedExit => EmulatorExitError::UnexpectedExit,
/*pub fn page_size() -> GuestUsize { QemuExitError::UnknownKind => EmulatorExitError::UnknownKind,
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<R, T>(&self, reg: R, val: T) -> Result<(), QemuRWError>
where
T: Num + PartialOrd + Copy + Into<GuestReg>,
R: Into<i32> + 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<R, T>(&self, reg: R) -> Result<T, QemuRWError>
where
T: Num + PartialOrd + Copy + From<GuestReg>,
R: Into<i32> + Clone,
{
self.qemu.read_reg(reg)
} }
}
#[allow(clippy::unused_self)]
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
where
S: UsesInput,
{
pub fn add_breakpoint(&self, mut bp: Breakpoint<CM, EH, ET, S>, enable: bool) -> BreakpointId { pub fn add_breakpoint(&self, mut bp: Breakpoint<CM, EH, ET, S>, enable: bool) -> BreakpointId {
if enable { if enable {
bp.enable(self.qemu); bp.enable(self.qemu);
@ -671,120 +660,4 @@ where
.remove(&bp_addr) .remove(&bp_addr)
.expect("Could not remove bp"); .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<OT>(
&mut self,
input: &S::Input,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S>,
{
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<EmulatorExitResult<CM, EH, ET, S>, 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<ExitHandlerResult<CM, EH, ET, S>, 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<dyn FnMut(&Qemu, &str) -> 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);
}
} }

View File

@ -4,13 +4,12 @@ use std::{
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl::state::{HasExecutions, State}; use libafl::inputs::UsesInput;
use libafl_qemu_sys::GuestPhysAddr; use libafl_qemu_sys::GuestPhysAddr;
use crate::{ use crate::{
command::CommandManager, emu::IsSnapshotManager, modules::EmulatorModuleTuple, emu::IsSnapshotManager, DeviceSnapshotFilter, Emulator, Qemu, QemuSnapshotCheckResult,
DeviceSnapshotFilter, Emulator, EmulatorExitHandler, Qemu, QemuSnapshotCheckResult, SnapshotId, SnapshotId, SnapshotManagerError,
SnapshotManagerError,
}; };
impl SnapshotId { impl SnapshotId {
@ -173,10 +172,7 @@ impl IsSnapshotManager for FastSnapshotManager {
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S> impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
/// Write a value to a phsical guest address, including ROM areas. /// Write a value to a phsical guest address, including ROM areas.
pub unsafe fn write_phys_mem(&self, paddr: GuestPhysAddr, buf: &[u8]) { pub unsafe fn write_phys_mem(&self, paddr: GuestPhysAddr, buf: &[u8]) {

View File

@ -1,18 +1,11 @@
use libafl::inputs::UsesInput;
use libafl_qemu_sys::{GuestAddr, MmapPerms, VerifyAccess}; use libafl_qemu_sys::{GuestAddr, MmapPerms, VerifyAccess};
use crate::{ use crate::{Emulator, GuestMaps};
command::CommandManager,
emu::{HasExecutions, State},
modules::EmulatorModuleTuple,
Emulator, EmulatorExitHandler, GuestMaps,
};
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S> impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
/// This function gets the memory mappings from the emulator. /// This function gets the memory mappings from the emulator.
#[must_use] #[must_use]

View File

@ -20,6 +20,7 @@ use libafl::{
}, },
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput,
observers::{ObserversTuple, UsesObservers}, observers::{ObserversTuple, UsesObservers},
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState}, state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error, ExecutionProcessor, HasScheduler, Error, ExecutionProcessor, HasScheduler,
@ -27,28 +28,26 @@ use libafl::{
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
use libafl_bolts::shmem::ShMemProvider; use libafl_bolts::shmem::ShMemProvider;
use libafl_bolts::{ use libafl_bolts::{
os::unix_signals::{siginfo_t, ucontext_t, Signal}, os::unix_signals::{ucontext_t, Signal},
tuples::RefIndexable, tuples::RefIndexable,
}; };
#[cfg(emulation_mode = "usermode")]
use libafl_qemu_sys::libafl_qemu_handle_crash;
#[cfg(emulation_mode = "systemmode")] #[cfg(emulation_mode = "systemmode")]
use libafl_qemu_sys::qemu_system_debug_request; 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")] #[cfg(emulation_mode = "usermode")]
use crate::EmulatorModules; use crate::EmulatorModules;
use crate::{command::CommandManager, modules::EmulatorModuleTuple, Emulator, EmulatorExitHandler}; 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> pub struct QemuExecutor<'a, CM, EH, H, OT, ET, S>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind, H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions, S: State,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
{ {
@ -56,41 +55,33 @@ where
} }
#[cfg(emulation_mode = "usermode")] #[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, signal: Signal,
info: &'a mut siginfo_t, info: &mut siginfo_t,
mut context: Option<&'a mut ucontext_t>, mut context: Option<&mut ucontext_t>,
_data: &'a mut InProcessExecutorHandlerData, _data: &mut InProcessExecutorHandlerData,
) where ) {
E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>,
E::State: HasExecutions + HasSolutions + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State>,
ET: EmulatorModuleTuple<S> + Debug + 'a,
S: Unpin + State + HasExecutions + 'a,
{
let puc = match &mut context { let puc = match &mut context {
Some(v) => ptr::from_mut::<ucontext_t>(*v) as *mut c_void, Some(v) => ptr::from_mut::<ucontext_t>(*v) as *mut c_void,
None => ptr::null_mut(), None => ptr::null_mut(),
}; };
libafl_qemu_handle_crash(signal as i32, std::ptr::from_mut::<siginfo_t>(info), puc); libafl_qemu_handle_crash(signal as i32, ptr::from_mut::<siginfo_t>(info), puc);
} }
#[cfg(emulation_mode = "systemmode")] #[cfg(emulation_mode = "systemmode")]
pub(crate) static mut BREAK_ON_TMOUT: bool = false; pub(crate) static mut BREAK_ON_TMOUT: bool = false;
#[cfg(emulation_mode = "systemmode")] #[cfg(emulation_mode = "systemmode")]
pub unsafe fn inproc_qemu_timeout_handler<'a, E, EM, OF, Z>( pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
signal: Signal, signal: Signal,
info: &'a mut siginfo_t, info: &mut siginfo_t,
context: Option<&'a mut ucontext_t>, context: Option<&mut ucontext_t>,
data: &'a mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
) where ) where
E: Executor<EM, Z> + HasObservers + HasInProcessHooks<E::State>, E: HasObservers + HasInProcessHooks<E::State>,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasCorpus + HasExecutions, E::State: HasExecutions + HasSolutions + HasCorpus,
Z: HasObjective<Objective = OF, State = E::State> + ExecutionProcessor + HasScheduler, Z: HasObjective<Objective = OF, State = E::State> + ExecutionProcessor + HasScheduler,
{ {
if BREAK_ON_TMOUT { 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> impl<'a, CM, EH, H, OT, ET, S> Debug for QemuExecutor<'a, CM, EH, H, OT, ET, S>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind, H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions, S: State,
OT: ObserversTuple<S> + Debug, OT: ObserversTuple<S> + Debug,
ET: EmulatorModuleTuple<S> + Debug, ET: EmulatorModuleTuple<S> + Debug,
{ {
@ -120,12 +109,10 @@ where
impl<'a, CM, EH, H, OT, ET, S> QemuExecutor<'a, CM, EH, H, OT, ET, S> impl<'a, CM, EH, H, OT, ET, S> QemuExecutor<'a, CM, EH, H, OT, ET, S>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind, H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions, S: State,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S> + Debug, ET: EmulatorModuleTuple<S>,
{ {
pub fn new<EM, OF, Z>( pub fn new<EM, OF, Z>(
emulator: Emulator<CM, EH, ET, S>, emulator: Emulator<CM, EH, ET, S>,
@ -140,7 +127,7 @@ where
EM: EventFirer<State = S> + EventRestarter<State = S>, EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<S>, OF: Feedback<S>,
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions, S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
Z: HasObjective<Objective = OF, State = S> + HasScheduler + ExecutionProcessor, Z: HasObjective<Objective = OF, State = S> + HasScheduler<State = S> + ExecutionProcessor,
{ {
let mut inner = StatefulInProcessExecutor::with_timeout( let mut inner = StatefulInProcessExecutor::with_timeout(
harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout, harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout,
@ -148,14 +135,7 @@ where
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
{ {
inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler::< inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler as *const c_void;
StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, EH, ET, S>>,
EM,
OF,
Z,
ET,
S,
> as *const c_void;
let handler = |emulator_modules: &mut EmulatorModules<ET, S>, host_sig| { let handler = |emulator_modules: &mut EmulatorModules<ET, S>, host_sig| {
eprintln!("Crashed with signal {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<EM, Z> for QemuExecutor<'a, CM, EH, H, OT, ET, S> impl<'a, CM, EH, EM, H, OT, ET, S, Z> Executor<EM, Z> for QemuExecutor<'a, CM, EH, H, OT, ET, S>
where where
CM: CommandManager<EH, ET, S>, EM: UsesState<State = S>,
EH: EmulatorExitHandler<ET, S>, ET: EmulatorModuleTuple<S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind, H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
OF: Feedback<S>, S: State + HasExecutions + Unpin,
ET: EmulatorModuleTuple<S> + Debug, Z: UsesState<State = S>,
Z: HasObjective<Objective = OF, State = S>,
{ {
fn run_target( fn run_target(
&mut self, &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> impl<'a, CM, EH, H, OT, ET, S> UsesState for QemuExecutor<'a, CM, EH, H, OT, ET, S>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind, H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: State,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
type State = S; type State = S;
} }
impl<'a, CM, EH, H, OT, ET, S> UsesObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S> impl<'a, CM, EH, H, OT, ET, S> UsesObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind, H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: State,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
type Observers = OT; type Observers = OT;
} }
impl<'a, CM, EH, H, OT, ET, S> HasObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S> impl<'a, CM, EH, H, OT, ET, S> HasObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind, H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions, S: State,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
{ {
@ -286,14 +257,12 @@ where
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
pub struct QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> pub struct QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
SP: ShMemProvider,
EM: UsesState<State = S>, EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S>,
S: UsesInput,
SP: ShMemProvider,
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
inner: InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>, 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 impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> Debug
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
where where
CM: CommandManager<EH, ET, S> + Debug, CM: Debug,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
S: Unpin + State + HasExecutions + Debug,
OT: ObserversTuple<S> + Debug,
ET: EmulatorModuleTuple<S> + Debug,
SP: ShMemProvider,
EM: UsesState<State = S>, EM: UsesState<State = S>,
EH: Debug,
ET: EmulatorModuleTuple<S> + Debug,
H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S> + Debug,
S: UsesInput + Debug,
SP: ShMemProvider,
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@ -323,19 +292,15 @@ where
} }
#[cfg(feature = "fork")] #[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 where
CM: CommandManager<EH, ET, S>, EM: EventFirer<State = S> + EventRestarter<State = S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S>,
S: State + HasSolutions,
SP: ShMemProvider, SP: ShMemProvider,
EM: EventFirer<State = S> + EventRestarter, Z: HasObjective<State = S>,
OF: Feedback<S>,
S: Unpin + HasSolutions,
Z: HasObjective<Objective = OF, State = S>,
{ {
pub fn new( pub fn new(
emulator: Emulator<CM, EH, ET, S>, emulator: Emulator<CM, EH, ET, S>,
@ -410,14 +375,12 @@ where
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesObservers impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesObservers
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
SP: ShMemProvider,
EM: UsesState<State = S>, EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S>,
S: State,
SP: ShMemProvider,
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
type Observers = OT; type Observers = OT;
@ -427,14 +390,12 @@ where
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesState impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesState
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
SP: ShMemProvider,
EM: UsesState<State = S>, EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S>,
S: State,
SP: ShMemProvider,
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
type State = S; type State = S;
@ -444,14 +405,12 @@ where
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> HasObservers impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> HasObservers
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z> for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
where where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
SP: ShMemProvider,
EM: UsesState<State = S>, EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S>,
S: State,
SP: ShMemProvider,
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
#[inline] #[inline]

View File

@ -55,6 +55,10 @@ pub mod breakpoint;
pub mod command; pub mod command;
pub mod sync_exit; pub mod sync_exit;
pub use libafl_qemu_sys::{GuestAddr, MmapPerms};
#[cfg(emulation_mode = "systemmode")]
pub use libafl_qemu_sys::{GuestPhysAddr, GuestVirtAddr};
#[must_use] #[must_use]
pub fn filter_qemu_args() -> Vec<String> { pub fn filter_qemu_args() -> Vec<String> {
let mut args = vec![env::args().next().unwrap()]; let mut args = vec![env::args().next().unwrap()];
@ -90,7 +94,7 @@ pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_submodule(&regsm)?; m.add_submodule(&regsm)?;
let mmapm = PyModule::new_bound(m.py(), "mmap")?; let mmapm = PyModule::new_bound(m.py(), "mmap")?;
for r in sys::MmapPerms::iter() { for r in MmapPerms::iter() {
let v: i32 = r.into(); let v: i32 = r.into();
mmapm.add(PyString::new_bound(m.py(), &format!("{r:?}")), v)?; 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::<sys::MapInfo>()?; m.add_class::<sys::MapInfo>()?;
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
m.add_class::<qemu::GuestMaps>()?; m.add_class::<GuestMaps>()?;
m.add_class::<qemu::SyscallHookResult>()?; m.add_class::<SyscallHookResult>()?;
m.add_class::<qemu::pybind::Qemu>()?; m.add_class::<pybind::Qemu>()?;
Ok(()) Ok(())
} }

View File

@ -37,7 +37,7 @@ use crate::emu::EmulatorModules;
// TODO remove 'static when specialization will be stable // TODO remove 'static when specialization will be stable
pub trait EmulatorModule<S>: 'static + Debug pub trait EmulatorModule<S>: 'static + Debug
where where
S: Unpin + UsesInput, S: UsesInput,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = true; const HOOKS_DO_SIDE_EFFECTS: bool = true;
@ -76,7 +76,7 @@ where
pub trait EmulatorModuleTuple<S>: pub trait EmulatorModuleTuple<S>:
MatchFirstType + for<'a> SplitBorrowExtractFirstType<'a> + Unpin MatchFirstType + for<'a> SplitBorrowExtractFirstType<'a> + Unpin
where where
S: Unpin + UsesInput, S: UsesInput,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool; const HOOKS_DO_SIDE_EFFECTS: bool;
@ -108,7 +108,7 @@ where
impl<S> EmulatorModuleTuple<S> for () impl<S> EmulatorModuleTuple<S> for ()
where where
S: Unpin + UsesInput, S: UsesInput,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = false; const HOOKS_DO_SIDE_EFFECTS: bool = false;
@ -150,7 +150,7 @@ impl<Head, Tail, S> EmulatorModuleTuple<S> for (Head, Tail)
where where
Head: EmulatorModule<S> + Unpin, Head: EmulatorModule<S> + Unpin,
Tail: EmulatorModuleTuple<S>, Tail: EmulatorModuleTuple<S>,
S: Unpin + UsesInput, S: UsesInput + Unpin,
{ {
const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS; const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS;

View File

@ -19,7 +19,7 @@ use crate::{
}, },
qemu::{MemAccessInfo, QemuInitError}, qemu::{MemAccessInfo, QemuInitError},
sys::TCGTemp, sys::TCGTemp,
GuestAddr, Qemu, Regs, Qemu, Regs,
}; };
// TODO at some point, merge parts with libafl_frida // TODO at some point, merge parts with libafl_frida
@ -149,6 +149,7 @@ impl AllocTreeItem {
} }
use std::pin::Pin; use std::pin::Pin;
use libafl_qemu_sys::GuestAddr;
use object::{Object, ObjectSection}; use object::{Object, ObjectSection};
use crate::{ use crate::{

View File

@ -8,6 +8,7 @@ use std::{
}; };
use libafl::inputs::UsesInput; use libafl::inputs::UsesInput;
use libafl_qemu_sys::{GuestAddr, MapInfo};
#[cfg(not(feature = "clippy"))] #[cfg(not(feature = "clippy"))]
use crate::sys::libafl_tcg_gen_asan; use crate::sys::libafl_tcg_gen_asan;
@ -19,7 +20,6 @@ use crate::{
}, },
qemu::{Hook, MemAccessInfo, Qemu, QemuInitError}, qemu::{Hook, MemAccessInfo, Qemu, QemuInitError},
sys::TCGTemp, sys::TCGTemp,
GuestAddr, MapInfo,
}; };
static mut ASAN_GUEST_INITED: bool = false; static mut ASAN_GUEST_INITED: bool = false;

View File

@ -12,7 +12,6 @@ use pyo3::{pyclass, pymethods, FromPyObject};
use crate::{ use crate::{
emu::EmulatorModules, emu::EmulatorModules,
modules::EmulatorModuleTuple,
qemu::{MemAccessInfo, Qemu}, qemu::{MemAccessInfo, Qemu},
sys::TCGTemp, sys::TCGTemp,
HookData, HookId, HookData, HookId,
@ -98,8 +97,7 @@ macro_rules! create_wrapper {
paste::paste! { paste::paste! {
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut c_void, $($param: $param_type),*) pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut c_void, $($param: $param_type),*)
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
@ -110,7 +108,6 @@ macro_rules! create_wrapper {
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*) pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*)
where where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput, S: Unpin + UsesInput,
{ {
unsafe { unsafe {
@ -125,8 +122,7 @@ macro_rules! create_wrapper {
paste::paste! { paste::paste! {
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut c_void, $($param: $param_type),*) -> $ret_type pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut c_void, $($param: $param_type),*) -> $ret_type
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
@ -137,8 +133,7 @@ macro_rules! create_wrapper {
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
@ -155,8 +150,7 @@ macro_rules! create_pre_exec_wrapper {
paste::paste! { paste::paste! {
pub extern "C" fn [<$name _pre_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*) pub extern "C" fn [<$name _pre_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
@ -186,8 +180,7 @@ macro_rules! create_post_exec_wrapper {
paste::paste! { paste::paste! {
pub extern "C" fn [<$name _post_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*) pub extern "C" fn [<$name _post_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
@ -217,8 +210,7 @@ macro_rules! create_gen_wrapper {
paste::paste! { paste::paste! {
pub extern "C" fn [<$name _gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type pub extern "C" fn [<$name _gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
@ -248,8 +240,7 @@ macro_rules! create_post_gen_wrapper {
paste::paste! { paste::paste! {
pub extern "C" fn [<$name _post_gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) pub extern "C" fn [<$name _post_gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
@ -278,8 +269,7 @@ macro_rules! create_exec_wrapper {
paste::paste! { paste::paste! {
pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where where
ET: EmulatorModuleTuple<S>, S: UsesInput + Unpin,
S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(); let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();

View File

@ -6,7 +6,7 @@
use core::fmt; use core::fmt;
use std::{ use std::{
cmp::{Ordering, PartialOrd}, cmp::{Ordering, PartialOrd},
ffi::CString, ffi::{c_void, CString},
fmt::{Display, Formatter}, fmt::{Display, Formatter},
intrinsics::{copy_nonoverlapping, transmute}, intrinsics::{copy_nonoverlapping, transmute},
mem::MaybeUninit, mem::MaybeUninit,
@ -156,12 +156,12 @@ pub struct QemuMemoryChunk {
#[allow(clippy::vec_box)] #[allow(clippy::vec_box)]
static mut GDB_COMMANDS: Vec<Box<FatPtr>> = vec![]; static mut GDB_COMMANDS: Vec<Box<FatPtr>> = 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 { unsafe {
let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Qemu, &'r str) -> bool>); let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Qemu, &'r str) -> bool>);
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len));
let qemu = Qemu::get_unchecked(); 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 val = GuestReg::to_le(val.into());
let success = 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 { if success == 0 {
Err(QemuRWError { Err(QemuRWError {
kind: QemuRWErrorKind::Write, kind: QemuRWErrorKind::Write,
@ -780,7 +780,7 @@ impl Qemu {
Box<dyn for<'a, 'b> FnMut(&'a Qemu, &'b str) -> bool>, Box<dyn for<'a, 'b> FnMut(&'a Qemu, &'b str) -> bool>,
FatPtr, FatPtr,
>(callback)); >(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); GDB_COMMANDS.push(fat);
} }
} }

View File

@ -207,12 +207,12 @@ impl Qemu {
pub fn save_snapshot(&self, name: &str, sync: bool) { pub fn save_snapshot(&self, name: &str, sync: bool) {
let s = CString::new(name).expect("Invalid snapshot name"); 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) { pub fn load_snapshot(&self, name: &str, sync: bool) {
let s = CString::new(name).expect("Invalid snapshot name"); 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] #[must_use]

View File

@ -6,10 +6,10 @@ use std::{
use libafl_qemu_sys::{ use libafl_qemu_sys::{
exec_path, free_self_maps, guest_base, libafl_force_dfl, libafl_get_brk, libafl_load_addr, 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, 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, pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot,
IntervalTreeRoot, MapInfo, MmapPerms, VerifyAccess, MapInfo, MmapPerms, VerifyAccess,
}; };
use libc::c_int; use libc::{c_char, c_int, strlen};
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python}; use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python};
@ -138,7 +138,12 @@ impl Qemu {
#[must_use] #[must_use]
pub fn binary_path<'a>(&self) -> &'a str { 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] #[must_use]

View File

@ -4,14 +4,9 @@ use std::{
}; };
use enum_map::Enum; use enum_map::Enum;
use libafl::state::{HasExecutions, State}; use libafl::inputs::UsesInput;
use crate::{ use crate::{command::IsCommand, get_exit_arch_regs, GuestReg, Regs, CPU};
command::{CommandManager, IsCommand},
get_exit_arch_regs,
modules::EmulatorModuleTuple,
EmulatorExitHandler, GuestReg, Regs, CPU,
};
#[derive(Debug, Clone, Enum)] #[derive(Debug, Clone, Enum)]
pub enum ExitArgs { pub enum ExitArgs {
@ -28,20 +23,14 @@ pub enum ExitArgs {
#[derive(Debug)] #[derive(Debug)]
pub struct SyncExit<CM, EH, ET, S> pub struct SyncExit<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
command: Rc<dyn IsCommand<CM, EH, ET, S>>, command: Rc<dyn IsCommand<CM, EH, ET, S>>,
} }
impl<CM, EH, ET, S> SyncExit<CM, EH, ET, S> impl<CM, EH, ET, S> SyncExit<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
#[must_use] #[must_use]
pub fn new(command: Rc<dyn IsCommand<CM, EH, ET, S>>) -> Self { pub fn new(command: Rc<dyn IsCommand<CM, EH, ET, S>>) -> Self {
@ -66,10 +55,7 @@ where
impl<CM, EH, ET, S> Display for SyncExit<CM, EH, ET, S> impl<CM, EH, ET, S> Display for SyncExit<CM, EH, ET, S>
where where
CM: CommandManager<EH, ET, S>, S: UsesInput,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.command) write!(f, "{}", self.command)