parent
1fafaf6454
commit
5fbe2415e1
@ -90,7 +90,7 @@ pub fn fuzz() {
|
||||
|
||||
// Choose Snapshot Builder
|
||||
// let emu_snapshot_manager = QemuSnapshotBuilder::new(true);
|
||||
let emu_snapshot_manager = FastSnapshotManager::new(false);
|
||||
let emu_snapshot_manager = FastSnapshotManager::new();
|
||||
|
||||
// Choose Exit Handler
|
||||
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 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> =
|
||||
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_DIRNAME: &str = "qemu-libafl-bridge";
|
||||
const QEMU_REVISION: &str = "9f3e2399ee9b106dfbb8c3afcdfdf30e235fc88f";
|
||||
const QEMU_REVISION: &str = "9d2197b73bf5e66e709f9f1669467d5c84062da0";
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub struct BuildResult {
|
||||
|
@ -317,6 +317,11 @@ where
|
||||
.snapshot_manager_borrow_mut()
|
||||
.restore(&snapshot_id, qemu)?;
|
||||
|
||||
#[cfg(feature = "paranoid_debug")]
|
||||
emu_exit_handler
|
||||
.snapshot_manager_borrow()
|
||||
.check(&snapshot_id, emu.qemu())?;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
@ -445,6 +450,11 @@ where
|
||||
.snapshot_manager_borrow_mut()
|
||||
.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())))
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ use crate::{
|
||||
sys::TCGTemp,
|
||||
BackdoorHookId, BlockHookId, CmpHookId, EdgeHookId, EmulatorMemoryChunk, GuestReg, HookData,
|
||||
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")]
|
||||
@ -96,6 +97,7 @@ where
|
||||
pub enum ExitHandlerError {
|
||||
QemuExitReasonError(EmulatorExitError),
|
||||
SMError(SnapshotManagerError),
|
||||
SMCheckError(SnapshotManagerCheckError),
|
||||
CommandError(CommandError),
|
||||
UnhandledSignal(Signal),
|
||||
MultipleSnapshotDefinition,
|
||||
@ -109,6 +111,12 @@ pub enum SnapshotManagerError {
|
||||
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
|
||||
where
|
||||
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)]
|
||||
pub struct SnapshotId {
|
||||
id: u64,
|
||||
@ -175,6 +189,27 @@ pub trait IsSnapshotManager: Debug + Clone {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rework with generics for command handlers?
|
||||
|
@ -9,7 +9,8 @@ use libafl_qemu_sys::GuestPhysAddr;
|
||||
|
||||
use crate::{
|
||||
command::CommandManager, emu::IsSnapshotManager, DeviceSnapshotFilter, Emulator,
|
||||
EmulatorExitHandler, Qemu, QemuHelperTuple, SnapshotId, SnapshotManagerError,
|
||||
EmulatorExitHandler, Qemu, QemuHelperTuple, QemuSnapshotCheckResult, SnapshotId,
|
||||
SnapshotManagerError,
|
||||
};
|
||||
|
||||
impl SnapshotId {
|
||||
@ -50,6 +51,17 @@ impl IsSnapshotManager for SnapshotManager {
|
||||
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;
|
||||
@ -57,20 +69,18 @@ pub type FastSnapshotPtr = *mut libafl_qemu_sys::SyxSnapshot;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FastSnapshotManager {
|
||||
snapshots: HashMap<SnapshotId, FastSnapshotPtr>,
|
||||
check_memory_consistency: bool,
|
||||
}
|
||||
|
||||
impl Default for FastSnapshotManager {
|
||||
fn default() -> Self {
|
||||
Self::new(false)
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl FastSnapshotManager {
|
||||
pub fn new(check_memory_consistency: bool) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
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);
|
||||
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 {
|
||||
@ -136,19 +155,20 @@ impl IsSnapshotManager for FastSnapshotManager {
|
||||
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(())
|
||||
}
|
||||
|
||||
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>
|
||||
@ -194,10 +214,6 @@ where
|
||||
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> {
|
||||
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.
|
||||
}
|
||||
|
||||
#[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.
|
||||
/// It is considered unsafe to use it directly.
|
||||
/// Prefer using `Emulator` instead in case of doubt.
|
||||
|
@ -16,7 +16,7 @@ use num_traits::Zero;
|
||||
|
||||
use crate::{
|
||||
EmulatorMemoryChunk, FastSnapshotPtr, GuestAddrKind, MemAccessInfo, Qemu, QemuExitError,
|
||||
QemuExitReason, CPU,
|
||||
QemuExitReason, QemuSnapshotCheckResult, CPU,
|
||||
};
|
||||
|
||||
pub(super) extern "C" fn qemu_cleanup_atexit() {
|
||||
@ -256,8 +256,15 @@ impl Qemu {
|
||||
libafl_qemu_sys::syx_snapshot_root_restore(snapshot)
|
||||
}
|
||||
|
||||
pub unsafe fn check_fast_snapshot_memory_consistency(&self, snapshot: FastSnapshotPtr) -> u64 {
|
||||
libafl_qemu_sys::syx_snapshot_check_memory_consistency(snapshot)
|
||||
pub unsafe fn check_fast_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> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user