Qemu generics cleanup (#2484)
* cleanup generics * remove most extern C * update qemu to latest revision * executor trait bounds minimization
This commit is contained in:
parent
13ba32ed2a
commit
6979032ad9
@ -61,6 +61,7 @@ const WRAPPER_HEADER: &str = r#"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/replay.h"
|
||||
|
||||
#include "libafl/qemu_snapshot.h"
|
||||
#include "libafl/syx-snapshot/device-save.h"
|
||||
#include "libafl/syx-snapshot/syx-snapshot.h"
|
||||
|
||||
@ -82,6 +83,8 @@ const WRAPPER_HEADER: &str = r#"
|
||||
|
||||
#include "qemu/plugin-memory.h"
|
||||
|
||||
#include "libafl/cpu.h"
|
||||
#include "libafl/gdb.h"
|
||||
#include "libafl/exit.h"
|
||||
#include "libafl/jit.h"
|
||||
#include "libafl/utils.h"
|
||||
|
@ -11,7 +11,7 @@ use crate::cargo_add_rpath;
|
||||
|
||||
pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
||||
pub const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
||||
pub const QEMU_REVISION: &str = "86d38fbfa7e632b3a4a14def14a11b9b9ba1642d";
|
||||
pub const QEMU_REVISION: &str = "7f468ebba6ec4b74d6ca6f4267f365f551c71fe4";
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub struct BuildResult {
|
||||
|
@ -421,6 +421,8 @@ pub fn maybe_generate_stub_bindings(
|
||||
force_regeneration,
|
||||
);
|
||||
}
|
||||
} else if env::var("CARGO_CFG_DOC").is_ok() {
|
||||
println!("cargo:warning=Bindings regeneration has been skipped. Please rerun with x86_64 with usermode to trigger the bindings regeneration.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,11 @@ __Warning__: The documentation is built by default for `x86_64` in `usermode`. T
|
||||
#![allow(clippy::pedantic)]
|
||||
#![cfg_attr(nightly, feature(used_with_arg))]
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use core::ops::BitAnd;
|
||||
use std::ffi::c_void;
|
||||
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use paste::paste;
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
#[cfg(all(not(feature = "clippy"), target_os = "linux"))]
|
||||
@ -40,6 +43,8 @@ pub use bindings::*;
|
||||
#[allow(dead_code)]
|
||||
#[rustfmt::skip]
|
||||
mod x86_64_stub_bindings;
|
||||
#[cfg(any(feature = "clippy", not(target_os = "linux")))]
|
||||
pub use x86_64_stub_bindings::*;
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
mod usermode;
|
||||
@ -115,25 +120,18 @@ macro_rules! extern_c_checked {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use core::ops::BitAnd;
|
||||
use std::ffi::c_void;
|
||||
pub type CPUStatePtr = *mut CPUState;
|
||||
pub type CPUArchStatePtr = *mut CPUArchState;
|
||||
pub type ExitReasonPtr = *mut libafl_exit_reason;
|
||||
|
||||
#[cfg(any(feature = "clippy", not(target_os = "linux")))]
|
||||
pub use x86_64_stub_bindings::*;
|
||||
pub type GuestUsize = target_ulong;
|
||||
pub type GuestIsize = target_long;
|
||||
|
||||
pub type CPUStatePtr = *mut crate::CPUState;
|
||||
pub type CPUArchStatePtr = *mut crate::CPUArchState;
|
||||
pub type ExitReasonPtr = *mut crate::libafl_exit_reason;
|
||||
pub type GuestAddr = target_ulong;
|
||||
pub type GuestPhysAddr = hwaddr;
|
||||
pub type GuestVirtAddr = vaddr;
|
||||
|
||||
pub type GuestUsize = crate::target_ulong;
|
||||
pub type GuestIsize = crate::target_long;
|
||||
|
||||
pub type GuestAddr = crate::target_ulong;
|
||||
pub type GuestPhysAddr = crate::hwaddr;
|
||||
pub type GuestVirtAddr = crate::vaddr;
|
||||
|
||||
pub type GuestHwAddrInfo = crate::qemu_plugin_hwaddr;
|
||||
pub type GuestHwAddrInfo = qemu_plugin_hwaddr;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -177,37 +175,3 @@ pub fn make_plugin_meminfo(oi: MemOpIdx, rw: qemu_plugin_mem_rw) -> qemu_plugin_
|
||||
pub fn cpu_env(cpu: *mut CPUState) -> *mut CPUArchState {
|
||||
unsafe { cpu.add(1) as *mut CPUArchState }
|
||||
}
|
||||
|
||||
extern_c_checked! {
|
||||
//static libafl_page_size: GuestUsize;
|
||||
pub fn libafl_page_from_addr(addr: GuestAddr) -> GuestAddr;
|
||||
|
||||
// CPUState* libafl_qemu_get_cpu(int cpu_index);
|
||||
pub fn libafl_qemu_get_cpu(cpu_index: i32) -> CPUStatePtr;
|
||||
// int libafl_qemu_num_cpus(void);
|
||||
pub fn libafl_qemu_num_cpus() -> i32;
|
||||
// CPUState* libafl_qemu_current_cpu(void);
|
||||
pub fn libafl_qemu_current_cpu() -> CPUStatePtr;
|
||||
|
||||
// struct libafl_exit_reason* libafl_get_exit_reason(void);
|
||||
// fn libafl_get_exit_reason() -> ExitReasonPtr;
|
||||
|
||||
pub fn libafl_qemu_cpu_index(cpu: CPUStatePtr) -> i32;
|
||||
|
||||
pub fn libafl_qemu_write_reg(cpu: CPUStatePtr, reg: i32, val: *const u8) -> i32;
|
||||
pub fn libafl_qemu_read_reg(cpu: CPUStatePtr, reg: i32, val: *mut u8) -> i32;
|
||||
pub fn libafl_qemu_num_regs(cpu: CPUStatePtr) -> i32;
|
||||
|
||||
// fn libafl_qemu_set_breakpoint(addr: u64) -> i32;
|
||||
// fn libafl_qemu_remove_breakpoint(addr: u64) -> i32;
|
||||
pub fn libafl_flush_jit();
|
||||
// fn libafl_qemu_trigger_breakpoint(cpu: CPUStatePtr);
|
||||
|
||||
pub fn strlen(s: *const u8) -> usize;
|
||||
|
||||
pub fn libafl_qemu_add_gdb_cmd(
|
||||
callback: extern "C" fn(*const (), *const u8, usize) -> i32,
|
||||
data: *const ()
|
||||
);
|
||||
pub fn libafl_qemu_gdb_reply(buf: *const u8, len: usize);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use paste::paste;
|
||||
|
||||
use crate::{extern_c_checked, CPUStatePtr, GuestPhysAddr};
|
||||
use crate::extern_c_checked;
|
||||
|
||||
extern_c_checked! {
|
||||
pub fn qemu_init(argc: i32, argv: *const *const u8, envp: *const *const u8);
|
||||
@ -8,9 +8,4 @@ extern_c_checked! {
|
||||
pub fn vm_start();
|
||||
pub fn qemu_main_loop();
|
||||
pub fn qemu_cleanup();
|
||||
|
||||
pub fn libafl_save_qemu_snapshot(name: *const u8, sync: bool);
|
||||
pub fn libafl_load_qemu_snapshot(name: *const u8, sync: bool);
|
||||
|
||||
pub fn libafl_qemu_current_paging_id(cpu: CPUStatePtr) -> GuestPhysAddr;
|
||||
}
|
||||
|
@ -1,22 +1,17 @@
|
||||
use core::{slice::from_raw_parts, str::from_utf8_unchecked};
|
||||
|
||||
use libc::{c_char, strlen};
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
use paste::paste;
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python};
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use crate::{extern_c_checked, libafl_mapinfo, strlen, GuestAddr, MmapPerms};
|
||||
use crate::{extern_c_checked, libafl_mapinfo, GuestAddr, MmapPerms};
|
||||
|
||||
extern_c_checked! {
|
||||
pub fn qemu_user_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
|
||||
|
||||
pub fn libafl_qemu_run() -> i32;
|
||||
|
||||
pub fn libafl_load_addr() -> u64;
|
||||
pub fn libafl_get_brk() -> u64;
|
||||
pub fn libafl_set_brk(brk: u64) -> u64;
|
||||
|
||||
pub static exec_path: *const u8;
|
||||
pub static guest_base: usize;
|
||||
pub static mut mmap_next_start: GuestAddr;
|
||||
@ -130,7 +125,7 @@ impl From<libafl_mapinfo> for MapInfo {
|
||||
Some(
|
||||
from_utf8_unchecked(from_raw_parts(
|
||||
map_info.path as *const u8,
|
||||
strlen(map_info.path as *const u8),
|
||||
strlen(map_info.path as *const c_char),
|
||||
))
|
||||
.to_string(),
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 1.82.0-nightly */
|
||||
/* qemu git hash: 8f61fadbec181bfcbd305ba92a86a41376a476f7 */
|
||||
/* qemu git hash: 31ee26f97071d5bed1ac1e7de75beea755b198d6 */
|
||||
/* automatically generated by rust-bindgen 0.69.4 */
|
||||
|
||||
#[repr(C)]
|
||||
@ -12631,6 +12631,408 @@ pub struct MemOp(pub ::std::os::raw::c_uint);
|
||||
pub type MemOpIdx = u32;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct image_info {
|
||||
pub load_bias: abi_ulong,
|
||||
pub load_addr: abi_ulong,
|
||||
pub start_code: abi_ulong,
|
||||
pub end_code: abi_ulong,
|
||||
pub start_data: abi_ulong,
|
||||
pub end_data: abi_ulong,
|
||||
pub brk: abi_ulong,
|
||||
pub start_stack: abi_ulong,
|
||||
pub stack_limit: abi_ulong,
|
||||
pub vdso: abi_ulong,
|
||||
pub entry: abi_ulong,
|
||||
pub code_offset: abi_ulong,
|
||||
pub data_offset: abi_ulong,
|
||||
pub saved_auxv: abi_ulong,
|
||||
pub auxv_len: abi_ulong,
|
||||
pub argc: abi_ulong,
|
||||
pub argv: abi_ulong,
|
||||
pub envc: abi_ulong,
|
||||
pub envp: abi_ulong,
|
||||
pub file_string: abi_ulong,
|
||||
pub elf_flags: u32,
|
||||
pub personality: ::std::os::raw::c_int,
|
||||
pub alignment: abi_ulong,
|
||||
pub exec_stack: bool,
|
||||
pub arg_strings: abi_ulong,
|
||||
pub env_strings: abi_ulong,
|
||||
pub loadmap_addr: abi_ulong,
|
||||
pub nsegs: u16,
|
||||
pub loadsegs: *mut ::std::os::raw::c_void,
|
||||
pub pt_dynamic_addr: abi_ulong,
|
||||
pub interpreter_loadmap_addr: abi_ulong,
|
||||
pub interpreter_pt_dynamic_addr: abi_ulong,
|
||||
pub other_info: *mut image_info,
|
||||
pub note_flags: u32,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_image_info() {
|
||||
const UNINIT: ::std::mem::MaybeUninit<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 ptr: *const ::std::os::raw::c_void,
|
||||
pub size: usize,
|
||||
@ -12900,9 +13302,6 @@ extern "C" {
|
||||
#[doc = " free_self_maps:\n @info: an interval tree\n\n Free a tree of MapInfo structures."]
|
||||
pub fn free_self_maps(root: *mut IntervalTreeRoot);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_set_breakpoint(pc: target_ulong) -> ::std::os::raw::c_int;
|
||||
}
|
||||
@ -13330,6 +13729,9 @@ impl Default for libafl_mapinfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_handle_crash(
|
||||
host_sig: ::std::os::raw::c_int,
|
||||
@ -13347,6 +13749,18 @@ extern "C" {
|
||||
ret: *mut libafl_mapinfo,
|
||||
) -> *mut IntervalTreeNode;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_load_addr() -> u64;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_get_image_info() -> *mut image_info;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_get_brk() -> u64;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_set_brk(new_brk: u64) -> u64;
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct AccelCPUClass {
|
||||
@ -14389,6 +14803,71 @@ extern "C" {
|
||||
data: *mut qemu_plugin_hwaddr,
|
||||
) -> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_page_from_addr(addr: target_ulong) -> target_ulong;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_get_cpu(cpu_index: ::std::os::raw::c_int) -> *mut CPUState;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_num_cpus() -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_current_cpu() -> *mut CPUState;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_cpu_index(arg1: *mut CPUState) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_write_reg(
|
||||
cpu: *mut CPUState,
|
||||
reg: ::std::os::raw::c_int,
|
||||
val: *mut u8,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_read_reg(
|
||||
cpu: *mut CPUState,
|
||||
reg: ::std::os::raw::c_int,
|
||||
val: *mut u8,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_num_regs(cpu: *mut CPUState) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_flush_jit();
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_main() -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_run() -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_set_qemu_env(env: *mut CPUArchState);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_add_gdb_cmd(
|
||||
callback: ::std::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
arg1: *mut ::std::os::raw::c_void,
|
||||
arg2: *mut u8,
|
||||
arg3: usize,
|
||||
) -> bool,
|
||||
>,
|
||||
data: *mut ::std::os::raw::c_void,
|
||||
);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_gdb_reply(buf: *const u8, len: usize);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_qemu_gdb_exec() -> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn libafl_jit_trace_edge_hitcount(data: u64, id: u64) -> usize;
|
||||
}
|
||||
|
@ -9,14 +9,10 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
use libafl::state::{HasExecutions, State};
|
||||
use libafl::inputs::UsesInput;
|
||||
use libafl_qemu_sys::GuestAddr;
|
||||
|
||||
use crate::{
|
||||
command::{CommandManager, IsCommand},
|
||||
modules::EmulatorModuleTuple,
|
||||
EmulatorExitHandler, Qemu,
|
||||
};
|
||||
use crate::{command::IsCommand, Qemu};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
@ -26,10 +22,7 @@ pub struct BreakpointId(u64);
|
||||
#[derive(Debug)]
|
||||
pub struct Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
id: BreakpointId,
|
||||
addr: GuestAddr,
|
||||
@ -56,10 +49,7 @@ impl Default for BreakpointId {
|
||||
|
||||
impl<CM, EH, ET, S> Hash for Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
@ -68,31 +58,18 @@ where
|
||||
|
||||
impl<CM, EH, ET, S> PartialEq for Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
|
||||
impl<CM, EH, ET, S> Eq for Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
{
|
||||
}
|
||||
impl<CM, EH, ET, S> Eq for Breakpoint<CM, EH, ET, S> where S: UsesInput {}
|
||||
|
||||
impl<CM, EH, ET, S> Display for Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Breakpoint @vaddr 0x{:x}", self.addr)
|
||||
@ -101,10 +78,7 @@ where
|
||||
|
||||
impl<CM, EH, ET, S> Borrow<BreakpointId> for Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn borrow(&self) -> &BreakpointId {
|
||||
&self.id
|
||||
@ -113,10 +87,7 @@ where
|
||||
|
||||
impl<CM, EH, ET, S> Borrow<GuestAddr> for Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn borrow(&self) -> &GuestAddr {
|
||||
&self.addr
|
||||
@ -125,10 +96,7 @@ where
|
||||
|
||||
impl<CM, EH, ET, S> Breakpoint<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
// Emu will return with the breakpoint as exit reason.
|
||||
#[must_use]
|
||||
|
@ -9,8 +9,7 @@ use hashbrown::HashMap;
|
||||
use hashbrown::HashSet;
|
||||
use libafl::{
|
||||
executors::ExitKind,
|
||||
inputs::HasTargetBytes,
|
||||
state::{HasExecutions, State},
|
||||
inputs::{HasTargetBytes, UsesInput},
|
||||
};
|
||||
use libafl_bolts::AsSlice;
|
||||
use num_enum::TryFromPrimitive;
|
||||
@ -25,12 +24,11 @@ use crate::{
|
||||
},
|
||||
get_exit_arch_regs,
|
||||
modules::{
|
||||
EmulatorModuleTuple, HasInstrumentationFilter, IsFilter,
|
||||
QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter,
|
||||
HasInstrumentationFilter, QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter,
|
||||
},
|
||||
sync_exit::ExitArgs,
|
||||
Emulator, EmulatorExitHandler, ExitHandlerError, ExitHandlerResult, GuestReg, InputLocation,
|
||||
IsSnapshotManager, Qemu, QemuMemoryChunk, QemuRWError, Regs, StdEmulatorExitHandler, CPU,
|
||||
Emulator, ExitHandlerError, ExitHandlerResult, GuestReg, InputLocation, IsSnapshotManager,
|
||||
Qemu, QemuMemoryChunk, QemuRWError, Regs, StdEmulatorExitHandler, CPU,
|
||||
};
|
||||
|
||||
pub mod parser;
|
||||
@ -55,10 +53,7 @@ macro_rules! define_std_command_manager {
|
||||
($name:ident, [$($native_command_parser:ident),+]) => {
|
||||
pub struct $name<ET, S, SM>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
S: UsesInput,
|
||||
{
|
||||
native_command_parsers:
|
||||
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>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
ET: StdInstrumentationFilter + Unpin,
|
||||
S: UsesInput + Unpin,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
@ -105,10 +100,7 @@ macro_rules! define_std_command_manager {
|
||||
|
||||
impl<ET, S, SM> CommandManager<StdEmulatorExitHandler<SM>, ET, S> for $name<ET, S, SM>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn parse(
|
||||
&self,
|
||||
@ -129,10 +121,7 @@ macro_rules! define_std_command_manager {
|
||||
|
||||
impl<ET, S, SM> Debug for $name<ET, S, SM>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
write!(f, stringify!($name))
|
||||
@ -141,8 +130,8 @@ macro_rules! define_std_command_manager {
|
||||
|
||||
impl<ET, S, SM> Default for $name<ET, S, SM>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
ET: StdInstrumentationFilter + Unpin,
|
||||
S: UsesInput + Unpin,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
@ -157,9 +146,7 @@ pub struct NopCommandManager;
|
||||
|
||||
impl<EH, ET, S> CommandManager<EH, ET, S> for NopCommandManager
|
||||
where
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn parse(&self, _qemu: Qemu) -> Result<Rc<dyn IsCommand<Self, EH, ET, S>>, CommandError> {
|
||||
Ok(Rc::new(NopCommand))
|
||||
@ -183,9 +170,7 @@ define_std_command_manager!(
|
||||
|
||||
pub trait CommandManager<EH, ET, S>: Sized
|
||||
where
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
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
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
/// Used to know whether the command can be run during a backdoor, or if it is necessary to go out of
|
||||
/// the QEMU VM to run the command.
|
||||
@ -251,10 +233,7 @@ impl Display for NopCommand {
|
||||
|
||||
impl<CM, EH, ET, S> IsCommand<CM, EH, ET, S> for NopCommand
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
true
|
||||
@ -275,10 +254,8 @@ pub struct SaveCommand;
|
||||
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for SaveCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
ET: StdInstrumentationFilter + Unpin,
|
||||
S: UsesInput + Unpin,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
@ -329,10 +306,7 @@ pub struct LoadCommand;
|
||||
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for LoadCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
S: UsesInput,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
@ -374,11 +348,8 @@ pub struct InputCommand {
|
||||
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for InputCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
true
|
||||
@ -410,9 +381,7 @@ pub struct StartCommand {
|
||||
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for StartCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
@ -460,10 +429,7 @@ pub struct EndCommand(Option<ExitKind>);
|
||||
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for EndCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
S: UsesInput,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
@ -501,11 +467,7 @@ pub struct VersionCommand(u64);
|
||||
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for VersionCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
true
|
||||
@ -531,21 +493,15 @@ where
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FilterCommand<T>
|
||||
where
|
||||
T: IsFilter + Debug,
|
||||
{
|
||||
pub struct FilterCommand<T> {
|
||||
filter: T,
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for PagingFilterCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
ET: StdInstrumentationFilter + Unpin,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
true
|
||||
@ -571,11 +527,7 @@ where
|
||||
|
||||
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorExitHandler<SM>, ET, S> for AddressRangeFilterCommand
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn usable_at_runtime(&self) -> bool {
|
||||
true
|
||||
@ -609,10 +561,7 @@ impl VersionCommand {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FilterCommand<T>
|
||||
where
|
||||
T: IsFilter + Debug,
|
||||
{
|
||||
impl<T> FilterCommand<T> {
|
||||
pub fn new(filter: T) -> Self {
|
||||
Self { filter }
|
||||
}
|
||||
|
@ -1,34 +1,27 @@
|
||||
use std::{fmt::Debug, rc::Rc, sync::OnceLock};
|
||||
use std::{rc::Rc, sync::OnceLock};
|
||||
|
||||
use enum_map::{enum_map, EnumMap};
|
||||
use libafl::{
|
||||
executors::ExitKind,
|
||||
inputs::HasTargetBytes,
|
||||
state::{HasExecutions, State},
|
||||
inputs::{HasTargetBytes, UsesInput},
|
||||
};
|
||||
use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr};
|
||||
|
||||
use crate::{
|
||||
command::{
|
||||
bindings, CommandError, CommandManager, EndCommand, FilterCommand, InputCommand, IsCommand,
|
||||
LoadCommand, NativeExitKind, SaveCommand, StartCommand, VersionCommand,
|
||||
},
|
||||
modules::{
|
||||
EmulatorModuleTuple, QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter,
|
||||
bindings, CommandError, EndCommand, FilterCommand, InputCommand, IsCommand, LoadCommand,
|
||||
NativeExitKind, SaveCommand, StartCommand, VersionCommand,
|
||||
},
|
||||
modules::{QemuInstrumentationAddressRangeFilter, StdInstrumentationFilter},
|
||||
sync_exit::ExitArgs,
|
||||
EmulatorExitHandler, GuestReg, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs,
|
||||
StdEmulatorExitHandler,
|
||||
GuestReg, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs, StdEmulatorExitHandler,
|
||||
};
|
||||
|
||||
pub static EMU_EXIT_KIND_MAP: OnceLock<EnumMap<NativeExitKind, Option<ExitKind>>> = OnceLock::new();
|
||||
|
||||
pub trait NativeCommandParser<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg;
|
||||
|
||||
@ -43,11 +36,8 @@ pub struct InputPhysCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
|
||||
for InputPhysCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg {
|
||||
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_PHYS.0)
|
||||
@ -76,11 +66,8 @@ pub struct InputVirtCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
|
||||
for InputVirtCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg {
|
||||
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_INPUT_VIRT.0)
|
||||
@ -105,9 +92,7 @@ pub struct StartPhysCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
|
||||
for StartPhysCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
@ -135,9 +120,7 @@ pub struct StartVirtCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
|
||||
for StartVirtCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
@ -164,10 +147,8 @@ where
|
||||
pub struct SaveCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for SaveCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
ET: StdInstrumentationFilter + Unpin,
|
||||
S: UsesInput + Unpin,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg {
|
||||
@ -186,10 +167,7 @@ where
|
||||
pub struct LoadCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for LoadCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
S: UsesInput,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg {
|
||||
@ -208,10 +186,7 @@ where
|
||||
pub struct EndCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S> for EndCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
S: UsesInput,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg {
|
||||
@ -244,11 +219,7 @@ pub struct VersionCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
|
||||
for VersionCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg {
|
||||
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VERSION.0)
|
||||
@ -269,11 +240,7 @@ pub struct VaddrFilterAllowRangeCommandParser;
|
||||
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorExitHandler<SM>, ET, S>
|
||||
for VaddrFilterAllowRangeCommandParser
|
||||
where
|
||||
CM: CommandManager<StdEmulatorExitHandler<SM>, ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn command_id(&self) -> GuestReg {
|
||||
GuestReg::from(bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_VADDR_FILTER_ALLOW.0)
|
||||
|
@ -99,8 +99,7 @@ where
|
||||
#[derive(Debug)]
|
||||
pub struct EmulatorModules<ET, S>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput,
|
||||
{
|
||||
qemu: Qemu,
|
||||
modules: Pin<Box<ET>>,
|
||||
@ -112,8 +111,7 @@ where
|
||||
#[derive(Debug)]
|
||||
pub struct EmulatorHooks<ET, S>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput,
|
||||
{
|
||||
qemu_hooks: QemuHooks,
|
||||
phantom: PhantomData<(ET, S)>,
|
||||
@ -143,8 +141,7 @@ where
|
||||
|
||||
impl<ET, S> EmulatorHooks<ET, S>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
#[must_use]
|
||||
pub fn new(qemu_hooks: QemuHooks) -> Self {
|
||||
@ -886,7 +883,6 @@ where
|
||||
|
||||
impl<ET, S> Default for EmulatorHooks<ET, S>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
{
|
||||
fn default() -> Self {
|
||||
@ -896,112 +892,8 @@ where
|
||||
|
||||
impl<ET, S> EmulatorModules<ET, S>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: 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).
|
||||
///
|
||||
/// # Safety
|
||||
@ -1037,6 +929,16 @@ where
|
||||
pub unsafe fn emulator_modules_mut<'a>() -> Option<&'a mut EmulatorModules<ET, S>> {
|
||||
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(
|
||||
&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
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
impl<ET, S> EmulatorModules<ET, S>
|
||||
@ -1290,8 +1299,7 @@ where
|
||||
|
||||
impl<ET, S> Drop for EmulatorModules<ET, S>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
// Make the global pointer null at drop time
|
||||
|
@ -17,24 +17,20 @@ use std::{
|
||||
use hashbrown::HashMap;
|
||||
use libafl::{
|
||||
executors::ExitKind,
|
||||
inputs::HasTargetBytes,
|
||||
inputs::{HasTargetBytes, UsesInput},
|
||||
observers::ObserversTuple,
|
||||
state::{HasExecutions, State},
|
||||
};
|
||||
use libafl_bolts::os::unix_signals::Signal;
|
||||
use libafl_qemu_sys::GuestUsize;
|
||||
pub use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr};
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
pub use libafl_qemu_sys::{MapInfo, MmapPerms, MmapPermsIter};
|
||||
use num_traits::Num;
|
||||
use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestUsize, GuestVirtAddr};
|
||||
use typed_builder::TypedBuilder;
|
||||
|
||||
use crate::{
|
||||
breakpoint::Breakpoint,
|
||||
command::{CommandError, InputCommand, IsCommand},
|
||||
breakpoint::{Breakpoint, BreakpointId},
|
||||
command::{CommandError, CommandManager, InputCommand, IsCommand},
|
||||
modules::EmulatorModuleTuple,
|
||||
sync_exit::SyncExit,
|
||||
GuestReg, Qemu, QemuExitError, QemuExitReason, QemuInitError, QemuMemoryChunk, QemuRWError,
|
||||
QemuShutdownCause, QemuSnapshotCheckResult, Regs, CPU,
|
||||
Qemu, QemuExitError, QemuExitReason, QemuInitError, QemuMemoryChunk, QemuShutdownCause,
|
||||
QemuSnapshotCheckResult, Regs, CPU,
|
||||
};
|
||||
|
||||
mod hooks;
|
||||
@ -48,15 +44,52 @@ mod systemmode;
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
pub use systemmode::*;
|
||||
|
||||
use crate::{
|
||||
breakpoint::BreakpointId,
|
||||
command::CommandManager,
|
||||
modules::{EmulatorModuleTuple, StdInstrumentationFilter},
|
||||
};
|
||||
|
||||
type CommandRef<CM, E, ET, S> = Rc<dyn IsCommand<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)]
|
||||
pub enum GuestAddrKind {
|
||||
Physical(GuestPhysAddr),
|
||||
@ -66,10 +99,7 @@ pub enum GuestAddrKind {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EmulatorExitResult<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
QemuExit(QemuShutdownCause), // QEMU ended for some reason.
|
||||
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),
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub enum ExitHandlerError {
|
||||
QemuExitReasonError(EmulatorExitError),
|
||||
@ -125,6 +126,15 @@ pub enum ExitHandlerError {
|
||||
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)]
|
||||
pub enum SnapshotManagerError {
|
||||
SnapshotIdNotFound(SnapshotId),
|
||||
@ -137,12 +147,95 @@ pub enum SnapshotManagerCheckError {
|
||||
SnapshotCheckError(QemuSnapshotCheckResult),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct SnapshotId {
|
||||
id: u64,
|
||||
}
|
||||
|
||||
/// Special kind of Exit handler with no data embedded.
|
||||
/// As a result, it is safe to transmute from any `Emulator` implementing `EmuExitHandler` to this one,
|
||||
/// since it won't use any data which could cause type confusion.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NopEmulatorExitHandler;
|
||||
impl<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
|
||||
where
|
||||
CM: CommandManager<EH, ET, S> + Debug,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S> + Debug,
|
||||
S: Unpin + State + HasExecutions + Debug,
|
||||
CM: Debug,
|
||||
EH: Debug,
|
||||
ET: Debug,
|
||||
S: UsesInput + Debug,
|
||||
{
|
||||
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 {
|
||||
#[must_use]
|
||||
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.
|
||||
#[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,
|
||||
{
|
||||
impl<SM> StdEmulatorExitHandler<SM> {
|
||||
pub fn new(snapshot_manager: SM) -> Self {
|
||||
Self {
|
||||
snapshot_manager: RefCell::new(snapshot_manager),
|
||||
@ -342,8 +334,7 @@ where
|
||||
// TODO: replace handlers with generics to permit compile-time customization of handlers
|
||||
impl<ET, S, SM> EmulatorExitHandler<ET, S> for StdEmulatorExitHandler<SM>
|
||||
where
|
||||
ET: EmulatorModuleTuple<S> + StdInstrumentationFilter + Debug,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
S::Input: HasTargetBytes,
|
||||
SM: IsSnapshotManager,
|
||||
{
|
||||
@ -436,10 +427,7 @@ impl From<CommandError> for ExitHandlerError {
|
||||
|
||||
impl<CM, EH, ET, S> Display for EmulatorExitResult<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
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>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: Unpin,
|
||||
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>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
#[allow(clippy::must_use_candidate, clippy::similar_names)]
|
||||
pub fn new(
|
||||
@ -520,12 +492,35 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub fn modules(&self) -> &EmulatorModules<ET, S> {
|
||||
&self.modules
|
||||
pub fn first_exec_all(&mut self) {
|
||||
if self.first_exec {
|
||||
self.modules.first_exec_all();
|
||||
self.first_exec = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modules_mut(&mut self) -> &mut EmulatorModules<ET, S> {
|
||||
self.modules.as_mut().get_mut()
|
||||
pub fn pre_exec_all(&mut self, input: &S::Input) {
|
||||
self.modules.pre_exec_all(input);
|
||||
}
|
||||
|
||||
pub fn post_exec_all<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]
|
||||
@ -537,91 +532,85 @@ where
|
||||
pub fn exit_handler(&self) -> &RefCell<EH> {
|
||||
&self.exit_handler
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub fn num_cpus(&self) -> usize {
|
||||
self.qemu.num_cpus()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub fn current_cpu(&self) -> Option<CPU> {
|
||||
self.qemu.current_cpu()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub fn cpu_from_index(&self, index: usize) -> CPU {
|
||||
self.qemu.cpu_from_index(index)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub fn page_from_addr(&self, addr: GuestAddr) -> GuestAddr {
|
||||
self.qemu.page_from_addr(addr)
|
||||
}
|
||||
|
||||
//#[must_use]
|
||||
/*pub fn page_size() -> GuestUsize {
|
||||
unsafe { libafl_page_size }
|
||||
}*/
|
||||
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub unsafe fn write_mem(&self, addr: GuestAddr, buf: &[u8]) {
|
||||
self.qemu.write_mem(addr, buf);
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub unsafe fn read_mem(&self, addr: GuestAddr, buf: &mut [u8]) {
|
||||
self.qemu.read_mem(addr, buf);
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub fn num_regs(&self) -> i32 {
|
||||
self.qemu.num_regs()
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), QemuRWError>
|
||||
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
|
||||
where
|
||||
T: Num + PartialOrd + Copy + Into<GuestReg>,
|
||||
R: Into<i32> + Clone,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
self.qemu.write_reg(reg, val)
|
||||
/// 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 read_reg<R, T>(&self, reg: R) -> Result<T, QemuRWError>
|
||||
/// 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,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
|
||||
where
|
||||
T: Num + PartialOrd + Copy + From<GuestReg>,
|
||||
R: Into<i32> + Clone,
|
||||
S: UsesInput,
|
||||
{
|
||||
self.qemu.read_reg(reg)
|
||||
}
|
||||
|
||||
pub fn add_breakpoint(&self, mut bp: Breakpoint<CM, EH, ET, S>, enable: bool) -> BreakpointId {
|
||||
if enable {
|
||||
bp.enable(self.qemu);
|
||||
@ -671,120 +660,4 @@ where
|
||||
.remove(&bp_addr)
|
||||
.expect("Could not remove bp");
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
note = "This function has been moved to the `Qemu` low-level structure. Please access it through `emu.qemu()`."
|
||||
)]
|
||||
pub fn entry_break(&self, addr: GuestAddr) {
|
||||
self.qemu.entry_break(addr);
|
||||
}
|
||||
|
||||
pub fn first_exec_all(&mut self) {
|
||||
if self.first_exec {
|
||||
self.modules.first_exec_all();
|
||||
self.first_exec = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pre_exec_all(&mut self, input: &S::Input) {
|
||||
self.modules.pre_exec_all(input);
|
||||
}
|
||||
|
||||
pub fn post_exec_all<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);
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,12 @@ use std::{
|
||||
};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use libafl::state::{HasExecutions, State};
|
||||
use libafl::inputs::UsesInput;
|
||||
use libafl_qemu_sys::GuestPhysAddr;
|
||||
|
||||
use crate::{
|
||||
command::CommandManager, emu::IsSnapshotManager, modules::EmulatorModuleTuple,
|
||||
DeviceSnapshotFilter, Emulator, EmulatorExitHandler, Qemu, QemuSnapshotCheckResult, SnapshotId,
|
||||
SnapshotManagerError,
|
||||
emu::IsSnapshotManager, DeviceSnapshotFilter, Emulator, Qemu, QemuSnapshotCheckResult,
|
||||
SnapshotId, SnapshotManagerError,
|
||||
};
|
||||
|
||||
impl SnapshotId {
|
||||
@ -173,10 +172,7 @@ impl IsSnapshotManager for FastSnapshotManager {
|
||||
|
||||
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
/// Write a value to a phsical guest address, including ROM areas.
|
||||
pub unsafe fn write_phys_mem(&self, paddr: GuestPhysAddr, buf: &[u8]) {
|
||||
|
@ -1,18 +1,11 @@
|
||||
use libafl::inputs::UsesInput;
|
||||
use libafl_qemu_sys::{GuestAddr, MmapPerms, VerifyAccess};
|
||||
|
||||
use crate::{
|
||||
command::CommandManager,
|
||||
emu::{HasExecutions, State},
|
||||
modules::EmulatorModuleTuple,
|
||||
Emulator, EmulatorExitHandler, GuestMaps,
|
||||
};
|
||||
use crate::{Emulator, GuestMaps};
|
||||
|
||||
impl<CM, EH, ET, S> Emulator<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
/// This function gets the memory mappings from the emulator.
|
||||
#[must_use]
|
||||
|
@ -20,6 +20,7 @@ use libafl::{
|
||||
},
|
||||
feedbacks::Feedback,
|
||||
fuzzer::HasObjective,
|
||||
inputs::UsesInput,
|
||||
observers::{ObserversTuple, UsesObservers},
|
||||
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
|
||||
Error, ExecutionProcessor, HasScheduler,
|
||||
@ -27,28 +28,26 @@ use libafl::{
|
||||
#[cfg(feature = "fork")]
|
||||
use libafl_bolts::shmem::ShMemProvider;
|
||||
use libafl_bolts::{
|
||||
os::unix_signals::{siginfo_t, ucontext_t, Signal},
|
||||
os::unix_signals::{ucontext_t, Signal},
|
||||
tuples::RefIndexable,
|
||||
};
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
use libafl_qemu_sys::libafl_qemu_handle_crash;
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
use libafl_qemu_sys::qemu_system_debug_request;
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
use libafl_qemu_sys::siginfo_t;
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
use libc::siginfo_t;
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
use crate::EmulatorModules;
|
||||
use crate::{command::CommandManager, modules::EmulatorModuleTuple, Emulator, EmulatorExitHandler};
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
extern "C" {
|
||||
// Original QEMU user signal handler
|
||||
fn libafl_qemu_handle_crash(signal: i32, info: *mut siginfo_t, puc: *mut c_void);
|
||||
}
|
||||
|
||||
pub struct QemuExecutor<'a, CM, EH, H, OT, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: State,
|
||||
OT: ObserversTuple<S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
{
|
||||
@ -56,41 +55,33 @@ where
|
||||
}
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
pub unsafe fn inproc_qemu_crash_handler<'a, E, EM, OF, Z, ET, S>(
|
||||
pub unsafe fn inproc_qemu_crash_handler(
|
||||
signal: Signal,
|
||||
info: &'a mut siginfo_t,
|
||||
mut context: Option<&'a mut ucontext_t>,
|
||||
_data: &'a mut InProcessExecutorHandlerData,
|
||||
) where
|
||||
E: Executor<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,
|
||||
{
|
||||
info: &mut siginfo_t,
|
||||
mut context: Option<&mut ucontext_t>,
|
||||
_data: &mut InProcessExecutorHandlerData,
|
||||
) {
|
||||
let puc = match &mut context {
|
||||
Some(v) => ptr::from_mut::<ucontext_t>(*v) as *mut c_void,
|
||||
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")]
|
||||
pub(crate) static mut BREAK_ON_TMOUT: bool = false;
|
||||
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
pub unsafe fn inproc_qemu_timeout_handler<'a, E, EM, OF, Z>(
|
||||
pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
|
||||
signal: Signal,
|
||||
info: &'a mut siginfo_t,
|
||||
context: Option<&'a mut ucontext_t>,
|
||||
data: &'a mut InProcessExecutorHandlerData,
|
||||
info: &mut siginfo_t,
|
||||
context: Option<&mut ucontext_t>,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
) where
|
||||
E: Executor<EM, Z> + HasObservers + HasInProcessHooks<E::State>,
|
||||
E: HasObservers + HasInProcessHooks<E::State>,
|
||||
EM: EventFirer<State = E::State> + EventRestarter<State = 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,
|
||||
{
|
||||
if BREAK_ON_TMOUT {
|
||||
@ -104,10 +95,8 @@ pub unsafe fn inproc_qemu_timeout_handler<'a, E, EM, OF, Z>(
|
||||
|
||||
impl<'a, CM, EH, H, OT, ET, S> Debug for QemuExecutor<'a, CM, EH, H, OT, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: State,
|
||||
OT: ObserversTuple<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>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: State,
|
||||
OT: ObserversTuple<S>,
|
||||
ET: EmulatorModuleTuple<S> + Debug,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
{
|
||||
pub fn new<EM, OF, Z>(
|
||||
emulator: Emulator<CM, EH, ET, S>,
|
||||
@ -140,7 +127,7 @@ where
|
||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||
OF: Feedback<S>,
|
||||
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(
|
||||
harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout,
|
||||
@ -148,14 +135,7 @@ where
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
{
|
||||
inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler::<
|
||||
StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, EH, ET, S>>,
|
||||
EM,
|
||||
OF,
|
||||
Z,
|
||||
ET,
|
||||
S,
|
||||
> as *const c_void;
|
||||
inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler as *const c_void;
|
||||
|
||||
let handler = |emulator_modules: &mut EmulatorModules<ET, S>, 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
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||
EM: UsesState<State = S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
|
||||
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
|
||||
OT: ObserversTuple<S>,
|
||||
OF: Feedback<S>,
|
||||
ET: EmulatorModuleTuple<S> + Debug,
|
||||
Z: HasObjective<Objective = OF, State = S>,
|
||||
S: State + HasExecutions + Unpin,
|
||||
Z: UsesState<State = S>,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
@ -241,34 +218,28 @@ where
|
||||
|
||||
impl<'a, CM, EH, H, OT, ET, S> UsesState for QemuExecutor<'a, CM, EH, H, OT, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
|
||||
S: State,
|
||||
OT: ObserversTuple<S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
{
|
||||
type State = S;
|
||||
}
|
||||
|
||||
impl<'a, CM, EH, H, OT, ET, S> UsesObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
|
||||
S: State,
|
||||
OT: ObserversTuple<S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
{
|
||||
type Observers = OT;
|
||||
}
|
||||
|
||||
impl<'a, CM, EH, H, OT, ET, S> HasObservers for QemuExecutor<'a, CM, EH, H, OT, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: State,
|
||||
OT: ObserversTuple<S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
{
|
||||
@ -286,14 +257,12 @@ where
|
||||
#[cfg(feature = "fork")]
|
||||
pub struct QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
|
||||
where
|
||||
CM: CommandManager<EH, 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>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||
OT: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
SP: ShMemProvider,
|
||||
Z: UsesState<State = S>,
|
||||
{
|
||||
inner: InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>,
|
||||
@ -304,14 +273,14 @@ where
|
||||
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> Debug
|
||||
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S> + 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,
|
||||
CM: Debug,
|
||||
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>,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
@ -323,19 +292,15 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "fork")]
|
||||
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z, OF> QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
|
||||
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
H: FnMut(&S::Input) -> ExitKind,
|
||||
S: Unpin + State + HasExecutions,
|
||||
OT: ObserversTuple<S>,
|
||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||
OT: ObserversTuple<S>,
|
||||
S: State + HasSolutions,
|
||||
SP: ShMemProvider,
|
||||
EM: EventFirer<State = S> + EventRestarter,
|
||||
OF: Feedback<S>,
|
||||
S: Unpin + HasSolutions,
|
||||
Z: HasObjective<Objective = OF, State = S>,
|
||||
Z: HasObjective<State = S>,
|
||||
{
|
||||
pub fn new(
|
||||
emulator: Emulator<CM, EH, ET, S>,
|
||||
@ -410,14 +375,12 @@ where
|
||||
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesObservers
|
||||
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
|
||||
where
|
||||
CM: CommandManager<EH, 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>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||
OT: ObserversTuple<S>,
|
||||
S: State,
|
||||
SP: ShMemProvider,
|
||||
Z: UsesState<State = S>,
|
||||
{
|
||||
type Observers = OT;
|
||||
@ -427,14 +390,12 @@ where
|
||||
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> UsesState
|
||||
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
|
||||
where
|
||||
CM: CommandManager<EH, 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>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||
OT: ObserversTuple<S>,
|
||||
S: State,
|
||||
SP: ShMemProvider,
|
||||
Z: UsesState<State = S>,
|
||||
{
|
||||
type State = S;
|
||||
@ -444,14 +405,12 @@ where
|
||||
impl<'a, CM, EH, H, OT, ET, S, SP, EM, Z> HasObservers
|
||||
for QemuForkExecutor<'a, CM, EH, H, OT, ET, S, SP, EM, Z>
|
||||
where
|
||||
CM: CommandManager<EH, 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>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
||||
OT: ObserversTuple<S>,
|
||||
S: State,
|
||||
SP: ShMemProvider,
|
||||
Z: UsesState<State = S>,
|
||||
{
|
||||
#[inline]
|
||||
|
@ -55,6 +55,10 @@ pub mod breakpoint;
|
||||
pub mod command;
|
||||
pub mod sync_exit;
|
||||
|
||||
pub use libafl_qemu_sys::{GuestAddr, MmapPerms};
|
||||
#[cfg(emulation_mode = "systemmode")]
|
||||
pub use libafl_qemu_sys::{GuestPhysAddr, GuestVirtAddr};
|
||||
|
||||
#[must_use]
|
||||
pub fn filter_qemu_args() -> Vec<String> {
|
||||
let mut args = vec![env::args().next().unwrap()];
|
||||
@ -90,7 +94,7 @@ pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_submodule(®sm)?;
|
||||
|
||||
let mmapm = PyModule::new_bound(m.py(), "mmap")?;
|
||||
for r in sys::MmapPerms::iter() {
|
||||
for r in MmapPerms::iter() {
|
||||
let v: i32 = r.into();
|
||||
mmapm.add(PyString::new_bound(m.py(), &format!("{r:?}")), v)?;
|
||||
}
|
||||
@ -99,10 +103,10 @@ pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_class::<sys::MapInfo>()?;
|
||||
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
m.add_class::<qemu::GuestMaps>()?;
|
||||
m.add_class::<GuestMaps>()?;
|
||||
|
||||
m.add_class::<qemu::SyscallHookResult>()?;
|
||||
m.add_class::<qemu::pybind::Qemu>()?;
|
||||
m.add_class::<SyscallHookResult>()?;
|
||||
m.add_class::<pybind::Qemu>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ use crate::emu::EmulatorModules;
|
||||
// TODO remove 'static when specialization will be stable
|
||||
pub trait EmulatorModule<S>: 'static + Debug
|
||||
where
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput,
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = true;
|
||||
|
||||
@ -76,7 +76,7 @@ where
|
||||
pub trait EmulatorModuleTuple<S>:
|
||||
MatchFirstType + for<'a> SplitBorrowExtractFirstType<'a> + Unpin
|
||||
where
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput,
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool;
|
||||
|
||||
@ -108,7 +108,7 @@ where
|
||||
|
||||
impl<S> EmulatorModuleTuple<S> for ()
|
||||
where
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput,
|
||||
{
|
||||
const HOOKS_DO_SIDE_EFFECTS: bool = false;
|
||||
|
||||
@ -150,7 +150,7 @@ impl<Head, Tail, S> EmulatorModuleTuple<S> for (Head, Tail)
|
||||
where
|
||||
Head: EmulatorModule<S> + Unpin,
|
||||
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;
|
||||
|
||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||
},
|
||||
qemu::{MemAccessInfo, QemuInitError},
|
||||
sys::TCGTemp,
|
||||
GuestAddr, Qemu, Regs,
|
||||
Qemu, Regs,
|
||||
};
|
||||
|
||||
// TODO at some point, merge parts with libafl_frida
|
||||
@ -149,6 +149,7 @@ impl AllocTreeItem {
|
||||
}
|
||||
use std::pin::Pin;
|
||||
|
||||
use libafl_qemu_sys::GuestAddr;
|
||||
use object::{Object, ObjectSection};
|
||||
|
||||
use crate::{
|
||||
|
@ -8,6 +8,7 @@ use std::{
|
||||
};
|
||||
|
||||
use libafl::inputs::UsesInput;
|
||||
use libafl_qemu_sys::{GuestAddr, MapInfo};
|
||||
|
||||
#[cfg(not(feature = "clippy"))]
|
||||
use crate::sys::libafl_tcg_gen_asan;
|
||||
@ -19,7 +20,6 @@ use crate::{
|
||||
},
|
||||
qemu::{Hook, MemAccessInfo, Qemu, QemuInitError},
|
||||
sys::TCGTemp,
|
||||
GuestAddr, MapInfo,
|
||||
};
|
||||
|
||||
static mut ASAN_GUEST_INITED: bool = false;
|
||||
|
@ -12,7 +12,6 @@ use pyo3::{pyclass, pymethods, FromPyObject};
|
||||
|
||||
use crate::{
|
||||
emu::EmulatorModules,
|
||||
modules::EmulatorModuleTuple,
|
||||
qemu::{MemAccessInfo, Qemu},
|
||||
sys::TCGTemp,
|
||||
HookData, HookId,
|
||||
@ -98,8 +97,7 @@ macro_rules! create_wrapper {
|
||||
paste::paste! {
|
||||
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut c_void, $($param: $param_type),*)
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
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),*)
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
{
|
||||
unsafe {
|
||||
@ -125,8 +122,7 @@ macro_rules! create_wrapper {
|
||||
paste::paste! {
|
||||
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut c_void, $($param: $param_type),*) -> $ret_type
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
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
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
|
||||
@ -155,8 +150,7 @@ macro_rules! create_pre_exec_wrapper {
|
||||
paste::paste! {
|
||||
pub extern "C" fn [<$name _pre_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
|
||||
@ -186,8 +180,7 @@ macro_rules! create_post_exec_wrapper {
|
||||
paste::paste! {
|
||||
pub extern "C" fn [<$name _post_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
|
||||
@ -217,8 +210,7 @@ macro_rules! create_gen_wrapper {
|
||||
paste::paste! {
|
||||
pub extern "C" fn [<$name _gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
|
||||
@ -248,8 +240,7 @@ macro_rules! create_post_gen_wrapper {
|
||||
paste::paste! {
|
||||
pub extern "C" fn [<$name _post_gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
|
||||
@ -278,8 +269,7 @@ macro_rules! create_exec_wrapper {
|
||||
paste::paste! {
|
||||
pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
|
||||
where
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + UsesInput,
|
||||
S: UsesInput + Unpin,
|
||||
{
|
||||
unsafe {
|
||||
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
|
||||
|
@ -6,7 +6,7 @@
|
||||
use core::fmt;
|
||||
use std::{
|
||||
cmp::{Ordering, PartialOrd},
|
||||
ffi::CString,
|
||||
ffi::{c_void, CString},
|
||||
fmt::{Display, Formatter},
|
||||
intrinsics::{copy_nonoverlapping, transmute},
|
||||
mem::MaybeUninit,
|
||||
@ -156,12 +156,12 @@ pub struct QemuMemoryChunk {
|
||||
#[allow(clippy::vec_box)]
|
||||
static mut GDB_COMMANDS: Vec<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 {
|
||||
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 qemu = Qemu::get_unchecked();
|
||||
i32::from(closure(&qemu, cmd))
|
||||
closure(&qemu, cmd)
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,7 +366,7 @@ impl CPU {
|
||||
let val = GuestReg::to_le(val.into());
|
||||
|
||||
let success =
|
||||
unsafe { libafl_qemu_write_reg(self.ptr, reg_id, ptr::addr_of!(val) as *const u8) };
|
||||
unsafe { libafl_qemu_write_reg(self.ptr, reg_id, ptr::addr_of!(val) as *mut u8) };
|
||||
if success == 0 {
|
||||
Err(QemuRWError {
|
||||
kind: QemuRWErrorKind::Write,
|
||||
@ -780,7 +780,7 @@ impl Qemu {
|
||||
Box<dyn for<'a, 'b> FnMut(&'a Qemu, &'b str) -> bool>,
|
||||
FatPtr,
|
||||
>(callback));
|
||||
libafl_qemu_add_gdb_cmd(gdb_cmd, ptr::from_ref(&*fat) as *const ());
|
||||
libafl_qemu_add_gdb_cmd(Some(gdb_cmd), ptr::from_ref(&*fat) as *mut c_void);
|
||||
GDB_COMMANDS.push(fat);
|
||||
}
|
||||
}
|
||||
|
@ -207,12 +207,12 @@ impl Qemu {
|
||||
|
||||
pub fn save_snapshot(&self, name: &str, sync: bool) {
|
||||
let s = CString::new(name).expect("Invalid snapshot name");
|
||||
unsafe { libafl_save_qemu_snapshot(s.as_ptr() as *const _, sync) };
|
||||
unsafe { libafl_save_qemu_snapshot(s.as_ptr() as *mut i8, sync) };
|
||||
}
|
||||
|
||||
pub fn load_snapshot(&self, name: &str, sync: bool) {
|
||||
let s = CString::new(name).expect("Invalid snapshot name");
|
||||
unsafe { libafl_load_qemu_snapshot(s.as_ptr() as *const _, sync) };
|
||||
unsafe { libafl_load_qemu_snapshot(s.as_ptr() as *mut i8, sync) };
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
@ -6,10 +6,10 @@ use std::{
|
||||
use libafl_qemu_sys::{
|
||||
exec_path, free_self_maps, guest_base, libafl_force_dfl, libafl_get_brk, libafl_load_addr,
|
||||
libafl_maps_first, libafl_maps_next, libafl_qemu_run, libafl_set_brk, mmap_next_start,
|
||||
pageflags_get_root, read_self_maps, strlen, GuestAddr, GuestUsize, IntervalTreeNode,
|
||||
IntervalTreeRoot, MapInfo, MmapPerms, VerifyAccess,
|
||||
pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot,
|
||||
MapInfo, MmapPerms, VerifyAccess,
|
||||
};
|
||||
use libc::c_int;
|
||||
use libc::{c_char, c_int, strlen};
|
||||
#[cfg(feature = "python")]
|
||||
use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python};
|
||||
|
||||
@ -138,7 +138,12 @@ impl Qemu {
|
||||
|
||||
#[must_use]
|
||||
pub fn binary_path<'a>(&self) -> &'a str {
|
||||
unsafe { from_utf8_unchecked(from_raw_parts(exec_path, strlen(exec_path))) }
|
||||
unsafe {
|
||||
from_utf8_unchecked(from_raw_parts(
|
||||
exec_path,
|
||||
strlen(exec_path as *const c_char),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
@ -4,14 +4,9 @@ use std::{
|
||||
};
|
||||
|
||||
use enum_map::Enum;
|
||||
use libafl::state::{HasExecutions, State};
|
||||
use libafl::inputs::UsesInput;
|
||||
|
||||
use crate::{
|
||||
command::{CommandManager, IsCommand},
|
||||
get_exit_arch_regs,
|
||||
modules::EmulatorModuleTuple,
|
||||
EmulatorExitHandler, GuestReg, Regs, CPU,
|
||||
};
|
||||
use crate::{command::IsCommand, get_exit_arch_regs, GuestReg, Regs, CPU};
|
||||
|
||||
#[derive(Debug, Clone, Enum)]
|
||||
pub enum ExitArgs {
|
||||
@ -28,20 +23,14 @@ pub enum ExitArgs {
|
||||
#[derive(Debug)]
|
||||
pub struct SyncExit<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
command: Rc<dyn IsCommand<CM, EH, ET, S>>,
|
||||
}
|
||||
|
||||
impl<CM, EH, ET, S> SyncExit<CM, EH, ET, S>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
#[must_use]
|
||||
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>
|
||||
where
|
||||
CM: CommandManager<EH, ET, S>,
|
||||
EH: EmulatorExitHandler<ET, S>,
|
||||
ET: EmulatorModuleTuple<S>,
|
||||
S: Unpin + State + HasExecutions,
|
||||
S: UsesInput,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.command)
|
||||
|
Loading…
x
Reference in New Issue
Block a user