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§
|
clippy = [] # special feature for clippy, don't use in normal projects§
|
||||||
|
|
||||||
|
systemmode = [] # Emulate system images instead of user-mode binaries
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../libafl", version = "0.7.1" }
|
libafl = { path = "../libafl", version = "0.7.1" }
|
||||||
libafl_targets = { path = "../libafl_targets", 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");
|
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));
|
let output_lib = build_dir.join(&format!("libqemu-{}.so", cpu_target));
|
||||||
if !output_lib.is_file() {
|
if !output_lib.is_file() {
|
||||||
drop(
|
drop(
|
||||||
@ -157,7 +160,7 @@ fn main() {
|
|||||||
.current_dir(&qemu_path)
|
.current_dir(&qemu_path)
|
||||||
//.arg("--as-static-lib")
|
//.arg("--as-static-lib")
|
||||||
.arg("--as-shared-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(&[
|
.args(&[
|
||||||
"--audio-drv-list=",
|
"--audio-drv-list=",
|
||||||
"--disable-blobs",
|
"--disable-blobs",
|
||||||
@ -170,7 +173,7 @@ fn main() {
|
|||||||
"--disable-curl",
|
"--disable-curl",
|
||||||
"--disable-curses",
|
"--disable-curses",
|
||||||
"--disable-dmg",
|
"--disable-dmg",
|
||||||
"--disable-fdt",
|
"--enable-fdt",
|
||||||
"--disable-gcrypt",
|
"--disable-gcrypt",
|
||||||
"--disable-glusterfs",
|
"--disable-glusterfs",
|
||||||
"--disable-gnutls",
|
"--disable-gnutls",
|
||||||
@ -199,7 +202,7 @@ fn main() {
|
|||||||
"--disable-smartcard",
|
"--disable-smartcard",
|
||||||
"--disable-snappy",
|
"--disable-snappy",
|
||||||
"--disable-spice",
|
"--disable-spice",
|
||||||
"--disable-system",
|
"--enable-system",
|
||||||
"--disable-tools",
|
"--disable-tools",
|
||||||
"--disable-tpm",
|
"--disable-tpm",
|
||||||
"--disable-usb-redir",
|
"--disable-usb-redir",
|
||||||
@ -248,6 +251,9 @@ fn main() {
|
|||||||
let mut objects = vec![];
|
let mut objects = vec![];
|
||||||
for dir in &[
|
for dir in &[
|
||||||
build_dir.join("libcommon.fa.p"),
|
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(&format!("libqemu-{}-linux-user.fa.p", cpu_target)),
|
||||||
build_dir.join("libcommon-user.fa.p"),
|
build_dir.join("libcommon-user.fa.p"),
|
||||||
//build_dir.join("libqemuutil.a.p"),
|
//build_dir.join("libqemuutil.a.p"),
|
||||||
@ -315,6 +321,13 @@ fn main() {
|
|||||||
|
|
||||||
#[cfg(not(feature = "python"))]
|
#[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(
|
fs::copy(
|
||||||
build_dir.join(&format!("libqemu-{}.so", cpu_target)),
|
build_dir.join(&format!("libqemu-{}.so", cpu_target)),
|
||||||
target_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={}",
|
"cargo:rustc-link-search=native={}",
|
||||||
&target_dir.to_string_lossy().to_string()
|
&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-link-lib=qemu-{}", cpu_target);
|
||||||
|
|
||||||
println!("cargo:rustc-env=LD_LIBRARY_PATH={}", target_dir.display());
|
println!("cargo:rustc-env=LD_LIBRARY_PATH={}", target_dir.display());
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Expose QEMU user `LibAFL` C api to Rust
|
//! Expose QEMU user `LibAFL` C api to Rust
|
||||||
|
|
||||||
|
use libc::c_char;
|
||||||
use core::{
|
use core::{
|
||||||
convert::Into,
|
convert::Into,
|
||||||
ffi::c_void,
|
ffi::c_void,
|
||||||
@ -170,12 +171,18 @@ impl MapInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
#[cfg(not(feature = "systemmode"))]
|
||||||
fn qemu_user_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
|
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_write_reg(reg: i32, val: *const u8) -> i32;
|
||||||
fn libafl_qemu_read_reg(reg: i32, val: *mut u8) -> i32;
|
fn libafl_qemu_read_reg(reg: i32, val: *mut u8) -> i32;
|
||||||
fn libafl_qemu_num_regs() -> i32;
|
fn libafl_qemu_num_regs() -> i32;
|
||||||
|
#[cfg(not(feature = "systemmode"))]
|
||||||
fn libafl_qemu_set_breakpoint(addr: u64) -> i32;
|
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_remove_breakpoint(addr: u64) -> i32;
|
||||||
fn libafl_qemu_set_hook(addr: u64, callback: extern "C" fn(u64), val: 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;
|
fn libafl_qemu_remove_hook(addr: u64) -> i32;
|
||||||
@ -184,6 +191,15 @@ extern "C" {
|
|||||||
fn libafl_get_brk() -> u64;
|
fn libafl_get_brk() -> u64;
|
||||||
fn libafl_set_brk(brk: u64) -> 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;
|
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)
|
/// 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)]
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
let argc = argv.len() as i32;
|
let argc = argv.len() as i32;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
#[cfg(not(feature = "systemmode"))]
|
||||||
qemu_user_init(
|
qemu_user_init(
|
||||||
argc,
|
argc,
|
||||||
argv.as_ptr() as *const *const u8,
|
argv.as_ptr() as *const *const u8,
|
||||||
envp.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_IS_INITIALIZED = true;
|
||||||
}
|
}
|
||||||
Emulator { _private: () }
|
Emulator { _private: () }
|
||||||
@ -338,6 +361,11 @@ impl Emulator {
|
|||||||
GuestMaps::new()
|
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]) {
|
pub unsafe fn write_mem<T>(&self, addr: u64, buf: &[T]) {
|
||||||
let host_addr = self.g2h(addr);
|
let host_addr = self.g2h(addr);
|
||||||
copy_nonoverlapping(
|
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]) {
|
pub unsafe fn read_mem<T>(&self, addr: u64, buf: &mut [T]) {
|
||||||
let host_addr = self.g2h(addr);
|
let host_addr = self.g2h(addr);
|
||||||
copy_nonoverlapping(
|
copy_nonoverlapping(
|
||||||
@ -392,6 +425,9 @@ impl Emulator {
|
|||||||
|
|
||||||
pub fn set_breakpoint(&self, addr: u64) {
|
pub fn set_breakpoint(&self, addr: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
#[cfg(feature = "systemmode")]
|
||||||
|
libafl_qemu_set_native_breakpoint(addr);
|
||||||
|
#[cfg(not(feature = "systemmode"))]
|
||||||
libafl_qemu_set_breakpoint(addr);
|
libafl_qemu_set_breakpoint(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,6 +655,25 @@ impl Emulator {
|
|||||||
libafl_post_syscall_hook = hook;
|
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")]
|
#[cfg(feature = "python")]
|
||||||
|
@ -35,10 +35,14 @@ pub use edges::QemuEdgeCoverageHelper;
|
|||||||
pub mod cmplog;
|
pub mod cmplog;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub use cmplog::QemuCmpLogHelper;
|
pub use cmplog::QemuCmpLogHelper;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(all(target_os = "linux",not(feature = "systemmode")))]
|
||||||
pub mod snapshot;
|
pub mod snapshot;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(all(target_os = "linux",not(feature = "systemmode")))]
|
||||||
pub use snapshot::QemuSnapshotHelper;
|
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")]
|
#[cfg(target_os = "linux")]
|
||||||
pub mod asan;
|
pub mod asan;
|
||||||
#[cfg(target_os = "linux")]
|
#[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