Add systemmode to libafl_qemu
Use the new configuration feature systemmode
This commit is contained in:
parent
d460bab404
commit
edff095401
@ -22,6 +22,8 @@ aarch64 = [] # build qemu for aarch64
|
||||
|
||||
clippy = [] # special feature for clippy, don't use in normal projects§
|
||||
|
||||
systemmode = [] # Emulate system images instead of user-mode binaries
|
||||
|
||||
[dependencies]
|
||||
libafl = { path = "../libafl", version = "0.7.1" }
|
||||
libafl_targets = { path = "../libafl_targets", version = "0.7.1" }
|
||||
|
@ -145,6 +145,9 @@ fn main() {
|
||||
}
|
||||
|
||||
let build_dir = qemu_path.join("build");
|
||||
#[cfg(feature = "systemmode")]
|
||||
let output_lib = build_dir.join(&format!("libqemu-system-{}.so", cpu_target));
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
let output_lib = build_dir.join(&format!("libqemu-{}.so", cpu_target));
|
||||
if !output_lib.is_file() {
|
||||
drop(
|
||||
@ -157,7 +160,7 @@ fn main() {
|
||||
.current_dir(&qemu_path)
|
||||
//.arg("--as-static-lib")
|
||||
.arg("--as-shared-lib")
|
||||
.arg(&format!("--target-list={}-linux-user", cpu_target))
|
||||
.arg(&format!("--target-list={}-linux-user,{}-softmmu", cpu_target,cpu_target))
|
||||
.args(&[
|
||||
"--audio-drv-list=",
|
||||
"--disable-blobs",
|
||||
@ -170,7 +173,7 @@ fn main() {
|
||||
"--disable-curl",
|
||||
"--disable-curses",
|
||||
"--disable-dmg",
|
||||
"--disable-fdt",
|
||||
"--enable-fdt",
|
||||
"--disable-gcrypt",
|
||||
"--disable-glusterfs",
|
||||
"--disable-gnutls",
|
||||
@ -199,7 +202,7 @@ fn main() {
|
||||
"--disable-smartcard",
|
||||
"--disable-snappy",
|
||||
"--disable-spice",
|
||||
"--disable-system",
|
||||
"--enable-system",
|
||||
"--disable-tools",
|
||||
"--disable-tpm",
|
||||
"--disable-usb-redir",
|
||||
@ -248,6 +251,9 @@ fn main() {
|
||||
let mut objects = vec![];
|
||||
for dir in &[
|
||||
build_dir.join("libcommon.fa.p"),
|
||||
#[cfg(feature = "systemmode")]
|
||||
build_dir.join(&format!("libqemu-{}-softmmu.fa.p", cpu_target)),
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
build_dir.join(&format!("libqemu-{}-linux-user.fa.p", cpu_target)),
|
||||
build_dir.join("libcommon-user.fa.p"),
|
||||
//build_dir.join("libqemuutil.a.p"),
|
||||
@ -315,6 +321,13 @@ fn main() {
|
||||
|
||||
#[cfg(not(feature = "python"))]
|
||||
{
|
||||
#[cfg(feature = "systemmode")]
|
||||
fs::copy(
|
||||
build_dir.join(&format!("libqemu-system-{}.so", cpu_target)),
|
||||
target_dir.join(&format!("libqemu-system-{}.so", cpu_target)),
|
||||
)
|
||||
.expect("Failed to copy the QEMU shared object");
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
fs::copy(
|
||||
build_dir.join(&format!("libqemu-{}.so", cpu_target)),
|
||||
target_dir.join(&format!("libqemu-{}.so", cpu_target)),
|
||||
@ -325,6 +338,9 @@ fn main() {
|
||||
"cargo:rustc-link-search=native={}",
|
||||
&target_dir.to_string_lossy().to_string()
|
||||
);
|
||||
#[cfg(feature = "systemmode")]
|
||||
println!("cargo:rustc-link-lib=qemu-system-{}", cpu_target);
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
println!("cargo:rustc-link-lib=qemu-{}", cpu_target);
|
||||
|
||||
println!("cargo:rustc-env=LD_LIBRARY_PATH={}", target_dir.display());
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Expose QEMU user `LibAFL` C api to Rust
|
||||
|
||||
use libc::c_char;
|
||||
use core::{
|
||||
convert::Into,
|
||||
ffi::c_void,
|
||||
@ -170,12 +171,18 @@ impl MapInfo {
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
fn qemu_user_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_qemu_sys_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
|
||||
|
||||
fn libafl_qemu_write_reg(reg: i32, val: *const u8) -> i32;
|
||||
fn libafl_qemu_read_reg(reg: i32, val: *mut u8) -> i32;
|
||||
fn libafl_qemu_num_regs() -> i32;
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
fn libafl_qemu_set_breakpoint(addr: u64) -> i32;
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_qemu_set_native_breakpoint(addr: u64) -> i32;
|
||||
fn libafl_qemu_remove_breakpoint(addr: u64) -> i32;
|
||||
fn libafl_qemu_set_hook(addr: u64, callback: extern "C" fn(u64), val: u64) -> i32;
|
||||
fn libafl_qemu_remove_hook(addr: u64) -> i32;
|
||||
@ -184,6 +191,15 @@ extern "C" {
|
||||
fn libafl_get_brk() -> u64;
|
||||
fn libafl_set_brk(brk: u64) -> u64;
|
||||
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_phys_write(addr: u64, buf: *const u8, len: i32);
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_phys_read(addr: u64, buf: *mut u8, len: i32);
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_snapshot_save(name: *const c_char) -> i32;
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_snapshot_load(name: *const c_char) -> i32;
|
||||
|
||||
fn strlen(s: *const u8) -> usize;
|
||||
|
||||
/// abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, int flags, int fd, abi_ulong offset)
|
||||
@ -318,11 +334,18 @@ impl Emulator {
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let argc = argv.len() as i32;
|
||||
unsafe {
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
qemu_user_init(
|
||||
argc,
|
||||
argv.as_ptr() as *const *const u8,
|
||||
envp.as_ptr() as *const *const u8,
|
||||
);
|
||||
#[cfg(feature = "systemmode")]
|
||||
libafl_qemu_sys_init(
|
||||
argc,
|
||||
argv.as_ptr() as *const *const u8,
|
||||
envp.as_ptr() as *const *const u8,
|
||||
);
|
||||
EMULATOR_IS_INITIALIZED = true;
|
||||
}
|
||||
Emulator { _private: () }
|
||||
@ -338,6 +361,11 @@ impl Emulator {
|
||||
GuestMaps::new()
|
||||
}
|
||||
|
||||
#[cfg(feature = "systemmode")]
|
||||
pub unsafe fn write_mem(&self, addr: u64, buf: &[u8]) {
|
||||
unsafe { libafl_phys_write(addr, buf.as_ptr(), buf.len().try_into().unwrap()); }
|
||||
}
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
pub unsafe fn write_mem<T>(&self, addr: u64, buf: &[T]) {
|
||||
let host_addr = self.g2h(addr);
|
||||
copy_nonoverlapping(
|
||||
@ -347,6 +375,11 @@ impl Emulator {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "systemmode")]
|
||||
pub unsafe fn read_mem(&self, addr: u64, buf: &mut [u8]) {
|
||||
unsafe { libafl_phys_read(addr, buf.as_mut_ptr(), buf.len().try_into().unwrap()); }
|
||||
}
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
pub unsafe fn read_mem<T>(&self, addr: u64, buf: &mut [T]) {
|
||||
let host_addr = self.g2h(addr);
|
||||
copy_nonoverlapping(
|
||||
@ -392,6 +425,9 @@ impl Emulator {
|
||||
|
||||
pub fn set_breakpoint(&self, addr: u64) {
|
||||
unsafe {
|
||||
#[cfg(feature = "systemmode")]
|
||||
libafl_qemu_set_native_breakpoint(addr);
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
libafl_qemu_set_breakpoint(addr);
|
||||
}
|
||||
}
|
||||
@ -619,6 +655,25 @@ impl Emulator {
|
||||
libafl_post_syscall_hook = hook;
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "systemmode")]
|
||||
pub fn snapshot_save(&self, name: &str) -> bool{
|
||||
let cname = std::ffi::CString::new(name).expect("Snapshot name not CString compatible");
|
||||
let ret = unsafe { libafl_snapshot_save(cname.as_ptr()) };
|
||||
match ret {
|
||||
0 => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "systemmode")]
|
||||
pub fn snapshot_load(&self, name: &str) -> bool{
|
||||
let cname = std::ffi::CString::new(name).expect("Snapshot name not CString compatible");
|
||||
let ret = unsafe { libafl_snapshot_load(cname.as_ptr()) };
|
||||
match ret {
|
||||
0 => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "python")]
|
||||
|
@ -35,10 +35,14 @@ pub use edges::QemuEdgeCoverageHelper;
|
||||
pub mod cmplog;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use cmplog::QemuCmpLogHelper;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(all(target_os = "linux",not(feature = "systemmode")))]
|
||||
pub mod snapshot;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(all(target_os = "linux",not(feature = "systemmode")))]
|
||||
pub use snapshot::QemuSnapshotHelper;
|
||||
#[cfg(all(target_os = "linux",feature = "systemmode"))]
|
||||
pub mod snapshot_sys;
|
||||
#[cfg(all(target_os = "linux",feature = "systemmode"))]
|
||||
pub use snapshot_sys::QemuSysSnapshotHelper;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod asan;
|
||||
#[cfg(target_os = "linux")]
|
||||
|
63
libafl_qemu/src/snapshot_sys.rs
Normal file
63
libafl_qemu/src/snapshot_sys.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use crate::Emulator;
|
||||
use crate::QemuExecutor;
|
||||
use crate::QemuHelper;
|
||||
use crate::QemuHelperTuple;
|
||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||
|
||||
use crate::{
|
||||
emu,
|
||||
};
|
||||
// TODO be thread-safe maybe with https://amanieu.github.io/thread_local-rs/thread_local/index.html
|
||||
#[derive(Debug)]
|
||||
pub struct QemuSysSnapshotHelper {
|
||||
pub empty: bool,
|
||||
}
|
||||
|
||||
impl QemuSysSnapshotHelper {
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
empty: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snapshot(&mut self, emulator: &Emulator) {
|
||||
if self.empty {
|
||||
let ret = emulator.snapshot_save("Start");
|
||||
if !ret { panic!("QemuSysSnapshotHelper failed to take a snapshot") };
|
||||
self.empty = false;
|
||||
}
|
||||
}
|
||||
pub fn reset(&mut self, emulator: &Emulator) {
|
||||
let ret = emulator.snapshot_load("Start");
|
||||
if !ret { panic!("QemuSysSnapshotHelper failed to load a snapshot") };
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuSysSnapshotHelper {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, S> QemuHelper<I, S> for QemuSysSnapshotHelper
|
||||
where
|
||||
I: Input,
|
||||
S: HasMetadata,
|
||||
{
|
||||
fn init<'a, H, OT, QT>(&self, _executor: &QemuExecutor<'a, H, I, OT, QT, S>)
|
||||
where
|
||||
H: FnMut(&I) -> ExitKind,
|
||||
OT: ObserversTuple<I, S>,
|
||||
QT: QemuHelperTuple<I, S>,
|
||||
{
|
||||
}
|
||||
|
||||
fn pre_exec(&mut self, emulator: &Emulator, _input: &I) {
|
||||
if self.empty {
|
||||
self.snapshot(emulator);
|
||||
} else {
|
||||
self.reset(emulator);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user