LibAFL_QEMU: Don't return a generic Address from Register reads (#2681)

* LibAFL_QEMU: Make ReadReg always return GuestReg type

* Don't return a generic address

* fix fuzzers

* fix mips
This commit is contained in:
Dominik Maier 2024-11-12 22:14:35 -03:00 committed by GitHub
parent f3aa88b400
commit 0ef0684e43
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 74 additions and 94 deletions

View File

@ -196,7 +196,7 @@ fn fuzz(
}
}
println!("Break at {:#x}", qemu.read_reg::<_, u64>(Regs::Pc).unwrap());
println!("Break at {:#x}", qemu.read_reg(Regs::Pc).unwrap());
let stack_ptr: u64 = qemu.read_reg(Regs::Sp).unwrap();
let mut ret_addr = [0; 8];

View File

@ -194,7 +194,7 @@ fn fuzz(
}
}
println!("Break at {:#x}", qemu.read_reg::<_, u64>(Regs::Pc).unwrap());
println!("Break at {:#x}", qemu.read_reg(Regs::Pc).unwrap());
let stack_ptr: u64 = qemu.read_reg(Regs::Sp).unwrap();
let mut ret_addr = [0; 8];

View File

@ -91,10 +91,7 @@ pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder {
pub type GuestReg = u64;
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
self.read_reg(Regs::Lr)
}
@ -105,10 +102,11 @@ impl crate::ArchExtras for crate::CPU {
self.write_reg(Regs::Lr, val)
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
let reg_id = match idx {

View File

@ -88,10 +88,7 @@ pub fn capstone_thumb() -> capstone::arch::arm::ArchCapstoneBuilder {
pub type GuestReg = u32;
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
self.read_reg(Regs::Lr)
}
@ -102,10 +99,11 @@ impl crate::ArchExtras for crate::CPU {
self.write_reg(Regs::Lr, val)
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
let reg_id = match idx {

View File

@ -92,10 +92,7 @@ impl Regs {
pub type GuestReg = u32;
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
self.read_reg(Regs::Lr)
}
@ -106,10 +103,11 @@ impl crate::ArchExtras for crate::CPU {
self.write_reg(Regs::Lr, val)
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
// Note that 64 bit values may be passed in two registers (and may have padding), then this mapping is off.

View File

@ -67,10 +67,7 @@ pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder {
pub type GuestReg = u32;
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
let stack_ptr: GuestReg = self.read_reg(Regs::Esp)?;
let mut ret_addr = [0; size_of::<GuestReg>()];
unsafe { self.read_mem(stack_ptr, &mut ret_addr) };
@ -88,10 +85,11 @@ impl crate::ArchExtras for crate::CPU {
Ok(())
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
match idx {

View File

@ -88,10 +88,7 @@ pub fn capstone() -> capstone::arch::mips::ArchCapstoneBuilder {
pub type GuestReg = u32;
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
self.read_reg(Regs::Ra)
}
@ -102,10 +99,11 @@ impl crate::ArchExtras for crate::CPU {
self.write_reg(Regs::Ra, val)
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
let reg_id = match idx {

View File

@ -128,10 +128,7 @@ pub fn capstone() -> capstone::arch::ppc::ArchCapstoneBuilder {
pub type GuestReg = u32;
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
self.read_reg(Regs::Lr)
}
@ -142,10 +139,11 @@ impl crate::ArchExtras for crate::CPU {
self.write_reg(Regs::Lr, val)
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
let reg_id = match idx {

View File

@ -95,10 +95,7 @@ pub fn capstone() -> capstone::arch::riscv::ArchCapstoneBuilder {
}
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
self.read_reg(Regs::Ra)
}
@ -109,10 +106,11 @@ impl crate::ArchExtras for crate::CPU {
self.write_reg(Regs::Ra, val)
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
// Note that 64 bit values may be passed in two registers (and are even-odd eg. A0, A2 and A3 where A1 is empty), then this mapping is off.

View File

@ -78,14 +78,11 @@ pub type GuestReg = u64;
pub const PROCESS_ADDRESS_RANGE: Range<u64> = 0..0x0000_7fff_ffff_ffff;
impl crate::ArchExtras for crate::CPU {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
let stack_ptr: GuestReg = self.read_reg(Regs::Rsp)?;
let mut ret_addr = [0; size_of::<GuestReg>()];
unsafe { self.read_mem_unchecked(stack_ptr, &mut ret_addr) };
Ok(GuestReg::from_le_bytes(ret_addr).into())
Ok(GuestReg::from_le_bytes(ret_addr))
}
fn write_return_address<T>(&self, val: T) -> Result<(), QemuRWError>
@ -99,10 +96,11 @@ impl crate::ArchExtras for crate::CPU {
Ok(())
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
QemuRWError::check_conv(QemuRWErrorKind::Read, CallingConvention::Cdecl, conv)?;
let reg_id = match idx {

View File

@ -106,7 +106,7 @@ macro_rules! define_std_command_manager {
#[deny(unreachable_patterns)]
fn parse(&self, qemu: Qemu) -> Result<Self::Commands, CommandError> {
let arch_regs_map: &'static EnumMap<ExitArgs, Regs> = get_exit_arch_regs();
let cmd_id = qemu.read_reg::<Regs, GuestReg>(arch_regs_map[ExitArgs::Cmd])? as c_uint;
let cmd_id = qemu.read_reg(arch_regs_map[ExitArgs::Cmd])? as c_uint;
match cmd_id {
// <StartPhysCommandParser as NativeCommandParser<S>>::COMMAND_ID => Ok(StdCommandManagerCommands::StartPhysCommandParserCmd(<StartPhysCommandParser as NativeCommandParser<S>>::parse(qemu, arch_regs_map)?)),

View File

@ -52,7 +52,7 @@ where
qemu: Qemu,
arch_regs_map: &'static EnumMap<ExitArgs, Regs>,
) -> Result<Self::OutputCommand, CommandError> {
let input_phys_addr: GuestPhysAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?;
let input_phys_addr: GuestPhysAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?.into();
let max_input_size: GuestReg = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])?;
Ok(InputCommand::new(
@ -81,7 +81,7 @@ where
qemu: Qemu,
arch_regs_map: &'static EnumMap<ExitArgs, Regs>,
) -> Result<Self::OutputCommand, CommandError> {
let input_virt_addr: GuestVirtAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?;
let input_virt_addr: GuestVirtAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?.into();
let max_input_size: GuestReg = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])?;
Ok(InputCommand::new(
@ -109,7 +109,7 @@ where
qemu: Qemu,
arch_regs_map: &'static EnumMap<ExitArgs, Regs>,
) -> Result<Self::OutputCommand, CommandError> {
let input_phys_addr: GuestPhysAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?;
let input_phys_addr: GuestPhysAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?.into();
let max_input_size: GuestReg = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])?;
Ok(StartCommand::new(QemuMemoryChunk::phys(
@ -138,7 +138,7 @@ where
qemu: Qemu,
arch_regs_map: &'static EnumMap<ExitArgs, Regs>,
) -> Result<Self::OutputCommand, CommandError> {
let input_virt_addr: GuestVirtAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?;
let input_virt_addr: GuestVirtAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?.into();
let max_input_size: GuestReg = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])?;
Ok(StartCommand::new(QemuMemoryChunk::virt(
@ -237,7 +237,7 @@ where
qemu: Qemu,
arch_regs_map: &'static EnumMap<ExitArgs, Regs>,
) -> Result<Self::OutputCommand, CommandError> {
let client_version = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?;
let client_version = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?.into();
Ok(VersionCommand::new(client_version))
}
@ -283,7 +283,7 @@ where
) -> Result<Self::OutputCommand, CommandError> {
let buf_addr: GuestAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?;
let str_size: usize = qemu
.read_reg::<Regs, GuestAddr>(arch_regs_map[ExitArgs::Arg2])?
.read_reg(arch_regs_map[ExitArgs::Arg2])?
.try_into()
.unwrap(); // without null byte
let cpu = qemu.current_cpu().unwrap();

View File

@ -320,15 +320,15 @@ impl From<libafl_qemu_sys::MemOpIdx> for MemAccessInfo {
}
pub trait ArchExtras {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>;
fn read_return_address(&self) -> Result<GuestReg, QemuRWError>;
fn write_return_address<T>(&self, val: T) -> Result<(), QemuRWError>
where
T: Into<GuestReg>;
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>;
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError>;
fn write_function_argument<T>(
&self,
conv: CallingConvention,
@ -360,10 +360,9 @@ impl CPU {
unsafe { libafl_qemu_num_regs(self.ptr) }
}
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, QemuRWError>
pub fn read_reg<R>(&self, reg: R) -> Result<GuestReg, QemuRWError>
where
R: Into<i32> + Clone,
T: From<GuestReg>,
{
unsafe {
let reg_id = reg.clone().into();
@ -824,9 +823,8 @@ impl Qemu {
.write_reg(reg, val)
}
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, QemuRWError>
pub fn read_reg<R>(&self, reg: R) -> Result<GuestReg, QemuRWError>
where
T: Num + PartialOrd + Copy + From<GuestReg>,
R: Into<i32> + Clone,
{
self.current_cpu()
@ -907,17 +905,14 @@ impl Qemu {
}
impl ArchExtras for Qemu {
fn read_return_address<T>(&self) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_return_address(&self) -> Result<GuestReg, QemuRWError> {
self.current_cpu()
.ok_or(QemuRWError {
kind: QemuRWErrorKind::Read,
cause: QemuRWErrorCause::CurrentCpuNotFound,
cpu: None,
})?
.read_return_address::<T>()
.read_return_address()
}
fn write_return_address<T>(&self, val: T) -> Result<(), QemuRWError>
@ -929,13 +924,14 @@ impl ArchExtras for Qemu {
.write_return_address::<T>(val)
}
fn read_function_argument<T>(&self, conv: CallingConvention, idx: u8) -> Result<T, QemuRWError>
where
T: From<GuestReg>,
{
fn read_function_argument(
&self,
conv: CallingConvention,
idx: u8,
) -> Result<GuestReg, QemuRWError> {
self.current_cpu()
.ok_or(QemuRWError::current_cpu_not_found(QemuRWErrorKind::Read))?
.read_function_argument::<T>(conv, idx)
.read_function_argument(conv, idx)
}
fn write_function_argument<T>(