Update QEMU syshook ret value (#3092)

* update syshook ret value
This commit is contained in:
Romain Malmain 2025-03-31 15:51:01 +02:00 committed by GitHub
parent c68b30ae2a
commit 184b69be8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 178 additions and 145 deletions

View File

@ -11,7 +11,7 @@ use crate::cargo_add_rpath;
pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
pub const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
pub const QEMU_REVISION: &str = "2a676d9cd8c474b5c0db1d77d2769e56e2ed8524";
pub const QEMU_REVISION: &str = "97bef506eed24ee8d0eda4a07c4419c55dae4acb";
pub struct BuildResult {
pub qemu_path: PathBuf,

View File

@ -1,5 +1,5 @@
/* 1.87.0-nightly */
/* qemu git hash: 2a676d9cd8c474b5c0db1d77d2769e56e2ed8524 */
/* qemu git hash: 97bef506eed24ee8d0eda4a07c4419c55dae4acb */
/* automatically generated by rust-bindgen 0.71.1 */
use libc::siginfo_t;
@ -8687,24 +8687,99 @@ unsafe extern "C" {
unsafe extern "C" {
pub fn libafl_hook_new_thread_run(env: *mut CPUArchState, tid: u32) -> bool;
}
pub const libafl_syshook_ret_tag_LIBAFL_SYSHOOK_RUN: libafl_syshook_ret_tag =
libafl_syshook_ret_tag(0);
pub const libafl_syshook_ret_tag_LIBAFL_SYSHOOK_SKIP: libafl_syshook_ret_tag =
libafl_syshook_ret_tag(1);
impl ::std::ops::BitOr<libafl_syshook_ret_tag> for libafl_syshook_ret_tag {
type Output = Self;
#[inline]
fn bitor(self, other: Self) -> Self {
libafl_syshook_ret_tag(self.0 | other.0)
}
}
impl ::std::ops::BitOrAssign for libafl_syshook_ret_tag {
#[inline]
fn bitor_assign(&mut self, rhs: libafl_syshook_ret_tag) {
self.0 |= rhs.0;
}
}
impl ::std::ops::BitAnd<libafl_syshook_ret_tag> for libafl_syshook_ret_tag {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self {
libafl_syshook_ret_tag(self.0 & other.0)
}
}
impl ::std::ops::BitAndAssign for libafl_syshook_ret_tag {
#[inline]
fn bitand_assign(&mut self, rhs: libafl_syshook_ret_tag) {
self.0 &= rhs.0;
}
}
#[repr(transparent)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct libafl_syshook_ret_tag(pub ::std::os::raw::c_uint);
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct syshook_ret {
pub retval: target_ulong,
pub skip_syscall: bool,
#[derive(Copy, Clone)]
pub struct libafl_syshook_ret {
pub tag: libafl_syshook_ret_tag,
pub __bindgen_anon_1: libafl_syshook_ret__bindgen_ty_1,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union libafl_syshook_ret__bindgen_ty_1 {
pub syshook_skip_retval: target_ulong,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of syshook_ret"][::std::mem::size_of::<syshook_ret>() - 16usize];
["Alignment of syshook_ret"][::std::mem::align_of::<syshook_ret>() - 8usize];
["Offset of field: syshook_ret::retval"][::std::mem::offset_of!(syshook_ret, retval) - 0usize];
["Offset of field: syshook_ret::skip_syscall"]
[::std::mem::offset_of!(syshook_ret, skip_syscall) - 8usize];
["Size of libafl_syshook_ret__bindgen_ty_1"]
[::std::mem::size_of::<libafl_syshook_ret__bindgen_ty_1>() - 8usize];
["Alignment of libafl_syshook_ret__bindgen_ty_1"]
[::std::mem::align_of::<libafl_syshook_ret__bindgen_ty_1>() - 8usize];
["Offset of field: libafl_syshook_ret__bindgen_ty_1::syshook_skip_retval"]
[::std::mem::offset_of!(libafl_syshook_ret__bindgen_ty_1, syshook_skip_retval) - 0usize];
};
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct libafl_pre_syscall_hook {
pub callback: ::std::option::Option<
impl Default for libafl_syshook_ret__bindgen_ty_1 {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
impl ::std::fmt::Debug for libafl_syshook_ret__bindgen_ty_1 {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "libafl_syshook_ret__bindgen_ty_1 {{ union }}")
}
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of libafl_syshook_ret"][::std::mem::size_of::<libafl_syshook_ret>() - 16usize];
["Alignment of libafl_syshook_ret"][::std::mem::align_of::<libafl_syshook_ret>() - 8usize];
["Offset of field: libafl_syshook_ret::tag"]
[::std::mem::offset_of!(libafl_syshook_ret, tag) - 0usize];
};
impl Default for libafl_syshook_ret {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
impl ::std::fmt::Debug for libafl_syshook_ret {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(
f,
"libafl_syshook_ret {{ tag: {:?}, __bindgen_anon_1: {:?} }}",
self.tag, self.__bindgen_anon_1
)
}
}
pub type libafl_pre_syscall_cb = ::std::option::Option<
unsafe extern "C" fn(
data: u64,
sys_num: ::std::os::raw::c_int,
@ -8716,8 +8791,27 @@ pub struct libafl_pre_syscall_hook {
arg5: target_ulong,
arg6: target_ulong,
arg7: target_ulong,
) -> syshook_ret,
>,
) -> libafl_syshook_ret,
>;
pub type libafl_post_syscall_cb = ::std::option::Option<
unsafe extern "C" fn(
data: u64,
ret: target_ulong,
sys_num: ::std::os::raw::c_int,
arg0: target_ulong,
arg1: target_ulong,
arg2: target_ulong,
arg3: target_ulong,
arg4: target_ulong,
arg5: target_ulong,
arg6: target_ulong,
arg7: target_ulong,
) -> target_ulong,
>;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct libafl_pre_syscall_hook {
pub callback: libafl_pre_syscall_cb,
pub data: u64,
pub num: usize,
pub next: *mut libafl_pre_syscall_hook,
@ -8748,21 +8842,7 @@ impl Default for libafl_pre_syscall_hook {
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct libafl_post_syscall_hook {
pub callback: ::std::option::Option<
unsafe extern "C" fn(
data: u64,
ret: target_ulong,
sys_num: ::std::os::raw::c_int,
arg0: target_ulong,
arg1: target_ulong,
arg2: target_ulong,
arg3: target_ulong,
arg4: target_ulong,
arg5: target_ulong,
arg6: target_ulong,
arg7: target_ulong,
) -> target_ulong,
>,
pub callback: libafl_post_syscall_cb,
pub data: u64,
pub num: usize,
pub next: *mut libafl_post_syscall_hook,
@ -8792,43 +8872,10 @@ impl Default for libafl_post_syscall_hook {
}
}
unsafe extern "C" {
pub fn libafl_add_pre_syscall_hook(
callback: ::std::option::Option<
unsafe extern "C" fn(
data: u64,
sys_num: ::std::os::raw::c_int,
arg0: target_ulong,
arg1: target_ulong,
arg2: target_ulong,
arg3: target_ulong,
arg4: target_ulong,
arg5: target_ulong,
arg6: target_ulong,
arg7: target_ulong,
) -> syshook_ret,
>,
data: u64,
) -> usize;
pub fn libafl_add_pre_syscall_hook(callback: libafl_pre_syscall_cb, data: u64) -> usize;
}
unsafe extern "C" {
pub fn libafl_add_post_syscall_hook(
callback: ::std::option::Option<
unsafe extern "C" fn(
data: u64,
ret: target_ulong,
sys_num: ::std::os::raw::c_int,
arg0: target_ulong,
arg1: target_ulong,
arg2: target_ulong,
arg3: target_ulong,
arg4: target_ulong,
arg5: target_ulong,
arg6: target_ulong,
arg7: target_ulong,
) -> target_ulong,
>,
data: u64,
) -> usize;
pub fn libafl_add_post_syscall_hook(callback: libafl_post_syscall_cb, data: u64) -> usize;
}
unsafe extern "C" {
pub fn libafl_qemu_remove_pre_syscall_hook(num: usize) -> ::std::os::raw::c_int;

View File

@ -1,5 +1,5 @@
/* 1.87.0-nightly */
/* qemu git hash: 2a676d9cd8c474b5c0db1d77d2769e56e2ed8524 */
/* qemu git hash: 97bef506eed24ee8d0eda4a07c4419c55dae4acb */
/* automatically generated by rust-bindgen 0.71.1 */
#[repr(C)]

View File

@ -1,5 +1,5 @@
/* 1.87.0-nightly */
/* qemu git hash: 2a676d9cd8c474b5c0db1d77d2769e56e2ed8524 */
/* qemu git hash: 97bef506eed24ee8d0eda4a07c4419c55dae4acb */
/* automatically generated by rust-bindgen 0.71.1 */
#[repr(C)]

View File

@ -98,7 +98,7 @@ pub fn python_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
#[cfg(feature = "usermode")]
m.add_class::<GuestMaps>()?;
m.add_class::<SyscallHookResult>()?;
m.add_class::<pybind::SyscallHookResult>()?;
m.add_class::<pybind::Qemu>()?;
Ok(())

View File

@ -578,9 +578,9 @@ impl AsanGiovese {
}
_ => (),
}
SyscallHookResult::new(Some(r))
SyscallHookResult::Skip(r)
} else {
SyscallHookResult::new(None)
SyscallHookResult::Run
}
}
@ -1350,9 +1350,9 @@ where
}
_ => (),
}
SyscallHookResult::new(Some(0))
SyscallHookResult::Skip(0)
} else {
SyscallHookResult::new(None)
SyscallHookResult::Run
}
}

View File

@ -400,13 +400,13 @@ where
let first_parameter = unsafe {
if (*c_array.offset(1)).is_null() {
return SyscallHookResult::new(None);
return SyscallHookResult::Run;
}
CStr::from_ptr(*c_array.offset(1)).to_string_lossy()
};
let second_parameter = unsafe {
if (*c_array.offset(2)).is_null() {
return SyscallHookResult::new(None);
return SyscallHookResult::Run;
}
CStr::from_ptr(*c_array.offset(2)).to_string_lossy()
};
@ -419,9 +419,9 @@ where
//println!("PARAMETERS First {} Second {}", first_parameter, second_
}
SyscallHookResult::new(Some(0))
SyscallHookResult::Skip(0)
} else {
SyscallHookResult::new(None)
SyscallHookResult::Run
}
}

