From 5cd7339b1a99fadbf37eea35053afe4a94cea563 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 16 Jul 2021 10:38:00 +0200 Subject: [PATCH] Qemu read memory mappings (#228) * add x64 syscalls numbers * syscall hook * update commit * read guest mappings * clippy --- fuzzers/fuzzbench_qemu/Makefile | 2 +- libafl/src/executors/timeout.rs | 2 +- libafl_qemu/src/emu.rs | 133 ++++++++++++++++++++++++++++---- libafl_qemu/src/weaks.c | 17 ++++ 4 files changed, 139 insertions(+), 15 deletions(-) diff --git a/fuzzers/fuzzbench_qemu/Makefile b/fuzzers/fuzzbench_qemu/Makefile index de10e631ce..9f9e4b3037 100644 --- a/fuzzers/fuzzbench_qemu/Makefile +++ b/fuzzers/fuzzbench_qemu/Makefile @@ -33,7 +33,7 @@ target/$(BUILD_TARGET)/lib$(FUZZER_NAME).a: src/* qemu-libafl-bridge: git clone git@github.com:AFLplusplus/qemu-libafl-bridge.git - cd qemu-libafl-bridge && git checkout beb8bf68beac1f3b522dab9cda2d00d4a2912c5b + cd qemu-libafl-bridge && git checkout 03dfdbd7da90b2d3b9e4df1a52b5a48e8d453a84 build/config.status: qemu-libafl-bridge qemu-libafl-bridge/configure mkdir -p build diff --git a/libafl/src/executors/timeout.rs b/libafl/src/executors/timeout.rs index 0f0629913c..8886a2f46f 100644 --- a/libafl/src/executors/timeout.rs +++ b/libafl/src/executors/timeout.rs @@ -72,8 +72,8 @@ impl TimeoutExecutor { tv_usec: 0, }; let itimerval = Itimerval { - it_value, it_interval, + it_value, }; Self { executor, diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index 8071ab95ae..a3697497f8 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -1,18 +1,88 @@ //! Expose QEMU user `LibAFL` C api to Rust -use core::{convert::Into, mem::transmute, ptr::copy_nonoverlapping}; +use core::{ + convert::Into, + convert::TryFrom, + ffi::c_void, + mem::{size_of, transmute, MaybeUninit}, + ptr::copy_nonoverlapping, +}; use num::Num; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use std::{mem::size_of, slice::from_raw_parts, str::from_utf8_unchecked}; +use std::{slice::from_raw_parts, str::from_utf8_unchecked}; pub const SKIP_EXEC_HOOK: u32 = u32::MAX; +#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)] +#[repr(i32)] +#[allow(clippy::pub_enum_variant_names)] +pub enum MmapPerms { + Read = libc::PROT_READ, + Write = libc::PROT_WRITE, + Execute = libc::PROT_EXEC, + ReadWrite = libc::PROT_READ | libc::PROT_WRITE, + ReadExecute = libc::PROT_READ | libc::PROT_EXEC, + WriteExecute = libc::PROT_WRITE | libc::PROT_EXEC, + ReadWriteExecute = libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC, +} + #[repr(C)] pub struct SyscallHookResult { retval: u64, skip_syscall: bool, } +#[repr(C)] +pub struct MapInfo { + start: u64, + end: u64, + offset: u64, + path: *const u8, + flags: i32, + is_priv: i32, +} + +impl MapInfo { + #[must_use] + pub fn start(&self) -> u64 { + self.start + } + + #[must_use] + pub fn end(&self) -> u64 { + self.end + } + + #[must_use] + pub fn offset(&self) -> u64 { + self.offset + } + + #[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), + ))) + } + } + } + + #[must_use] + pub fn flags(&self) -> MmapPerms { + MmapPerms::try_from(self.flags).unwrap() + } + + #[must_use] + pub fn is_priv(&self) -> bool { + self.is_priv != 0 + } +} + extern "C" { fn libafl_qemu_write_reg(reg: i32, val: *const u8) -> i32; fn libafl_qemu_read_reg(reg: i32, val: *mut u8) -> i32; @@ -31,6 +101,11 @@ extern "C" { /// int target_munmap(abi_ulong start, abi_ulong len) fn target_munmap(start: u64, len: u64) -> i32; + fn read_self_maps() -> *const c_void; + fn free_self_maps(map_info: *const c_void); + + fn libafl_maps_next(map_info: *const c_void, ret: *mut MapInfo) -> *const c_void; + static exec_path: *const u8; static guest_base: usize; @@ -49,17 +124,49 @@ extern "C" { unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult; } -#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)] -#[repr(i32)] -#[allow(clippy::pub_enum_variant_names)] -pub enum MmapPerms { - Read = libc::PROT_READ, - Write = libc::PROT_WRITE, - Execute = libc::PROT_EXEC, - ReadWrite = libc::PROT_READ | libc::PROT_WRITE, - ReadExecute = libc::PROT_READ | libc::PROT_EXEC, - WriteExecute = libc::PROT_WRITE | libc::PROT_EXEC, - ReadWriteExecute = libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC, +pub struct GuestMaps { + orig_c_iter: *const c_void, + c_iter: *const c_void, +} + +impl GuestMaps { + #[must_use] + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + unsafe { + let maps = read_self_maps(); + Self { + orig_c_iter: maps, + c_iter: maps, + } + } + } +} + +impl Iterator for GuestMaps { + type Item = MapInfo; + + #[allow(clippy::uninit_assumed_init)] + fn next(&mut self) -> Option { + if self.c_iter.is_null() { + return None; + } + unsafe { + let mut ret: MapInfo = MaybeUninit::uninit().assume_init(); + self.c_iter = libafl_maps_next(self.c_iter, &mut ret as *mut _); + if self.c_iter.is_null() { + None + } else { + Some(ret) + } + } + } +} + +impl Drop for GuestMaps { + fn drop(&mut self) { + unsafe { free_self_maps(self.orig_c_iter) } + } } pub fn write_mem(addr: u64, buf: &[T]) { diff --git a/libafl_qemu/src/weaks.c b/libafl_qemu/src/weaks.c index 66f6349dc3..0dfe19d91a 100644 --- a/libafl_qemu/src/weaks.c +++ b/libafl_qemu/src/weaks.c @@ -79,3 +79,20 @@ struct syshook_ret { __attribute__((weak)) struct syshook_ret (*libafl_syscall_hook)(int, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); + +typedef void GSList; + +__attribute__((weak)) GSList * read_self_maps(void) { + return NULL; +} +__attribute__((weak)) void free_self_maps(GSList *map_info) { + (void)map_info; +} + +struct libafl_mapinfo { + uint64_t start, end; + uint64_t offset; + const char* path; + int flags, is_priv; +}; +__attribute__((weak)) GSList * libafl_maps_next(GSList *map_info, struct libafl_mapinfo* ret);