Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -8237,6 +8237,9 @@ unsafe extern "C" {
unsafe extern "C" {
pub fn libafl_qemu_run() -> ::std::os::raw::c_int;
}
unsafe extern "C" {
pub fn libafl_qemu_run_single_cpu(cpu_index: *mut CPUState) -> ::std::os::raw::c_int;
}
unsafe extern "C" {
pub fn libafl_set_qemu_env(env: *mut CPUArchState);
}
Expand Down
55 changes: 55 additions & 0 deletions crates/libafl_qemu/src/qemu/usermode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use std::{
str::from_utf8_unchecked_mut,
};

use crate::{QemuExitError, QemuExitReason, QemuShutdownCause};
use crate::qemu::transmute;

use libafl_bolts::{Error, os::unix_signals::Signal};
#[cfg(not(feature = "systemmode"))]
use libafl_qemu_sys::libafl_qemu_run;
Expand All @@ -14,6 +17,7 @@ use libafl_qemu_sys::{
libafl_get_initial_brk, libafl_load_addr, libafl_maps_first, libafl_maps_next, libafl_set_brk,
mmap_next_start, pageflags_get_root, read_self_maps,
};
use libafl_qemu_sys::{libafl_get_exit_reason, libafl_qemu_run_single_cpu};
use libc::{c_int, c_uchar, siginfo_t, strlen};
#[cfg(feature = "python")]
use pyo3::{IntoPyObject, Py, PyRef, PyRefMut, Python, pyclass, pymethods};
Expand Down Expand Up @@ -491,6 +495,57 @@ impl Qemu {
},
}
}

/// Run a single, caller-selected CPU until the next exit.
///
/// # Safety
///
/// The provided [`CPU`] must belong to this QEMU instance and remain valid for the duration of
/// the run.
#[allow(dead_code)]
pub unsafe fn run_single_cpu(&self, cpu: CPU) -> Result<QemuExitReason, QemuExitError> {
unsafe {
libafl_qemu_run_single_cpu(cpu.raw_ptr());
}
Comment on lines +507 to +509

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @rliebig
Thank you for this. This could not have come at a better time for our team.
Trying out your changes I noticed you seem to be missing

unsafe {
    QEMU_IS_RUNNING = true;
    libafl_qemu_run_single_cpu(cpu.raw_ptr());
    QEMU_IS_RUNNING = false;
}

Without this the fuzzers crashes the first time a crash is detected.

[2026-07-09T17:54:16Z ERROR libafl_qemu::executor] The fuzzer crashed at addr 0x0... Bug in the fuzzer? Exiting.


let exit_reason = unsafe { libafl_get_exit_reason() };
if exit_reason.is_null() {
Err(QemuExitError::UnexpectedExit)
} else {
let exit_reason: &mut libafl_qemu_sys::libafl_exit_reason =
unsafe { transmute(&mut *exit_reason) };
Ok(match exit_reason.kind {
libafl_qemu_sys::libafl_exit_reason_kind_INTERNAL => unsafe {
let qemu_shutdown_cause: QemuShutdownCause = match exit_reason.data.internal.cause {
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_NONE => QemuShutdownCause::None,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_HOST_ERROR => QemuShutdownCause::HostError,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_HOST_QMP_QUIT => QemuShutdownCause::HostQmpQuit,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET => QemuShutdownCause::HostQmpSystemReset,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_HOST_SIGNAL => {
QemuShutdownCause::HostSignal(
Signal::try_from(exit_reason.data.internal.signal).unwrap(),
)
}
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_HOST_UI => QemuShutdownCause::HostUi,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_GUEST_SHUTDOWN => QemuShutdownCause::GuestShutdown,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_GUEST_RESET => QemuShutdownCause::GuestReset,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_GUEST_PANIC => QemuShutdownCause::GuestPanic,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_SUBSYSTEM_RESET => QemuShutdownCause::SubsystemReset,
libafl_qemu_sys::ShutdownCause_SHUTDOWN_CAUSE_SNAPSHOT_LOAD => QemuShutdownCause::SnapshotLoad,
_ => panic!("shutdown cause not handled."),
};
QemuExitReason::End(qemu_shutdown_cause)
},
libafl_qemu_sys::libafl_exit_reason_kind_BREAKPOINT => unsafe {
let bp_addr = exit_reason.data.breakpoint.addr;
QemuExitReason::Breakpoint(bp_addr)
},
libafl_qemu_sys::libafl_exit_reason_kind_CUSTOM_INSN => QemuExitReason::SyncExit,
libafl_qemu_sys::libafl_exit_reason_kind_CRASH => QemuExitReason::Crash,
_ => return Err(QemuExitError::UnknownKind),
})
}
}
}

#[cfg(feature = "python")]
Expand Down
Loading