View File

@ -114,7 +114,7 @@ where
{
let h = emulator_modules.get_mut::<RedirectStdinModule>().unwrap();
if h.input_addr.is_null() {
return SyscallHookResult::new(None);
return SyscallHookResult::Run;
}
if syscall == SYS_read as i32 && x0 == 0 {
/*
@ -143,7 +143,7 @@ where
};
// println!("copied {}", size);
h.read += size as usize;
return SyscallHookResult::new(Some(size));
return SyscallHookResult::Skip(size);
}
SyscallHookResult::new(None)
SyscallHookResult::Run
}

View File

@ -888,11 +888,11 @@ where
if i64::from(sys_num) == SYS_munmap {
let h = emulator_modules.get_mut::<SnapshotModule>().unwrap();
if !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) {
return SyscallHookResult::new(Some(0));
return SyscallHookResult::Skip(0);
}
}
SyscallHookResult::new(None)
SyscallHookResult::Run
}
#[expect(non_upper_case_globals, clippy::too_many_arguments)]

View File

@ -8,8 +8,6 @@ use core::{ffi::c_void, fmt::Debug, mem::transmute, ptr};
use libafl::executors::hooks::inprocess::inprocess_get_state;
use libafl_qemu_sys::{CPUArchStatePtr, CPUStatePtr, FatPtr, GuestAddr, GuestUsize};
#[cfg(feature = "python")]
use pyo3::{FromPyObject, pyclass, pymethods};
use crate::{
HookData, HookId,
@ -85,12 +83,20 @@ pub enum Hook<F, C, R: Clone> {
Empty,
}
/// Syshook result representation
///
/// # Safety
///
/// This enum is shadowed by another enum in QEMU (`libafl_syshook_ret`). Any change made to this
/// enum should be propagated to the C enum as well.
#[repr(C)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", derive(FromPyObject))]
pub struct SyscallHookResult {
pub retval: GuestAddr,
pub skip_syscall: bool,
pub enum SyscallHookResult {
/// Runs the syscall after the hook is executed. The return value will be the one of the
/// syscall itself.
/// If you need to change the return value of the syscall, please use a post-syscall hook.
Run,
/// Skip the syscall, and make the syscall return the value provided in the field in the target.
Skip(GuestAddr),
}
impl<F, C, R: Clone> Hook<F, C, R> {
@ -1281,7 +1287,7 @@ impl QemuHooks {
GuestAddr,
GuestAddr,
GuestAddr,
) -> libafl_qemu_sys::syshook_ret = transmute(callback);
) -> libafl_qemu_sys::libafl_syshook_ret = transmute(callback);
let num = libafl_qemu_sys::libafl_add_pre_syscall_hook(Some(callback), data);
PreSyscallHookId(num)
}
@ -1324,38 +1330,3 @@ impl QemuHooks {
}
}
}
#[cfg(feature = "python")]
#[pymethods]
impl SyscallHookResult {
#[new]
#[pyo3(signature = (
value=None
))]
#[must_use]
pub fn new(value: Option<GuestAddr>) -> Self {
Self::new_internal(value)
}
}
impl SyscallHookResult {
#[cfg(not(feature = "python"))]
#[must_use]
pub fn new(value: Option<GuestAddr>) -> Self {
Self::new_internal(value)
}
#[must_use]
fn new_internal(value: Option<GuestAddr>) -> Self {
value.map_or(
Self {
retval: 0,
skip_syscall: false,
},
|v| Self {
retval: v,
skip_syscall: true,
},
)
}
}

View File

@ -1238,6 +1238,8 @@ impl QemuMemoryChunk {
pub mod pybind {
use pyo3::{exceptions::PyValueError, prelude::*};
#[cfg(feature = "usermode")]
pub use super::usermode::pybind::*;
use super::{GuestAddr, GuestUsize};
static mut PY_GENERIC_HOOKS: Vec<(GuestAddr, PyObject)> = vec![];

View File

@ -467,17 +467,24 @@ impl Qemu {
pub mod pybind {
use libafl_qemu_sys::{GuestAddr, MmapPerms};
use pyo3::{
Bound, PyObject, PyResult, Python,
conversion::FromPyObject,
Bound, FromPyObject, PyObject, PyResult, Python,
exceptions::PyValueError,
pymethods,
pyclass, pymethods,
types::{PyAnyMethods, PyInt},
};
use crate::{pybind::Qemu, qemu::hooks::SyscallHookResult};
use crate::{pybind::Qemu, qemu::hooks};
static mut PY_SYSCALL_HOOK: Option<PyObject> = None;
#[pyclass]
#[derive(FromPyObject)]
pub struct SyscallHookResult {
/// if None: run.
/// else: skip with given value.
skip: Option<GuestAddr>,
}
extern "C" fn py_syscall_hook_wrapper(
_data: u64,
sys_num: i32,
@ -489,25 +496,31 @@ pub mod pybind {
a5: u64,
a6: u64,
a7: u64,
) -> SyscallHookResult {
) -> hooks::SyscallHookResult {
unsafe { (&raw const PY_SYSCALL_HOOK).read() }.map_or_else(
|| SyscallHookResult::new(None),
|| hooks::SyscallHookResult::Run,
|obj| {
let args = (sys_num, a0, a1, a2, a3, a4, a5, a6, a7);
Python::with_gil(|py| {
let ret = obj.call1(py, args).expect("Error in the syscall hook");
let any = ret.bind(py);
if any.is_none() {
SyscallHookResult::new(None)
hooks::SyscallHookResult::Run
} else {
let a: Result<&Bound<'_, PyInt>, _> = any.downcast_exact();
if let Ok(i) = a {
SyscallHookResult::new(Some(
hooks::SyscallHookResult::Skip(
i.extract().expect("Invalid syscall hook return value"),
))
)
} else {
SyscallHookResult::extract_bound(ret.bind(py))
.expect("The syscall hook must return a SyscallHookResult")
let syscall = SyscallHookResult::extract_bound(ret.bind(py))
.expect("The syscall hook must return a SyscallHookResult");
if let Some(ret) = syscall.skip {
hooks::SyscallHookResult::Skip(ret)
} else {
hooks::SyscallHookResult::Run
}
}
}
})