Fix libafl_unicorn CI (#2991)

* fix: clippy

* fix: allow specifying thumb mode or not

* fix: timeout for testcase
This commit is contained in:
henri2h 2025-02-17 10:45:07 +01:00 committed by GitHub
parent 53004f93d6
commit 9a2a42ccca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 62 additions and 54 deletions

View File

@ -27,7 +27,7 @@ test_single arch="arm":
#!/bin/bash #!/bin/bash
echo "Testing {{arch}}" echo "Testing {{arch}}"
RUST_LOG="debug" timeout 10s {{FUZZER}} {{arch}} 2>&1 | tee fuzz_stdout.log || true RUST_LOG="debug" timeout 30s {{FUZZER}} {{arch}} 2>&1 | tee fuzz_stdout.log || true
if grep -qa "objectives: 1" fuzz_stdout.log; then if grep -qa "objectives: 1" fuzz_stdout.log; then
echo "Fuzzer is working" echo "Fuzzer is working"
else else

View File

@ -26,14 +26,17 @@ use libafl_bolts::{
}; };
use libafl_targets::EDGES_MAP_DEFAULT_SIZE; use libafl_targets::EDGES_MAP_DEFAULT_SIZE;
pub use libafl_targets::EDGES_MAP_PTR; pub use libafl_targets::EDGES_MAP_PTR;
#[cfg(feature = "code_hook")]
use libafl_unicorn::helper::get_stack_pointer;
use libafl_unicorn::{ use libafl_unicorn::{
emu::{debug_print, memory_dump}, emu::{debug_print, memory_dump},
helper::get_stack_pointer,
hooks::set_coverage_hook, hooks::set_coverage_hook,
}; };
#[cfg(feature = "mem_hook")]
use unicorn_engine::{unicorn_const::MemType, HookType};
use unicorn_engine::{ use unicorn_engine::{
unicorn_const::{Arch, MemType, SECOND_SCALE}, unicorn_const::{Arch, SECOND_SCALE},
HookType, Mode, Permission, RegisterARM, RegisterARM64, RegisterX86, Unicorn, Mode, Permission, RegisterARM, RegisterARM64, RegisterX86, Unicorn,
}; };
pub const CODE_ADDRESS: u64 = 0x9000; pub const CODE_ADDRESS: u64 = 0x9000;
@ -223,7 +226,7 @@ fn fuzzer(should_emulate: bool, arch: Arch) {
log::error!("Error: {:?}", err); log::error!("Error: {:?}", err);
memory_dump(&emu, 2); memory_dump(&emu, 2);
debug_print(&emu); debug_print(&emu, true);
} }
} }
@ -323,6 +326,7 @@ fn unicorn_map_and_load_code(emu: &mut Unicorn<()>, address: u64, size: usize, p
buffer.len() as u64 buffer.len() as u64
} }
#[cfg(feature = "code_hook")]
fn add_code_hook(emu: &mut Unicorn<()>) { fn add_code_hook(emu: &mut Unicorn<()>) {
emu.add_code_hook(0x0, !0x0_u64, |emu, pc, _| { emu.add_code_hook(0x0, !0x0_u64, |emu, pc, _| {
let sp = get_stack_pointer(emu); let sp = get_stack_pointer(emu);
@ -330,6 +334,8 @@ fn add_code_hook(emu: &mut Unicorn<()>) {
}) })
.unwrap(); .unwrap();
} }
#[cfg(feature = "mem_hook")]
fn mem_callback( fn mem_callback(
emu: &mut unicorn_engine::Unicorn<()>, emu: &mut unicorn_engine::Unicorn<()>,
mem: MemType, mem: MemType,

View File

@ -461,7 +461,7 @@ where
if self.stdout_file.is_some() || self.stderr_file.is_some() { if self.stdout_file.is_some() || self.stderr_file.is_some() {
stdout = Stdio::inherit(); stdout = Stdio::inherit();
stderr = Stdio::inherit(); stderr = Stdio::inherit();
}; }
} }
std::thread::sleep(Duration::from_millis( std::thread::sleep(Duration::from_millis(

View File

@ -33,7 +33,9 @@ pub fn memory_dump(emu: &Unicorn<()>, len: u64) {
} }
} }
pub fn debug_print(emu: &Unicorn<()>) { // Display some register values and disassemble the instructions around the program counter
// address. The thumb_mode parameter is only taken into account when the architecture used is ARM.
pub fn debug_print(emu: &Unicorn<()>, thumb_mode: bool) {
log::debug!("Status when crash happened:"); log::debug!("Status when crash happened:");
let pc = emu.pc_read().unwrap(); let pc = emu.pc_read().unwrap();
@ -68,54 +70,55 @@ pub fn debug_print(emu: &Unicorn<()>) {
// Provide disassembly at instant of crash // Provide disassembly at instant of crash
let regions = emu.mem_regions().expect("Could not get memory regions"); let regions = emu.mem_regions().expect("Could not get memory regions");
for i in 0..regions.len() { for region in regions {
if regions[i].perms.contains(Permission::EXEC) { if region.perms.contains(Permission::EXEC) && pc >= region.begin && pc <= region.end {
if pc >= regions[i].begin && pc <= regions[i].end { let mut begin = pc - 32;
let mut begin = pc - 32; let mut end = pc + 32;
let mut end = pc + 32; if begin < region.begin {
if begin < regions[i].begin { begin = region.begin;
begin = regions[i].begin; }
} if end > region.end {
if end > regions[i].end { end = region.end;
end = regions[i].end; }
}
let bytes = emu let bytes = emu
.mem_read_as_vec(begin, (end - begin) as usize) .mem_read_as_vec(begin, (end - begin) as usize)
.expect("Could not get program code"); .expect("Could not get program code");
let cs = match emu.get_arch() { let cs = match emu.get_arch() {
Arch::ARM => Capstone::new() Arch::ARM => Capstone::new()
.arm() .arm()
.mode(arch::arm::ArchMode::Thumb) .mode(match thumb_mode {
.detail(true) true => arch::arm::ArchMode::Thumb,
.build() false => arch::arm::ArchMode::Arm,
.expect("Failed to create Capstone object"), })
Arch::ARM64 => Capstone::new() .detail(true)
.arm64() .build()
.mode(arch::arm64::ArchMode::Arm) .expect("Failed to create Capstone object"),
.detail(true) Arch::ARM64 => Capstone::new()
.build() .arm64()
.expect("Failed to create Capstone object"), .mode(arch::arm64::ArchMode::Arm)
.detail(true)
.build()
.expect("Failed to create Capstone object"),
_ => Capstone::new() _ => Capstone::new()
.x86() .x86()
.mode(arch::x86::ArchMode::Mode64) .mode(arch::x86::ArchMode::Mode64)
.syntax(arch::x86::ArchSyntax::Intel) .syntax(arch::x86::ArchSyntax::Intel)
.detail(true) .detail(true)
.build() .build()
.expect("Failed to create Capstone object"), .expect("Failed to create Capstone object"),
}; };
let insns = cs.disasm_all(&bytes, begin).expect("Failed to disassemble"); let insns = cs.disasm_all(&bytes, begin).expect("Failed to disassemble");
if !insns.is_empty() { if !insns.is_empty() {
log::debug!("Code dump: [0x{begin:x} -> 0x{end:x}]"); log::debug!("Code dump: [0x{begin:x} -> 0x{end:x}]");
} else { } else {
log::debug!("No disassembly available at PC: 0x{pc:x}"); log::debug!("No disassembly available at PC: 0x{pc:x}");
} }
for i in insns.as_ref() { for i in insns.as_ref() {
log::debug!("{}", i); log::debug!("{}", i);
}
} }
} }
} }

View File

@ -1,11 +1,10 @@
use unicorn_engine::{unicorn_const::Arch, RegisterARM, RegisterARM64, RegisterX86}; use unicorn_engine::{unicorn_const::Arch, RegisterARM, RegisterARM64, RegisterX86};
pub fn get_stack_pointer(emu: &unicorn_engine::Unicorn<()>) -> u64 { pub fn get_stack_pointer(emu: &unicorn_engine::Unicorn<()>) -> u64 {
let sp = match emu.get_arch() { match emu.get_arch() {
Arch::ARM => emu.reg_read(RegisterARM::SP).unwrap(), Arch::ARM => emu.reg_read(RegisterARM::SP).unwrap(),
Arch::ARM64 => emu.reg_read(RegisterARM64::SP).unwrap(), Arch::ARM64 => emu.reg_read(RegisterARM64::SP).unwrap(),
Arch::X86 => emu.reg_read(RegisterX86::ESP).unwrap(), Arch::X86 => emu.reg_read(RegisterX86::ESP).unwrap(),
_ => 0, _ => 0,
}; }
sp
} }