Add RISC-V support to libafl_unicorn (#3134)

This commit is contained in:
Daniel Hajjar 2025-04-07 16:18:10 +02:00 committed by GitHub
parent 8426ba5d58
commit ec24513c95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 41 additions and 7 deletions

View File

@ -12,7 +12,7 @@ runs:
with: { shared-key: "${{ runner.os }}-shared-fuzzer-cache" }
- name: Install fuzzers deps
shell: bash
run: sudo apt-get update && sudo apt-get install -y nasm nlohmann-json3-dev gcc-aarch64-linux-gnu g++-aarch64-linux-gnu gcc-mipsel-linux-gnu g++-mipsel-linux-gnu gcc-powerpc-linux-gnu g++-powerpc-linux-gnu libc6-dev-i386-cross libc6-dev libc6-dev-i386 lib32gcc-11-dev lib32stdc++-11-dev libgtk-3-dev pax-utils python3-msgpack python3-jinja2
run: sudo apt-get update && sudo apt-get install -y nasm nlohmann-json3-dev gcc-aarch64-linux-gnu g++-aarch64-linux-gnu gcc-mipsel-linux-gnu g++-mipsel-linux-gnu gcc-riscv64-linux-gnu gcc-powerpc-linux-gnu g++-powerpc-linux-gnu libc6-dev-i386-cross libc6-dev libc6-dev-i386 lib32gcc-11-dev lib32stdc++-11-dev libgtk-3-dev pax-utils python3-msgpack python3-jinja2
- name: enable mult-thread for `make`
shell: bash
run: export MAKEFLAGS="-j$(expr $(nproc) \+ 1)"

View File

@ -48,6 +48,7 @@ RUN apt-get update && \
gcc-i686-linux-gnu \
gcc-mipsel-linux-gnu \
gcc-powerpc-linux-gnu \
gcc-riscv64-linux-gnu \
gdb \
gdb-multiarch \
git \

View File

@ -20,7 +20,7 @@ build_bin:
[linux]
[macos]
test: fuzzer build_bin (test_single "arm") (test_single "arm64") (test_single "x86")
test: fuzzer build_bin (test_single "arm") (test_single "arm64") (test_single "riscv64") (test_single "x86")
echo "Done"
test_single arch="arm":

View File

@ -1,5 +1,6 @@
arm64 := "aarch64-linux-gnu"
arm := "arm-linux-gnueabihf"
riscv64 := "riscv64-linux-gnu"
x64 := "x86_64-linux-gnu"
assembly_arm64:
@ -16,6 +17,13 @@ binary_arm:
{{arm}}-as foo_arm.s -o foo_arm.elf
{{arm}}-objcopy -O binary foo_arm.elf foo_arm.bin
assembly_riscv64:
{{riscv64}}-gcc -O2 -S -c foo.c -o foo_riscv64.s
binary_riscv64:
{{riscv64}}-as foo_riscv64.s -o foo_riscv64.elf
{{riscv64}}-objcopy -O binary -j .text.startup foo_riscv64.elf foo_riscv64.bin
assembly_x86:
{{x64}}-gcc -O2 -S -c foo.c -o foo_x86.s
@ -26,11 +34,12 @@ binary_x86:
build_arm: assembly_arm binary_arm
build_arm64: assembly_arm64 binary_arm64
build_riscv64: assembly_riscv64 binary_riscv64
build_x86: assembly_x86 binary_x86
clean:
rm foo_*
all: build_arm build_arm64 build_x86
# sudo apt install gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu
all: build_arm build_arm64 build_riscv64 build_x86
# sudo apt install gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu

View File

@ -36,7 +36,7 @@ use libafl_unicorn::{
use unicorn_engine::{unicorn_const::MemType, HookType};
use unicorn_engine::{
unicorn_const::{Arch, SECOND_SCALE},
Mode, Permission, RegisterARM, RegisterARM64, RegisterX86, Unicorn,
Mode, Permission, RegisterARM, RegisterARM64, RegisterRISCV, RegisterX86, Unicorn,
};
pub const CODE_ADDRESS: u64 = 0x9000;
@ -64,6 +64,7 @@ fn main() {
let arch = match args[1].as_str() {
"arm" => Arch::ARM,
"arm64" => Arch::ARM64,
"riscv64" => Arch::RISCV,
"x86" => Arch::X86,
_ => {
panic!("This arcghitecture is not supported")
@ -86,6 +87,10 @@ pub fn init_registers(emu: &mut Unicorn<()>, sp: u64) {
emu.reg_write(RegisterARM64::SP, sp)
.expect("Could not setup register");
}
Arch::RISCV => {
emu.reg_write(RegisterRISCV::SP, sp)
.expect("Could not setup register");
}
Arch::X86 => {
emu.reg_write(RegisterX86::ESP, sp)
.expect("Could not setup register");
@ -99,6 +104,7 @@ fn fuzzer(should_emulate: bool, arch: Arch) {
let mode = match arch {
Arch::ARM => Mode::ARM,
Arch::ARM64 => Mode::ARM926,
Arch::RISCV => Mode::RISCV64,
Arch::X86 => Mode::MODE_64,
_ => Mode::MODE_64,
};
@ -112,6 +118,7 @@ fn fuzzer(should_emulate: bool, arch: Arch) {
match arch {
Arch::ARM => "bin/foo_arm.bin",
Arch::ARM64 => "bin/foo_arm64.bin",
Arch::RISCV => "bin/foo_riscv64.bin",
Arch::X86 => "bin/foo_x86.bin",
_ => "",
},
@ -191,6 +198,7 @@ fn fuzzer(should_emulate: bool, arch: Arch) {
match arch {
Arch::ARM => emu.reg_write(RegisterARM::LR, RETURN_ADDRESS).unwrap(),
Arch::ARM64 => emu.reg_write(RegisterARM64::LR, RETURN_ADDRESS).unwrap(),
Arch::RISCV => emu.reg_write(RegisterRISCV::RA, RETURN_ADDRESS).unwrap(),
Arch::X86 => {
let bytes = u64::to_le_bytes(RETURN_ADDRESS);
@ -213,6 +221,7 @@ fn fuzzer(should_emulate: bool, arch: Arch) {
let result_value = match arch {
Arch::ARM => emu.reg_read(RegisterARM::R0).unwrap(),
Arch::ARM64 => emu.reg_read(RegisterARM64::W0).unwrap(),
Arch::RISCV => emu.reg_read(RegisterRISCV::A0).unwrap(),
Arch::X86 => emu.reg_read(RegisterX86::EAX).unwrap(),
_ => 0,
};

View File

@ -4,7 +4,7 @@ use capstone::{
};
pub use libafl_targets::{EDGES_MAP, EDGES_MAP_PTR};
use unicorn_engine::{
RegisterARM, RegisterARM64, RegisterX86, Unicorn,
RegisterARM, RegisterARM64, RegisterRISCV, RegisterX86, Unicorn,
unicorn_const::{Arch, Permission},
};
@ -57,6 +57,14 @@ pub fn debug_print(emu: &Unicorn<()>, thumb_mode: bool) {
log::debug!("X2: {:X}", emu.reg_read(RegisterARM64::X2).unwrap());
log::debug!("X3: {:X}", emu.reg_read(RegisterARM64::X3).unwrap());
}
Arch::RISCV => {
log::debug!("SP: {:X}", emu.reg_read(RegisterRISCV::SP).unwrap());
log::debug!("RA: {:X}", emu.reg_read(RegisterRISCV::RA).unwrap());
log::debug!("GP: {:X}", emu.reg_read(RegisterRISCV::GP).unwrap());
log::debug!("TP: {:X}", emu.reg_read(RegisterRISCV::TP).unwrap());
log::debug!("A0: {:X}", emu.reg_read(RegisterRISCV::A0).unwrap());
log::debug!("A1: {:X}", emu.reg_read(RegisterRISCV::A1).unwrap());
}
Arch::X86 => {
log::debug!("ESP: {:X}", emu.reg_read(RegisterX86::ESP).unwrap());
log::debug!("RAX: {:X}", emu.reg_read(RegisterX86::RAX).unwrap());
@ -100,6 +108,12 @@ pub fn debug_print(emu: &Unicorn<()>, thumb_mode: bool) {
.detail(true)
.build()
.expect("Failed to create Capstone object"),
Arch::RISCV => Capstone::new()
.riscv()
.mode(arch::riscv::ArchMode::RiscV64)
.detail(true)
.build()
.expect("Failed to create Capstone object"),
_ => Capstone::new()
.x86()

View File

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