diff --git a/libafl_qemu/libafl_qemu_build/src/bindings.rs b/libafl_qemu/libafl_qemu_build/src/bindings.rs index a0930e8e14..162452cdf6 100644 --- a/libafl_qemu/libafl_qemu_build/src/bindings.rs +++ b/libafl_qemu/libafl_qemu_build/src/bindings.rs @@ -45,6 +45,9 @@ const WRAPPER_HEADER: &str = r#" #include "user/safe-syscall.h" #include "qemu/selfmap.h" #include "cpu_loop-common.h" +#include "qemu/selfmap.h" + +#include "libafl/user.h" #else @@ -55,8 +58,8 @@ const WRAPPER_HEADER: &str = r#" #include "sysemu/tcg.h" #include "sysemu/replay.h" -#include "libafl_extras/syx-snapshot/device-save.h" -#include "libafl_extras/syx-snapshot/syx-snapshot.h" +#include "libafl/syx-snapshot/device-save.h" +#include "libafl/syx-snapshot/syx-snapshot.h" #endif @@ -76,9 +79,9 @@ const WRAPPER_HEADER: &str = r#" #include "qemu/plugin-memory.h" -#include "libafl_extras/exit.h" -#include "libafl_extras/hook.h" -#include "libafl_extras/jit.h" +#include "libafl/exit.h" +#include "libafl/hook.h" +#include "libafl/jit.h" "#; @@ -142,6 +145,8 @@ pub fn generate( .allowlist_type("libafl_exit_reason_sync_backdoor") .allowlist_type("libafl_exit_reason_breakpoint") .allowlist_type("Syx.*") + .allowlist_type("libafl_mapinfo") + .allowlist_type("IntervalTreeRoot") .allowlist_function("qemu_user_init") .allowlist_function("target_mmap") .allowlist_function("target_mprotect") @@ -159,6 +164,8 @@ pub fn generate( .allowlist_function("syx_.*") .allowlist_function("device_list_all") .allowlist_function("libafl_.*") + .allowlist_function("read_self_maps") + .allowlist_function("free_self_maps") .blocklist_function("main_loop_wait") // bindgen issue #1313 .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())); diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index 50e342a3e3..44af50079f 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -8,7 +8,7 @@ use which::which; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -const QEMU_REVISION: &str = "e99b9da6585504a8333f2846a61de487f94d3476"; +const QEMU_REVISION: &str = "50b0c90e0aab07643ccb58cfbbef742bcfb8b7d1"; #[allow(clippy::module_name_repetitions)] pub struct BuildResult { diff --git a/libafl_qemu/libafl_qemu_sys/src/lib.rs b/libafl_qemu/libafl_qemu_sys/src/lib.rs index de4978d7e1..945777745e 100644 --- a/libafl_qemu/libafl_qemu_sys/src/lib.rs +++ b/libafl_qemu/libafl_qemu_sys/src/lib.rs @@ -98,7 +98,7 @@ macro_rules! extern_c_checked { #[cfg(target_os = "linux")] use core::ops::BitAnd; -use std::{ffi::c_void, slice::from_raw_parts, str::from_utf8_unchecked}; +use std::ffi::c_void; #[cfg(all(not(feature = "clippy"), target_os = "linux"))] pub use bindings::*; @@ -127,7 +127,7 @@ pub struct MapInfo { start: GuestAddr, end: GuestAddr, offset: GuestAddr, - path: *const u8, + path: Option, flags: i32, is_priv: i32, } @@ -227,17 +227,8 @@ impl MapInfo { } #[must_use] - pub fn path(&self) -> Option<&str> { - if self.path.is_null() { - None - } else { - unsafe { - Some(from_utf8_unchecked(from_raw_parts( - self.path, - strlen(self.path), - ))) - } - } + pub fn path(&self) -> Option<&String> { + self.path.as_ref() } #[must_use] diff --git a/libafl_qemu/libafl_qemu_sys/src/usermode.rs b/libafl_qemu/libafl_qemu_sys/src/usermode.rs index a925414ed1..a378a96f5c 100644 --- a/libafl_qemu/libafl_qemu_sys/src/usermode.rs +++ b/libafl_qemu/libafl_qemu_sys/src/usermode.rs @@ -1,10 +1,10 @@ -use core::ffi::c_void; +use core::{slice::from_raw_parts, str::from_utf8_unchecked}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use paste::paste; use strum_macros::EnumIter; -use crate::{extern_c_checked, GuestAddr, MapInfo}; +use crate::{extern_c_checked, libafl_mapinfo, strlen, GuestAddr, MapInfo}; extern_c_checked! { pub fn qemu_user_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32; @@ -15,12 +15,6 @@ extern_c_checked! { pub fn libafl_get_brk() -> u64; pub fn libafl_set_brk(brk: u64) -> u64; - pub fn read_self_maps() -> *const c_void; - pub fn free_self_maps(map_info: *const c_void); - - pub fn libafl_maps_first(root: *const c_void) -> *const c_void; - pub fn libafl_maps_next(node: *const c_void, ret: *mut MapInfo, is_root: bool) -> *const c_void; - pub static exec_path: *const u8; pub static guest_base: usize; pub static mut mmap_next_start: GuestAddr; @@ -35,3 +29,30 @@ pub enum VerifyAccess { Read = libc::PROT_READ, Write = libc::PROT_READ | libc::PROT_WRITE, } + +impl From for MapInfo { + fn from(map_info: libafl_mapinfo) -> Self { + let path: Option = if map_info.path.is_null() { + None + } else { + unsafe { + Some( + from_utf8_unchecked(from_raw_parts( + map_info.path as *const u8, + strlen(map_info.path as *const u8), + )) + .to_string(), + ) + } + }; + + MapInfo { + start: map_info.start, + end: map_info.end, + offset: map_info.offset, + path, + flags: map_info.flags, + is_priv: map_info.is_priv, + } + } +} diff --git a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs index 89f96fe304..a94bd688d5 100644 --- a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs +++ b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs @@ -11650,6 +11650,95 @@ impl Default for RBNode { } #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct RBRoot { + pub rb_node: *mut RBNode, +} +#[test] +fn bindgen_test_layout_RBRoot() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(RBRoot)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(RBRoot)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rb_node) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(RBRoot), + "::", + stringify!(rb_node) + ) + ); +} +impl Default for RBRoot { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct RBRootLeftCached { + pub rb_root: RBRoot, + pub rb_leftmost: *mut RBNode, +} +#[test] +fn bindgen_test_layout_RBRootLeftCached() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(RBRootLeftCached)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(RBRootLeftCached)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rb_root) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(RBRootLeftCached), + "::", + stringify!(rb_root) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).rb_leftmost) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(RBRootLeftCached), + "::", + stringify!(rb_leftmost) + ) + ); +} +impl Default for RBRootLeftCached { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct IntervalTreeNode { pub rb: RBNode, pub start: u64, @@ -11720,6 +11809,7 @@ impl Default for IntervalTreeNode { } } } +pub type IntervalTreeRoot = RBRootLeftCached; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct tb_tc { @@ -11983,6 +12073,14 @@ extern "C" { extern "C" { pub fn target_munmap(start: abi_ulong, len: abi_ulong) -> ::std::os::raw::c_int; } +extern "C" { + #[doc = " read_self_maps:\n\n Read /proc/self/maps and return a tree of MapInfo structures."] + pub fn read_self_maps() -> *mut IntervalTreeRoot; +} +extern "C" { + #[doc = " free_self_maps:\n @info: an interval tree\n\n Free a tree of MapInfo structures."] + pub fn free_self_maps(root: *mut IntervalTreeRoot); +} extern "C" { pub fn libafl_breakpoint_invalidate(cpu: *mut CPUState, pc: target_ulong); } @@ -12311,6 +12409,109 @@ extern "C" { } #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct libafl_mapinfo { + pub start: target_ulong, + pub end: target_ulong, + pub offset: target_ulong, + pub path: *const ::std::os::raw::c_char, + pub flags: ::std::os::raw::c_int, + pub is_priv: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_libafl_mapinfo() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!("Size of: ", stringify!(libafl_mapinfo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(libafl_mapinfo)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).start) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(libafl_mapinfo), + "::", + stringify!(start) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).end) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(libafl_mapinfo), + "::", + stringify!(end) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(libafl_mapinfo), + "::", + stringify!(offset) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).path) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(libafl_mapinfo), + "::", + stringify!(path) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(libafl_mapinfo), + "::", + stringify!(flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).is_priv) as usize - ptr as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(libafl_mapinfo), + "::", + stringify!(is_priv) + ) + ); +} +impl Default for libafl_mapinfo { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +extern "C" { + pub fn libafl_maps_first(map_info: *mut IntervalTreeRoot) -> *mut IntervalTreeNode; +} +extern "C" { + pub fn libafl_maps_next( + node: *mut IntervalTreeNode, + ret: *mut libafl_mapinfo, + ) -> *mut IntervalTreeNode; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct AccelCPUClass { pub parent_class: ObjectClass, pub cpu_class_init: ::std::option::Option, @@ -13669,6 +13870,9 @@ extern "C" { extern "C" { pub fn libafl_qemu_remove_new_thread_hook(num: usize) -> ::std::os::raw::c_int; } +extern "C" { + pub fn libafl_tcg_gen_asan(addr: *mut TCGTemp, size: usize); +} extern "C" { pub fn libafl_jit_trace_edge_hitcount(data: u64, id: u64) -> usize; } diff --git a/libafl_qemu/src/emu/usermode.rs b/libafl_qemu/src/emu/usermode.rs index 10e67b652c..241bcd28d5 100644 --- a/libafl_qemu/src/emu/usermode.rs +++ b/libafl_qemu/src/emu/usermode.rs @@ -1,11 +1,11 @@ -use core::{ffi::c_void, mem::MaybeUninit, ptr::copy_nonoverlapping}; +use core::{mem::MaybeUninit, ptr::copy_nonoverlapping}; use std::{cell::OnceCell, slice::from_raw_parts, str::from_utf8_unchecked}; use libafl_qemu_sys::{ exec_path, free_self_maps, guest_base, libafl_dump_core_hook, libafl_force_dfl, libafl_get_brk, libafl_load_addr, libafl_maps_first, libafl_maps_next, libafl_qemu_run, libafl_set_brk, - mmap_next_start, read_self_maps, strlen, GuestAddr, GuestUsize, MapInfo, MmapPerms, - VerifyAccess, + mmap_next_start, read_self_maps, strlen, GuestAddr, GuestUsize, IntervalTreeNode, + IntervalTreeRoot, MapInfo, MmapPerms, VerifyAccess, }; use libc::c_int; #[cfg(feature = "python")] @@ -27,8 +27,8 @@ pub enum HandlerError { #[cfg_attr(feature = "python", pyclass(unsendable))] pub struct GuestMaps { - maps_root: *const c_void, - maps_node: *const c_void, + maps_root: *mut IntervalTreeRoot, + maps_node: *mut IntervalTreeNode, } // Consider a private new only for Emulator @@ -51,13 +51,16 @@ impl Iterator for GuestMaps { #[allow(clippy::uninit_assumed_init)] fn next(&mut self) -> Option { - if self.maps_node.is_null() { - return None; - } unsafe { let mut ret = MaybeUninit::uninit(); - self.maps_node = libafl_maps_next(self.maps_node, ret.as_mut_ptr(), false); - Some(ret.assume_init()) + + self.maps_node = libafl_maps_next(self.maps_node, ret.as_mut_ptr()); + + if self.maps_node.is_null() { + None + } else { + Some(ret.assume_init().into()) + } } } }