diff --git a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs index 6baac70420..cc49c6e09e 100644 --- a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs @@ -51,7 +51,7 @@ use libafl_qemu::{ emu::Emulator, filter_qemu_args, hooks::QemuHooks, - MmapPerms, QemuForkExecutor, Regs, + GuestReg, MmapPerms, QemuForkExecutor, Regs, }; #[cfg(unix)] use nix::{self, unistd::dup}; @@ -318,7 +318,7 @@ fn fuzz( emu.write_mem(input_addr, buf); emu.write_reg(Regs::Rdi, input_addr).unwrap(); - emu.write_reg(Regs::Rsi, len).unwrap(); + emu.write_reg(Regs::Rsi, len as GuestReg).unwrap(); emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap(); emu.write_reg(Regs::Rsp, stack_ptr).unwrap(); diff --git a/fuzzers/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_qemu/src/fuzzer.rs index e872e38281..db1c4d45ed 100644 --- a/fuzzers/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_qemu/src/fuzzer.rs @@ -54,6 +54,7 @@ use libafl_qemu::{ emu::Emulator, filter_qemu_args, hooks::QemuHooks, + GuestReg, //snapshot::QemuSnapshotHelper, MmapPerms, QemuExecutor, @@ -330,7 +331,7 @@ fn fuzz( emu.write_mem(input_addr, buf); emu.write_reg(Regs::Rdi, input_addr).unwrap(); - emu.write_reg(Regs::Rsi, len).unwrap(); + emu.write_reg(Regs::Rsi, len as GuestReg).unwrap(); emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap(); emu.write_reg(Regs::Rsp, stack_ptr).unwrap(); diff --git a/fuzzers/qemu_coverage/Cargo.toml b/fuzzers/qemu_coverage/Cargo.toml index 39e55b3fa1..e7b8cd0442 100644 --- a/fuzzers/qemu_coverage/Cargo.toml +++ b/fuzzers/qemu_coverage/Cargo.toml @@ -13,12 +13,11 @@ debug = true [features] default = ["std"] std = [] -be = [] -64bit = [] +be = ["libafl_qemu/be"] arm = ["libafl_qemu/arm"] -x86_64 = ["libafl_qemu/x86_64", "64bit"] +x86_64 = ["libafl_qemu/x86_64"] i386 = ["libafl_qemu/i386"] -aarch64 = ["libafl_qemu/aarch64", "64bit"] +aarch64 = ["libafl_qemu/aarch64"] mips = ["libafl_qemu/mips"] ppc = ["libafl_qemu/ppc", "be"] diff --git a/fuzzers/qemu_coverage/src/fuzzer.rs b/fuzzers/qemu_coverage/src/fuzzer.rs index c69192960b..135de32e96 100644 --- a/fuzzers/qemu_coverage/src/fuzzer.rs +++ b/fuzzers/qemu_coverage/src/fuzzer.rs @@ -28,17 +28,11 @@ use libafl::{ Error, }; use libafl_qemu::{ - drcov::QemuDrCovHelper, elf::EasyElf, emu::Emulator, MmapPerms, QemuExecutor, QemuHooks, - QemuInstrumentationFilter, Regs, + drcov::QemuDrCovHelper, elf::EasyElf, emu::Emulator, ArchExtras, CallingConvention, GuestAddr, + GuestReg, MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationFilter, Regs, }; use rangemap::RangeMap; -#[cfg(feature = "64bit")] -type GuestReg = u64; - -#[cfg(not(feature = "64bit"))] -type GuestReg = u32; - #[derive(Default)] pub struct Version; @@ -141,60 +135,10 @@ pub fn fuzz() { ); } - let read_reg = |emu: &Emulator, reg: Regs| -> GuestReg { - let val: GuestReg = emu.read_reg(reg).unwrap(); - - #[cfg(feature = "be")] - return GuestReg::from_be(val); - - #[cfg(not(feature = "be"))] - return GuestReg::from_le(val); - }; - - let write_reg = |emu: &Emulator, reg: Regs, val: GuestReg| { - #[cfg(feature = "be")] - let val = GuestReg::to_be(val); - - #[cfg(not(feature = "be"))] - let val = GuestReg::to_le(val); - - emu.write_reg(reg, val).unwrap(); - }; - - println!("Break at {:#x}", read_reg(&emu, Regs::Pc)); - - #[cfg(feature = "arm")] - let ret_addr: u32 = read_reg(&emu, Regs::Lr); - - #[cfg(feature = "aarch64")] - let ret_addr: u64 = read_reg(&emu, Regs::Lr); - - #[cfg(feature = "x86_64")] - let stack_ptr: u64 = read_reg(&emu, Regs::Rsp); - - #[cfg(feature = "x86_64")] - let ret_addr: u64 = { - let mut ret_addr = [0; 8]; - unsafe { emu.read_mem(stack_ptr, &mut ret_addr) }; - u64::from_le_bytes(ret_addr) - }; - - #[cfg(feature = "i386")] - let stack_ptr: u32 = read_reg(&emu, Regs::Esp); - - #[cfg(feature = "i386")] - let ret_addr: u32 = { - let mut ret_addr = [0; 4]; - unsafe { emu.read_mem(stack_ptr, &mut ret_addr) }; - u32::from_le_bytes(ret_addr) - }; - - #[cfg(feature = "mips")] - let ret_addr: u32 = read_reg(&emu, Regs::Ra); - - #[cfg(feature = "ppc")] - let ret_addr: u32 = read_reg(&emu, Regs::Lr); + let pc: GuestReg = emu.read_reg(Regs::Pc).unwrap(); + println!("Break at {pc:#x}"); + let ret_addr: GuestAddr = emu.read_return_address().unwrap(); println!("Return address = {ret_addr:#x}"); emu.remove_breakpoint(test_one_input_ptr); @@ -203,6 +147,21 @@ pub fn fuzz() { let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap(); println!("Placing input at {input_addr:#x}"); + let stack_ptr: GuestAddr = emu.read_reg(Regs::Sp).unwrap(); + + let reset = |buf: &[u8], len: GuestReg| -> Result<(), String> { + unsafe { + emu.write_mem(input_addr, buf); + emu.write_reg(Regs::Pc, test_one_input_ptr)?; + emu.write_reg(Regs::Sp, stack_ptr)?; + emu.write_return_address(ret_addr)?; + emu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?; + emu.write_function_argument(CallingConvention::Cdecl, 1, len)?; + emu.run(); + Ok(()) + } + }; + let mut harness = |input: &BytesInput| { let target = input.target_bytes(); let buf = target @@ -211,65 +170,7 @@ pub fn fuzz() { .next() .expect("Failed to get chunk"); let len = buf.len() as GuestReg; - - unsafe { - emu.write_mem(input_addr, buf); - - #[cfg(feature = "arm")] - { - write_reg(&emu, Regs::R0, input_addr); - write_reg(&emu, Regs::R1, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Lr, ret_addr); - } - - #[cfg(feature = "aarch64")] - { - write_reg(&emu, Regs::X0, input_addr); - write_reg(&emu, Regs::X1, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Lr, ret_addr); - } - - #[cfg(feature = "x86_64")] - { - write_reg(&emu, Regs::Rdi, input_addr); - write_reg(&emu, Regs::Rsi, len); - write_reg(&emu, Regs::Rip, test_one_input_ptr); - write_reg(&emu, Regs::Rsp, stack_ptr); - } - - #[cfg(feature = "i386")] - { - let input_addr_bytes = input_addr.to_le_bytes(); - emu.write_mem(stack_ptr + (size_of::() as u32), &input_addr_bytes); - - let len_bytes = len.to_le_bytes(); - emu.write_mem(stack_ptr + ((2 * size_of::()) as u32), &len_bytes); - - write_reg(&emu, Regs::Eip, test_one_input_ptr); - write_reg(&emu, Regs::Esp, stack_ptr); - } - - #[cfg(feature = "mips")] - { - write_reg(&emu, Regs::A0, input_addr); - write_reg(&emu, Regs::A1, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Ra, ret_addr); - } - - #[cfg(feature = "ppc")] - { - write_reg(&emu, Regs::R3, input_addr); - write_reg(&emu, Regs::R4, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Lr, ret_addr); - } - - emu.run(); - } - + reset(buf, len).unwrap(); ExitKind::Ok }; diff --git a/fuzzers/qemu_launcher/Cargo.toml b/fuzzers/qemu_launcher/Cargo.toml index 8e80c01c8e..0d85aa7d77 100644 --- a/fuzzers/qemu_launcher/Cargo.toml +++ b/fuzzers/qemu_launcher/Cargo.toml @@ -7,12 +7,11 @@ edition = "2021" [features] default = ["std"] std = [] -be = [] -64bit = [] +be = ["libafl_qemu/be"] arm = ["libafl_qemu/arm"] -x86_64 = ["libafl_qemu/x86_64", "64bit"] +x86_64 = ["libafl_qemu/x86_64"] i386 = ["libafl_qemu/i386"] -aarch64 = ["libafl_qemu/aarch64", "64bit"] +aarch64 = ["libafl_qemu/aarch64"] mips = ["libafl_qemu/mips"] ppc = ["libafl_qemu/ppc", "be"] diff --git a/fuzzers/qemu_launcher/src/fuzzer.rs b/fuzzers/qemu_launcher/src/fuzzer.rs index e422e8727b..82cb6f4ba2 100644 --- a/fuzzers/qemu_launcher/src/fuzzer.rs +++ b/fuzzers/qemu_launcher/src/fuzzer.rs @@ -1,7 +1,5 @@ //! A libfuzzer-like fuzzer using qemu for binary-only coverage //! -#[cfg(feature = "i386")] -use core::mem::size_of; use core::{ptr::addr_of_mut, time::Duration}; use std::{env, path::PathBuf, process}; @@ -36,16 +34,11 @@ use libafl_qemu::{ edges::{edges_map_mut_slice, QemuEdgeCoverageHelper, MAX_EDGES_NUM}, elf::EasyElf, emu::Emulator, - MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationFilter, Regs, + ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, QemuExecutor, QemuHooks, + QemuInstrumentationFilter, Regs, }; use rangemap::RangeMap; -#[cfg(feature = "64bit")] -type GuestReg = u64; - -#[cfg(not(feature = "64bit"))] -type GuestReg = u32; - #[derive(Default)] pub struct Version; @@ -148,60 +141,10 @@ pub fn fuzz() { ); } - let read_reg = |emu: &Emulator, reg: Regs| -> GuestReg { - let val: GuestReg = emu.read_reg(reg).unwrap(); - - #[cfg(feature = "be")] - return GuestReg::from_be(val); - - #[cfg(not(feature = "be"))] - return GuestReg::from_le(val); - }; - - let write_reg = |emu: &Emulator, reg: Regs, val: GuestReg| { - #[cfg(feature = "be")] - let val = GuestReg::to_be(val); - - #[cfg(not(feature = "be"))] - let val = GuestReg::to_le(val); - - emu.write_reg(reg, val).unwrap(); - }; - - println!("Break at {:#x}", read_reg(&emu, Regs::Pc)); - - #[cfg(feature = "arm")] - let ret_addr: u32 = read_reg(&emu, Regs::Lr); - - #[cfg(feature = "aarch64")] - let ret_addr: u64 = read_reg(&emu, Regs::Lr); - - #[cfg(feature = "x86_64")] - let stack_ptr: u64 = read_reg(&emu, Regs::Rsp); - - #[cfg(feature = "x86_64")] - let ret_addr: u64 = { - let mut ret_addr = [0; 8]; - unsafe { emu.read_mem(stack_ptr, &mut ret_addr) }; - u64::from_le_bytes(ret_addr) - }; - - #[cfg(feature = "i386")] - let stack_ptr: u32 = read_reg(&emu, Regs::Esp); - - #[cfg(feature = "i386")] - let ret_addr: u32 = { - let mut ret_addr = [0; 4]; - unsafe { emu.read_mem(stack_ptr, &mut ret_addr) }; - u32::from_le_bytes(ret_addr) - }; - - #[cfg(feature = "mips")] - let ret_addr: u32 = read_reg(&emu, Regs::Ra); - - #[cfg(feature = "ppc")] - let ret_addr: u32 = read_reg(&emu, Regs::Lr); + let pc: GuestReg = emu.read_reg(Regs::Pc).unwrap(); + println!("Break at {pc:#x}"); + let ret_addr: GuestAddr = emu.read_return_address().unwrap(); println!("Return address = {ret_addr:#x}"); emu.remove_breakpoint(test_one_input_ptr); @@ -210,6 +153,21 @@ pub fn fuzz() { let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap(); println!("Placing input at {input_addr:#x}"); + let stack_ptr: GuestAddr = emu.read_reg(Regs::Sp).unwrap(); + + let reset = |buf: &[u8], len: GuestReg| -> Result<(), String> { + unsafe { + emu.write_mem(input_addr, buf); + emu.write_reg(Regs::Pc, test_one_input_ptr)?; + emu.write_reg(Regs::Sp, stack_ptr)?; + emu.write_return_address(ret_addr)?; + emu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?; + emu.write_function_argument(CallingConvention::Cdecl, 1, len)?; + emu.run(); + Ok(()) + } + }; + let mut harness = |input: &BytesInput| { let target = input.target_bytes(); let buf = target @@ -218,65 +176,7 @@ pub fn fuzz() { .next() .expect("Failed to get chunk"); let len = buf.len() as GuestReg; - - unsafe { - emu.write_mem(input_addr, buf); - - #[cfg(feature = "arm")] - { - write_reg(&emu, Regs::R0, input_addr); - write_reg(&emu, Regs::R1, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Lr, ret_addr); - } - - #[cfg(feature = "aarch64")] - { - write_reg(&emu, Regs::X0, input_addr); - write_reg(&emu, Regs::X1, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Lr, ret_addr); - } - - #[cfg(feature = "x86_64")] - { - write_reg(&emu, Regs::Rdi, input_addr); - write_reg(&emu, Regs::Rsi, len); - write_reg(&emu, Regs::Rip, test_one_input_ptr); - write_reg(&emu, Regs::Rsp, stack_ptr); - } - - #[cfg(feature = "i386")] - { - let input_addr_bytes = input_addr.to_le_bytes(); - emu.write_mem(stack_ptr + (size_of::() as u32), &input_addr_bytes); - - let len_bytes = len.to_le_bytes(); - emu.write_mem(stack_ptr + ((2 * size_of::()) as u32), &len_bytes); - - write_reg(&emu, Regs::Eip, test_one_input_ptr); - write_reg(&emu, Regs::Esp, stack_ptr); - } - - #[cfg(feature = "mips")] - { - write_reg(&emu, Regs::A0, input_addr); - write_reg(&emu, Regs::A1, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Ra, ret_addr); - } - - #[cfg(feature = "ppc")] - { - write_reg(&emu, Regs::R3, input_addr); - write_reg(&emu, Regs::R4, len); - write_reg(&emu, Regs::Pc, test_one_input_ptr); - write_reg(&emu, Regs::Lr, ret_addr); - } - - emu.run(); - } - + reset(buf, len).unwrap(); ExitKind::Ok }; diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 3fc9457de5..321a9d7cda 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -1867,13 +1867,13 @@ mod tests { #[test] fn test_read_tokens() { let _res = fs::remove_file("test.tkns"); - let data = r###" + let data = r#" # comment token1@123="AAA" token1="A\x41A" "A\AA" token2="B" - "###; + "#; fs::write("test.tkns", data).expect("Unable to write test.tkns"); let tokens = Tokens::from_file("test.tkns").unwrap(); log::info!("Token file entries: {:?}", tokens.tokens()); diff --git a/libafl_frida/src/alloc.rs b/libafl_frida/src/alloc.rs index fe7bb00fca..b6e35dbe88 100644 --- a/libafl_frida/src/alloc.rs +++ b/libafl_frida/src/alloc.rs @@ -385,14 +385,13 @@ impl Allocator { metadatas.sort_by(|a, b| a.address.cmp(&b.address)); let mut offset_to_closest = i64::max_value(); let mut closest = None; + let ptr: i64 = ptr.try_into().unwrap(); for metadata in metadatas { + let address: i64 = metadata.address.try_into().unwrap(); let new_offset = if hint_base == metadata.address { - (ptr as i64 - metadata.address as i64).abs() + (ptr - address).abs() } else { - std::cmp::min( - offset_to_closest, - (ptr as i64 - metadata.address as i64).abs(), - ) + std::cmp::min(offset_to_closest, (ptr - address).abs()) }; if new_offset < offset_to_closest { offset_to_closest = new_offset; diff --git a/libafl_frida/src/asan/errors.rs b/libafl_frida/src/asan/errors.rs index 4be258c9de..0bc0488823 100644 --- a/libafl_frida/src/asan/errors.rs +++ b/libafl_frida/src/asan/errors.rs @@ -251,14 +251,13 @@ impl AsanErrors { cs.set_skipdata(true).expect("failed to set skipdata"); let start_pc = error.pc - 4 * 5; - for insn in cs + for insn in &*cs .disasm_count( unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) }, start_pc as u64, 11, ) .expect("failed to disassemble instructions") - .iter() { if insn.address() as usize == error.pc { output @@ -276,7 +275,9 @@ impl AsanErrors { #[allow(clippy::non_ascii_literal)] writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap(); - let offset: i64 = fault_address as i64 - (error.metadata.address + 0x1000) as i64; + let fault_address: i64 = fault_address.try_into().unwrap(); + let metadata_address: i64 = error.metadata.address.try_into().unwrap(); + let offset: i64 = fault_address - (metadata_address + 0x1000); let direction = if offset > 0 { "right" } else { "left" }; writeln!( output, @@ -505,14 +506,13 @@ impl AsanErrors { cs.set_skipdata(true).expect("failed to set skipdata"); let start_pc = pc; - for insn in cs + for insn in &*cs .disasm_count( unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) }, start_pc as u64, 11, ) .expect("failed to disassemble instructions") - .iter() { if insn.address() as usize == pc { output diff --git a/libafl_frida/src/coverage_rt.rs b/libafl_frida/src/coverage_rt.rs index a55e42b999..8d53680687 100644 --- a/libafl_frida/src/coverage_rt.rs +++ b/libafl_frida/src/coverage_rt.rs @@ -150,7 +150,7 @@ impl CoverageRuntime { ; mov QWORD [rsp-0x98], rbx // Load the previous_pc - ; mov rax, QWORD prev_loc_ptr as *mut u64 as _ + ; mov rax, QWORD prev_loc_ptr as _ ; mov rax, QWORD [rax] // Calculate the edge id @@ -158,7 +158,7 @@ impl CoverageRuntime { ; xor rax, rbx // Load the map byte address - ; mov rbx, QWORD map_addr_ptr as *mut [u8; MAP_SIZE] as _ + ; mov rbx, QWORD map_addr_ptr as _ ; add rax, rbx // Update the map byte @@ -168,7 +168,7 @@ impl CoverageRuntime { ; mov BYTE [rax],bl // Update the previous_pc value - ; mov rax, QWORD prev_loc_ptr as *mut u64 as _ + ; mov rax, QWORD prev_loc_ptr as _ ; mov ebx, WORD (h64 >> 1) as i32 ; mov QWORD [rax], rbx diff --git a/libafl_qemu/src/aarch64.rs b/libafl_qemu/src/aarch64.rs index 56c6aee4f7..0e783b7a09 100644 --- a/libafl_qemu/src/aarch64.rs +++ b/libafl_qemu/src/aarch64.rs @@ -4,6 +4,8 @@ use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::aarch64::*; +use crate::CallingConvention; + #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[repr(i32)] pub enum Regs { @@ -62,3 +64,42 @@ impl IntoPy for Regs { pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder { capstone::Capstone::new().arm64() } + +pub type GuestReg = u64; + +impl crate::ArchExtras for crate::CPU { + fn read_return_address(&self) -> Result + where + T: From, + { + self.read_reg(Regs::Lr) + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + self.write_reg(Regs::Lr, val) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + let val: GuestReg = val.into(); + match idx { + 0 => self.write_reg(Regs::X0, val), + 1 => self.write_reg(Regs::X1, val), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } +} diff --git a/libafl_qemu/src/arm.rs b/libafl_qemu/src/arm.rs index 5cf02ebad7..87dc9fc7c9 100644 --- a/libafl_qemu/src/arm.rs +++ b/libafl_qemu/src/arm.rs @@ -5,6 +5,8 @@ use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::arm::*; +use crate::CallingConvention; + /// Registers for the ARM instruction set. #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[repr(i32)] @@ -62,3 +64,42 @@ pub fn capstone_thumb() -> capstone::arch::arm::ArchCapstoneBuilder { .arm() .mode(capstone::arch::arm::ArchMode::Thumb) } + +pub type GuestReg = u32; + +impl crate::ArchExtras for crate::CPU { + fn read_return_address(&self) -> Result + where + T: From, + { + self.read_reg(Regs::Lr) + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + self.write_reg(Regs::Lr, val) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + let val: GuestReg = val.into(); + match idx { + 0 => self.write_reg(Regs::R0, val), + 1 => self.write_reg(Regs::R1, val), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } +} diff --git a/libafl_qemu/src/asan.rs b/libafl_qemu/src/asan.rs index 65456196e5..ccdfecaaaf 100644 --- a/libafl_qemu/src/asan.rs +++ b/libafl_qemu/src/asan.rs @@ -395,7 +395,7 @@ impl AsanGiovese { if self.snapshot_shadow { let set = self.dirty_shadow.lock().unwrap(); - for &page in set.iter() { + for &page in &*set { let data = Self::get_shadow_page(emu, page).to_vec(); self.saved_shadow.insert(page, data); } @@ -425,7 +425,7 @@ impl AsanGiovese { if self.snapshot_shadow { let mut set = self.dirty_shadow.lock().unwrap(); - for &page in set.iter() { + for &page in &*set { let original = self.saved_shadow.get(&page); if let Some(data) = original { let cur = Self::get_shadow_page(emu, page); @@ -472,7 +472,7 @@ pub fn init_with_asan( |e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..]; let mut added = false; - for (k, v) in env.iter_mut() { + for (k, v) in &mut *env { if k == "QEMU_SET_ENV" { let mut new_v = vec![]; for e in v.split(',') { diff --git a/libafl_qemu/src/calls.rs b/libafl_qemu/src/calls.rs index fa94c72a61..2e7ba6337c 100644 --- a/libafl_qemu/src/calls.rs +++ b/libafl_qemu/src/calls.rs @@ -10,10 +10,10 @@ use libafl::{ use crate::{ capstone, - emu::Emulator, + emu::{ArchExtras, Emulator}, helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, hooks::QemuHooks, - GuestAddr, Regs, + GuestAddr, }; pub trait CallTraceCollector: 'static + Debug { @@ -242,51 +242,7 @@ where S: UsesInput, QT: QemuHelperTuple, { - #[cfg(cpu_target = "x86_64")] - let ret_addr = { - let emu = hooks.emulator(); - let stack_ptr: GuestAddr = emu.read_reg(Regs::Rsp).unwrap(); - let mut ret_addr = [0; 8]; - unsafe { emu.read_mem(stack_ptr, &mut ret_addr) }; - GuestAddr::from_le_bytes(ret_addr) - }; - - #[cfg(cpu_target = "i386")] - let ret_addr = { - let emu = hooks.emulator(); - let stack_ptr: GuestAddr = emu.read_reg(Regs::Esp).unwrap(); - let mut ret_addr = [0; 4]; - unsafe { emu.read_mem(stack_ptr, &mut ret_addr) }; - GuestAddr::from_le_bytes(ret_addr) - }; - - #[cfg(any(cpu_target = "arm", cpu_target = "aarch64"))] - let ret_addr = { - let emu = hooks.emulator(); - let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap(); - ret_addr - }; - - #[cfg(cpu_target = "mips")] - let ret_addr = { - let emu = hooks.emulator(); - let ret_addr: GuestAddr = emu.read_reg(Regs::Ra).unwrap(); - ret_addr - }; - - #[cfg(cpu_target = "ppc")] - let ret_addr = { - let emu = hooks.emulator(); - let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap(); - ret_addr - }; - - #[cfg(cpu_target = "hexagon")] - let ret_addr = { - let emu = hooks.emulator(); - let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap(); - ret_addr - }; + let ret_addr: GuestAddr = hooks.emulator().read_return_address().unwrap(); // log::info!("RET @ 0x{:#x}", ret_addr); diff --git a/libafl_qemu/src/drcov.rs b/libafl_qemu/src/drcov.rs index 17ddabe4e1..4e8057aee4 100644 --- a/libafl_qemu/src/drcov.rs +++ b/libafl_qemu/src/drcov.rs @@ -102,8 +102,8 @@ where if self.full_trace { if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len { let mut drcov_vec = Vec::::new(); - for id in DRCOV_IDS.lock().unwrap().as_ref().unwrap().iter() { - 'pcs_full: for (pc, idm) in DRCOV_MAP.lock().unwrap().as_ref().unwrap().iter() { + for id in DRCOV_IDS.lock().unwrap().as_ref().unwrap() { + 'pcs_full: for (pc, idm) in DRCOV_MAP.lock().unwrap().as_ref().unwrap() { let mut module_found = false; for module in self.module_mapping.iter() { let (range, (_, _)) = module; @@ -141,7 +141,7 @@ where } else { if DRCOV_MAP.lock().unwrap().as_ref().unwrap().len() > self.drcov_len { let mut drcov_vec = Vec::::new(); - 'pcs: for (pc, _) in DRCOV_MAP.lock().unwrap().as_ref().unwrap().iter() { + 'pcs: for (pc, _) in DRCOV_MAP.lock().unwrap().as_ref().unwrap() { let mut module_found = false; for module in self.module_mapping.iter() { let (range, (_, _)) = module; diff --git a/libafl_qemu/src/elf.rs b/libafl_qemu/src/elf.rs index bfc42e5328..5917872894 100644 --- a/libafl_qemu/src/elf.rs +++ b/libafl_qemu/src/elf.rs @@ -41,7 +41,7 @@ impl<'a> EasyElf<'a> { #[must_use] pub fn resolve_symbol(&self, name: &str, load_addr: GuestAddr) -> Option { - for sym in self.elf.syms.iter() { + for sym in &self.elf.syms { if let Some(sym_name) = self.elf.strtab.get_at(sym.st_name) { if sym_name == name { return if sym.st_value == 0 { diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index 53ae0352b4..712d67458d 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -17,6 +17,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_traits::Num; use strum_macros::EnumIter; +use crate::GuestReg; + pub type GuestAddr = libafl_qemu_sys::target_ulong; pub type GuestUsize = libafl_qemu_sys::target_ulong; pub type GuestIsize = libafl_qemu_sys::target_long; @@ -485,6 +487,28 @@ pub struct CPU { ptr: CPUStatePtr, } +#[derive(Debug, PartialEq)] +pub enum CallingConvention { + Cdecl, +} + +pub trait ArchExtras { + fn read_return_address(&self) -> Result + where + T: From; + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into; + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into; +} + #[allow(clippy::unused_self)] impl CPU { #[must_use] @@ -617,8 +641,15 @@ impl CPU { pub fn write_reg(&self, reg: R, val: T) -> Result<(), String> where R: Into, + T: Into, { let reg = reg.into(); + #[cfg(feature = "be")] + let val = GuestReg::to_be(val.into()); + + #[cfg(not(feature = "be"))] + let val = GuestReg::to_le(val.into()); + let success = unsafe { libafl_qemu_write_reg(self.ptr, reg, addr_of!(val) as *const u8) }; if success == 0 { Err(format!("Failed to write to register {reg}")) @@ -630,6 +661,7 @@ impl CPU { pub fn read_reg(&self, reg: R) -> Result where R: Into, + T: From, { unsafe { let reg = reg.into(); @@ -638,7 +670,11 @@ impl CPU { if success == 0 { Err(format!("Failed to read register {reg}")) } else { - Ok(val.assume_init()) + #[cfg(feature = "be")] + return Ok(GuestReg::from_be(val.assume_init()).into()); + + #[cfg(not(feature = "be"))] + return Ok(GuestReg::from_le(val.assume_init()).into()); } } } @@ -739,11 +775,7 @@ impl Emulator { envp.push(null()); unsafe { #[cfg(emulation_mode = "usermode")] - qemu_user_init( - argc, - argv.as_ptr() as *const *const u8, - envp.as_ptr() as *const *const u8, - ); + qemu_user_init(argc, argv.as_ptr(), envp.as_ptr()); #[cfg(emulation_mode = "systemmode")] { qemu_init( @@ -861,7 +893,7 @@ impl Emulator { pub fn write_reg(&self, reg: R, val: T) -> Result<(), String> where - T: Num + PartialOrd + Copy, + T: Num + PartialOrd + Copy + Into, R: Into, { self.current_cpu().unwrap().write_reg(reg, val) @@ -869,7 +901,7 @@ impl Emulator { pub fn read_reg(&self, reg: R) -> Result where - T: Num + PartialOrd + Copy, + T: Num + PartialOrd + Copy + From, R: Into, { self.current_cpu().unwrap().read_reg(reg) @@ -1154,6 +1186,40 @@ impl Emulator { } } +impl ArchExtras for Emulator { + fn read_return_address(&self) -> Result + where + T: From, + { + self.current_cpu() + .ok_or("Failed to get current CPU")? + .read_return_address::() + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + self.current_cpu() + .ok_or("Failed to get current CPU")? + .write_return_address::(val) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + self.current_cpu() + .ok_or("Failed to get current CPU")? + .write_function_argument::(conv, idx, val) + } +} + #[cfg(feature = "python")] pub mod pybind { use std::convert::TryFrom; diff --git a/libafl_qemu/src/hexagon.rs b/libafl_qemu/src/hexagon.rs index f4eadba613..fde8de98ce 100644 --- a/libafl_qemu/src/hexagon.rs +++ b/libafl_qemu/src/hexagon.rs @@ -3,6 +3,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; use pyo3::prelude::*; pub use strum_macros::EnumIter; +use crate::CallingConvention; + #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[repr(i32)] pub enum Regs { @@ -66,3 +68,37 @@ impl Regs { pub const Fp: Regs = Regs::R30; pub const Lr: Regs = Regs::R31; } + +pub type GuestReg = u32; + +impl crate::ArchExtras for crate::CPU { + fn read_return_address(&self) -> Result + where + T: From, + { + self.read_reg(Regs::Lr) + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + self.write_reg(Regs::Lr, val) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + Err(format!("Unsupported argument: {idx:}")) + } +} diff --git a/libafl_qemu/src/i386.rs b/libafl_qemu/src/i386.rs index 56ccd3b086..c54461356d 100644 --- a/libafl_qemu/src/i386.rs +++ b/libafl_qemu/src/i386.rs @@ -1,3 +1,5 @@ +use std::mem::size_of; + use capstone::arch::BuildsCapstone; use num_enum::{IntoPrimitive, TryFromPrimitive}; #[cfg(feature = "python")] @@ -5,6 +7,8 @@ use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::x86::*; +use crate::{CallingConvention, GuestAddr}; + #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[repr(i32)] pub enum Regs { @@ -41,3 +45,62 @@ pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder { .x86() .mode(capstone::arch::x86::ArchMode::Mode32) } + +pub type GuestReg = u32; + +impl crate::ArchExtras for crate::CPU { + fn read_return_address(&self) -> Result + where + T: From, + { + let stack_ptr: GuestReg = self.read_reg(Regs::Esp)?; + let mut ret_addr = [0; size_of::()]; + unsafe { self.read_mem(stack_ptr, &mut ret_addr) }; + Ok(GuestReg::from_le_bytes(ret_addr).into()) + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + let stack_ptr: GuestReg = self.read_reg(Regs::Esp)?; + let val: GuestReg = val.into(); + let ret_addr = val.to_le_bytes(); + unsafe { self.write_mem(stack_ptr, &ret_addr) }; + Ok(()) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + match idx { + 0..=1 => { + let val: GuestReg = val.into(); + let stack_ptr: GuestAddr = self.read_reg(Regs::Sp)?; + /* + * Stack is full and descending. SP points to return address, arguments + * are in reverse order above that. + */ + let size: GuestAddr = size_of::() as GuestAddr; + let offset = size * (idx as GuestAddr + 1); + + let arg = val.to_le_bytes(); + unsafe { + self.write_mem(stack_ptr + offset, &arg); + } + Ok(()) + } + _ => Err(format!("Unsupported argument: {idx:}")), + } + } +} diff --git a/libafl_qemu/src/mips.rs b/libafl_qemu/src/mips.rs index 72469bc5e5..7a1636e07d 100644 --- a/libafl_qemu/src/mips.rs +++ b/libafl_qemu/src/mips.rs @@ -4,6 +4,8 @@ use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::mips::*; +use crate::CallingConvention; + /// Registers for the MIPS instruction set. #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[repr(i32)] @@ -62,3 +64,42 @@ impl IntoPy for Regs { pub fn capstone() -> capstone::arch::mips::ArchCapstoneBuilder { capstone::Capstone::new().mips() } + +pub type GuestReg = u32; + +impl crate::ArchExtras for crate::CPU { + fn read_return_address(&self) -> Result + where + T: From, + { + self.read_reg(Regs::Ra) + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + self.write_reg(Regs::Ra, val) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + let val: GuestReg = val.into(); + match idx { + 0 => self.write_reg(Regs::A0, val), + 1 => self.write_reg(Regs::A1, val), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } +} diff --git a/libafl_qemu/src/ppc.rs b/libafl_qemu/src/ppc.rs index b6fb27cea1..3a81b9bc67 100644 --- a/libafl_qemu/src/ppc.rs +++ b/libafl_qemu/src/ppc.rs @@ -4,6 +4,8 @@ use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::powerpc::*; +use crate::CallingConvention; + /// Registers for the MIPS instruction set. #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[repr(i32)] @@ -87,6 +89,7 @@ pub enum Regs { #[allow(non_upper_case_globals)] impl Regs { pub const Pc: Regs = Regs::Nip; + pub const Sp: Regs = Regs::R1; } #[cfg(feature = "python")] @@ -101,3 +104,42 @@ impl IntoPy for Regs { pub fn capstone() -> capstone::arch::ppc::ArchCapstoneBuilder { capstone::Capstone::new().ppc() } + +pub type GuestReg = u32; + +impl crate::ArchExtras for crate::CPU { + fn read_return_address(&self) -> Result + where + T: From, + { + self.read_reg(Regs::Lr) + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + self.write_reg(Regs::Lr, val) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + let val: GuestReg = val.into(); + match idx { + 0 => self.write_reg(Regs::R3, val), + 1 => self.write_reg(Regs::R4, val), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } +} diff --git a/libafl_qemu/src/snapshot.rs b/libafl_qemu/src/snapshot.rs index 530d1a10d7..deecf8775a 100644 --- a/libafl_qemu/src/snapshot.rs +++ b/libafl_qemu/src/snapshot.rs @@ -211,7 +211,7 @@ impl QemuSnapshotHelper { { let new_maps = self.new_maps.get_mut().unwrap(); - for acc in self.accesses.iter_mut() { + for acc in &mut self.accesses { unsafe { &mut (*acc.get()) }.dirty.retain(|page| { if let Some(info) = self.pages.get_mut(page) { // TODO avoid duplicated memcpy @@ -251,7 +251,7 @@ impl QemuSnapshotHelper { self.reset_maps(emulator); // This one is after that we remapped potential regions mapped at snapshot time but unmapped during execution - for acc in self.accesses.iter_mut() { + for acc in &mut self.accesses { for page in unsafe { &(*acc.get()).dirty } { for entry in self .maps diff --git a/libafl_qemu/src/x86_64.rs b/libafl_qemu/src/x86_64.rs index 3537b4fa60..f758cbe270 100644 --- a/libafl_qemu/src/x86_64.rs +++ b/libafl_qemu/src/x86_64.rs @@ -1,3 +1,5 @@ +use std::mem::size_of; + use capstone::arch::BuildsCapstone; use num_enum::{IntoPrimitive, TryFromPrimitive}; #[cfg(feature = "python")] @@ -5,6 +7,8 @@ use pyo3::prelude::*; pub use strum_macros::EnumIter; pub use syscall_numbers::x86_64::*; +use crate::CallingConvention; + #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)] #[repr(i32)] pub enum Regs { @@ -50,3 +54,49 @@ pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder { .x86() .mode(capstone::arch::x86::ArchMode::Mode64) } + +pub type GuestReg = u64; + +impl crate::ArchExtras for crate::CPU { + fn read_return_address(&self) -> Result + where + T: From, + { + let stack_ptr: GuestReg = self.read_reg(Regs::Rsp)?; + let mut ret_addr = [0; size_of::()]; + unsafe { self.read_mem(stack_ptr, &mut ret_addr) }; + Ok(GuestReg::from_le_bytes(ret_addr).into()) + } + + fn write_return_address(&self, val: T) -> Result<(), String> + where + T: Into, + { + let stack_ptr: GuestReg = self.read_reg(Regs::Rsp)?; + let val: GuestReg = val.into(); + let ret_addr = val.to_le_bytes(); + unsafe { self.write_mem(stack_ptr, &ret_addr) }; + Ok(()) + } + + fn write_function_argument( + &self, + conv: CallingConvention, + idx: i32, + val: T, + ) -> Result<(), String> + where + T: Into, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + let val: GuestReg = val.into(); + match idx { + 0 => self.write_reg(Regs::Rdi, val), + 1 => self.write_reg(Regs::Rsi, val), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } +} diff --git a/libafl_targets/src/sancov_8bit.rs b/libafl_targets/src/sancov_8bit.rs index 1a745bcb96..937879807b 100644 --- a/libafl_targets/src/sancov_8bit.rs +++ b/libafl_targets/src/sancov_8bit.rs @@ -165,7 +165,7 @@ mod observers { let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); for map in unsafe { &COUNTERS_MAPS } { let slice = map.as_slice(); - let ptr = slice.as_ptr() as *const u8; + let ptr = slice.as_ptr(); let map_size = slice.len() / core::mem::size_of::(); unsafe { hasher.write(from_raw_parts(ptr, map_size)); diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index 41a4e48964..aa18211309 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -22,11 +22,11 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) { { #[cfg(feature = "sancov_pcguard_edges")] { - (EDGES_MAP_PTR as *mut u8).add(pos).write(1); + EDGES_MAP_PTR.add(pos).write(1); } #[cfg(feature = "sancov_pcguard_hitcounts")] { - let addr = (EDGES_MAP_PTR as *mut u8).add(pos); + let addr = EDGES_MAP_PTR.add(pos); let val = addr.read().wrapping_add(1); addr.write(val); } diff --git a/utils/gramatron/construct_automata/src/main.rs b/utils/gramatron/construct_automata/src/main.rs index ff0c7d2df2..7a74067845 100644 --- a/utils/gramatron/construct_automata/src/main.rs +++ b/utils/gramatron/construct_automata/src/main.rs @@ -208,7 +208,7 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton { //let mut culled_pda_unique = HashSet::new(); for final_state in &finals { - for transition in pda.iter() { + for transition in pda { if transition.dest == *final_state && transition.stack.len() > 0 { blocklist.insert(transition.dest); } else { @@ -267,7 +267,7 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton { } } else { // Running FSA construction in exact approximation mode and postprocessing it like so - for transition in pda.iter() { + for transition in pda { num_transition += 1; let state = transition.source; if state >= memoized.len() {