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