parent
1fafaf6454
commit
5fbe2415e1
@ -90,7 +90,7 @@ pub fn fuzz() {
|
|||||||
|
|
||||||
// Choose Snapshot Builder
|
// Choose Snapshot Builder
|
||||||
// let emu_snapshot_manager = QemuSnapshotBuilder::new(true);
|
// let emu_snapshot_manager = QemuSnapshotBuilder::new(true);
|
||||||
let emu_snapshot_manager = FastSnapshotManager::new(false);
|
let emu_snapshot_manager = FastSnapshotManager::new();
|
||||||
|
|
||||||
// Choose Exit Handler
|
// Choose Exit Handler
|
||||||
let emu_exit_handler = StdEmulatorExitHandler::new(emu_snapshot_manager);
|
let emu_exit_handler = StdEmulatorExitHandler::new(emu_snapshot_manager);
|
||||||
|
@ -55,7 +55,7 @@ pub fn fuzz() {
|
|||||||
let env: Vec<(String, String)> = env::vars().collect();
|
let env: Vec<(String, String)> = env::vars().collect();
|
||||||
|
|
||||||
// let emu_snapshot_manager = QemuSnapshotBuilder::new(true);
|
// let emu_snapshot_manager = QemuSnapshotBuilder::new(true);
|
||||||
let emu_snapshot_manager = FastSnapshotManager::new(false); // Create a snapshot manager (normal or fast for now).
|
let emu_snapshot_manager = FastSnapshotManager::new(); // Create a snapshot manager (normal or fast for now).
|
||||||
let emu_exit_handler: StdEmulatorExitHandler<FastSnapshotManager> =
|
let emu_exit_handler: StdEmulatorExitHandler<FastSnapshotManager> =
|
||||||
StdEmulatorExitHandler::new(emu_snapshot_manager); // Create an exit handler: it is the entity taking the decision of what should be done when QEMU returns.
|
StdEmulatorExitHandler::new(emu_snapshot_manager); // Create an exit handler: it is the entity taking the decision of what should be done when QEMU returns.
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use crate::cargo_add_rpath;
|
|||||||
|
|
||||||
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
||||||
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
||||||
const QEMU_REVISION: &str = "9f3e2399ee9b106dfbb8c3afcdfdf30e235fc88f";
|
const QEMU_REVISION: &str = "9d2197b73bf5e66e709f9f1669467d5c84062da0";
|
||||||
|
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
pub struct BuildResult {
|
pub struct BuildResult {
|
||||||
|
@ -317,6 +317,11 @@ where
|
|||||||
.snapshot_manager_borrow_mut()
|
.snapshot_manager_borrow_mut()
|
||||||
.restore(&snapshot_id, qemu)?;
|
.restore(&snapshot_id, qemu)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "paranoid_debug")]
|
||||||
|
emu_exit_handler
|
||||||
|
.snapshot_manager_borrow()
|
||||||
|
.check(&snapshot_id, emu.qemu())?;
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,6 +450,11 @@ where
|
|||||||
.snapshot_manager_borrow_mut()
|
.snapshot_manager_borrow_mut()
|
||||||
.restore(&snapshot_id, emu.qemu())?;
|
.restore(&snapshot_id, emu.qemu())?;
|
||||||
|
|
||||||
|
#[cfg(feature = "paranoid_debug")]
|
||||||
|
emu_exit_handler
|
||||||
|
.snapshot_manager_borrow()
|
||||||
|
.check(&snapshot_id, emu.qemu())?;
|
||||||
|
|
||||||
Ok(Some(ExitHandlerResult::EndOfRun(self.0.unwrap())))
|
Ok(Some(ExitHandlerResult::EndOfRun(self.0.unwrap())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,8 @@ use crate::{
|
|||||||
sys::TCGTemp,
|
sys::TCGTemp,
|
||||||
BackdoorHookId, BlockHookId, CmpHookId, EdgeHookId, EmulatorMemoryChunk, GuestReg, HookData,
|
BackdoorHookId, BlockHookId, CmpHookId, EdgeHookId, EmulatorMemoryChunk, GuestReg, HookData,
|
||||||
HookId, InstructionHookId, MemAccessInfo, Qemu, QemuExitError, QemuExitReason, QemuHelperTuple,
|
HookId, InstructionHookId, MemAccessInfo, Qemu, QemuExitError, QemuExitReason, QemuHelperTuple,
|
||||||
QemuInitError, QemuShutdownCause, ReadHookId, Regs, StdInstrumentationFilter, WriteHookId, CPU,
|
QemuInitError, QemuShutdownCause, QemuSnapshotCheckResult, ReadHookId, Regs,
|
||||||
|
StdInstrumentationFilter, WriteHookId, CPU,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
@ -96,6 +97,7 @@ where
|
|||||||
pub enum ExitHandlerError {
|
pub enum ExitHandlerError {
|
||||||
QemuExitReasonError(EmulatorExitError),
|
QemuExitReasonError(EmulatorExitError),
|
||||||
SMError(SnapshotManagerError),
|
SMError(SnapshotManagerError),
|
||||||
|
SMCheckError(SnapshotManagerCheckError),
|
||||||
CommandError(CommandError),
|
CommandError(CommandError),
|
||||||
UnhandledSignal(Signal),
|
UnhandledSignal(Signal),
|
||||||
MultipleSnapshotDefinition,
|
MultipleSnapshotDefinition,
|
||||||
@ -109,6 +111,12 @@ pub enum SnapshotManagerError {
|
|||||||
MemoryInconsistencies(u64),
|
MemoryInconsistencies(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum SnapshotManagerCheckError {
|
||||||
|
SnapshotManagerError(SnapshotManagerError),
|
||||||
|
SnapshotCheckError(QemuSnapshotCheckResult),
|
||||||
|
}
|
||||||
|
|
||||||
impl<CM, E, QT, S> TryFrom<ExitHandlerResult<CM, E, QT, S>> for ExitKind
|
impl<CM, E, QT, S> TryFrom<ExitHandlerResult<CM, E, QT, S>> for ExitKind
|
||||||
where
|
where
|
||||||
CM: CommandManager<E, QT, S> + Debug,
|
CM: CommandManager<E, QT, S> + Debug,
|
||||||
@ -163,6 +171,12 @@ impl From<SnapshotManagerError> for ExitHandlerError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SnapshotManagerCheckError> for ExitHandlerError {
|
||||||
|
fn from(sm_check_error: SnapshotManagerCheckError) -> Self {
|
||||||
|
ExitHandlerError::SMCheckError(sm_check_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub struct SnapshotId {
|
pub struct SnapshotId {
|
||||||
id: u64,
|
id: u64,
|
||||||
@ -175,6 +189,27 @@ pub trait IsSnapshotManager: Debug + Clone {
|
|||||||
snapshot_id: &SnapshotId,
|
snapshot_id: &SnapshotId,
|
||||||
qemu: &Qemu,
|
qemu: &Qemu,
|
||||||
) -> Result<(), SnapshotManagerError>;
|
) -> 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Rework with generics for command handlers?
|
// TODO: Rework with generics for command handlers?
|
||||||
|
@ -9,7 +9,8 @@ use libafl_qemu_sys::GuestPhysAddr;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
command::CommandManager, emu::IsSnapshotManager, DeviceSnapshotFilter, Emulator,
|
command::CommandManager, emu::IsSnapshotManager, DeviceSnapshotFilter, Emulator,
|
||||||
EmulatorExitHandler, Qemu, QemuHelperTuple, SnapshotId, SnapshotManagerError,
|
EmulatorExitHandler, Qemu, QemuHelperTuple, QemuSnapshotCheckResult, SnapshotId,
|
||||||
|
SnapshotManagerError,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl SnapshotId {
|
impl SnapshotId {
|
||||||
@ -50,6 +51,17 @@ impl IsSnapshotManager for SnapshotManager {
|
|||||||
SnapshotManager::Fast(fast_sm) => fast_sm.restore(snapshot_id, qemu),
|
SnapshotManager::Fast(fast_sm) => fast_sm.restore(snapshot_id, qemu),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn do_check(
|
||||||
|
&self,
|
||||||
|
reference_snapshot_id: &SnapshotId,
|
||||||
|
qemu: &Qemu,
|
||||||
|
) -> Result<QemuSnapshotCheckResult, SnapshotManagerError> {
|
||||||
|
match self {
|
||||||
|
SnapshotManager::Qemu(qemu_sm) => qemu_sm.do_check(reference_snapshot_id, qemu),
|
||||||
|
SnapshotManager::Fast(fast_sm) => fast_sm.do_check(reference_snapshot_id, qemu),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type FastSnapshotPtr = *mut libafl_qemu_sys::SyxSnapshot;
|
pub type FastSnapshotPtr = *mut libafl_qemu_sys::SyxSnapshot;
|
||||||
@ -57,20 +69,18 @@ pub type FastSnapshotPtr = *mut libafl_qemu_sys::SyxSnapshot;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FastSnapshotManager {
|
pub struct FastSnapshotManager {
|
||||||
snapshots: HashMap<SnapshotId, FastSnapshotPtr>,
|
snapshots: HashMap<SnapshotId, FastSnapshotPtr>,
|
||||||
check_memory_consistency: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FastSnapshotManager {
|
impl Default for FastSnapshotManager {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(false)
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FastSnapshotManager {
|
impl FastSnapshotManager {
|
||||||
pub fn new(check_memory_consistency: bool) -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
snapshots: HashMap::new(),
|
snapshots: HashMap::new(),
|
||||||
check_memory_consistency,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +122,15 @@ impl IsSnapshotManager for QemuSnapshotManager {
|
|||||||
qemu.load_snapshot(self.snapshot_id_to_name(snapshot_id).as_str(), self.is_sync);
|
qemu.load_snapshot(self.snapshot_id_to_name(snapshot_id).as_str(), self.is_sync);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn do_check(
|
||||||
|
&self,
|
||||||
|
_reference_snapshot_id: &SnapshotId,
|
||||||
|
_qemu: &Qemu,
|
||||||
|
) -> Result<QemuSnapshotCheckResult, SnapshotManagerError> {
|
||||||
|
// We consider the qemu implementation to be 'ideal' for now.
|
||||||
|
Ok(QemuSnapshotCheckResult::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsSnapshotManager for FastSnapshotManager {
|
impl IsSnapshotManager for FastSnapshotManager {
|
||||||
@ -136,19 +155,20 @@ impl IsSnapshotManager for FastSnapshotManager {
|
|||||||
qemu.restore_fast_snapshot(fast_snapshot_ptr);
|
qemu.restore_fast_snapshot(fast_snapshot_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.check_memory_consistency {
|
|
||||||
let nb_inconsistencies =
|
|
||||||
unsafe { qemu.check_fast_snapshot_memory_consistency(fast_snapshot_ptr) };
|
|
||||||
|
|
||||||
if nb_inconsistencies > 0 {
|
|
||||||
return Err(SnapshotManagerError::MemoryInconsistencies(
|
|
||||||
nb_inconsistencies,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn do_check(
|
||||||
|
&self,
|
||||||
|
reference_snapshot_id: &SnapshotId,
|
||||||
|
qemu: &Qemu,
|
||||||
|
) -> Result<QemuSnapshotCheckResult, SnapshotManagerError> {
|
||||||
|
let fast_snapshot_ptr = *self.snapshots.get(reference_snapshot_id).ok_or(
|
||||||
|
SnapshotManagerError::SnapshotIdNotFound(*reference_snapshot_id),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
unsafe { Ok(qemu.check_fast_snapshot(fast_snapshot_ptr)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CM, E, QT, S> Emulator<CM, E, QT, S>
|
impl<CM, E, QT, S> Emulator<CM, E, QT, S>
|
||||||
@ -194,10 +214,6 @@ where
|
|||||||
self.qemu.restore_fast_snapshot(snapshot)
|
self.qemu.restore_fast_snapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn check_fast_snapshot_memory_consistency(&self, snapshot: FastSnapshotPtr) -> u64 {
|
|
||||||
self.qemu.check_fast_snapshot_memory_consistency(snapshot)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_devices(&self) -> Vec<String> {
|
pub fn list_devices(&self) -> Vec<String> {
|
||||||
self.qemu.list_devices()
|
self.qemu.list_devices()
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,20 @@ pub enum QemuExitError {
|
|||||||
UnexpectedExit, // Qemu exited without going through an expected exit point. Can be caused by a crash for example.
|
UnexpectedExit, // Qemu exited without going through an expected exit point. Can be caused by a crash for example.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct QemuSnapshotCheckResult {
|
||||||
|
nb_page_inconsistencies: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a QEMU snapshot check result for which no error was detected
|
||||||
|
impl Default for QemuSnapshotCheckResult {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
nb_page_inconsistencies: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The thin wrapper around QEMU.
|
/// The thin wrapper around QEMU.
|
||||||
/// It is considered unsafe to use it directly.
|
/// It is considered unsafe to use it directly.
|
||||||
/// Prefer using `Emulator` instead in case of doubt.
|
/// Prefer using `Emulator` instead in case of doubt.
|
||||||
|
@ -16,7 +16,7 @@ use num_traits::Zero;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
EmulatorMemoryChunk, FastSnapshotPtr, GuestAddrKind, MemAccessInfo, Qemu, QemuExitError,
|
EmulatorMemoryChunk, FastSnapshotPtr, GuestAddrKind, MemAccessInfo, Qemu, QemuExitError,
|
||||||
QemuExitReason, CPU,
|
QemuExitReason, QemuSnapshotCheckResult, CPU,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) extern "C" fn qemu_cleanup_atexit() {
|
pub(super) extern "C" fn qemu_cleanup_atexit() {
|
||||||
@ -256,8 +256,15 @@ impl Qemu {
|
|||||||
libafl_qemu_sys::syx_snapshot_root_restore(snapshot)
|
libafl_qemu_sys::syx_snapshot_root_restore(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn check_fast_snapshot_memory_consistency(&self, snapshot: FastSnapshotPtr) -> u64 {
|
pub unsafe fn check_fast_snapshot(
|
||||||
libafl_qemu_sys::syx_snapshot_check_memory_consistency(snapshot)
|
&self,
|
||||||
|
ref_snapshot: FastSnapshotPtr,
|
||||||
|
) -> QemuSnapshotCheckResult {
|
||||||
|
let check_result = libafl_qemu_sys::syx_snapshot_check(ref_snapshot);
|
||||||
|
|
||||||
|
QemuSnapshotCheckResult {
|
||||||
|
nb_page_inconsistencies: check_result.nb_inconsistencies,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_devices(&self) -> Vec<String> {
|
pub fn list_devices(&self) -> Vec<String> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user