From ec24513c95901cfeacdda0016e8f4c70632c8672 Mon Sep 17 00:00:00 2001 From: Daniel Hajjar <33489389+DanTGL@users.noreply.github.com> Date: Mon, 7 Apr 2025 16:18:10 +0200 Subject: [PATCH] Add RISC-V support to libafl_unicorn (#3134) --- .../workflows/fuzzer-tester-prepare/action.yml | 2 +- Dockerfile | 1 + fuzzers/full_system/unicorn/Justfile | 2 +- fuzzers/full_system/unicorn/bin/Justfile | 13 +++++++++++-- fuzzers/full_system/unicorn/src/main.rs | 11 ++++++++++- libafl_unicorn/src/emu.rs | 16 +++++++++++++++- libafl_unicorn/src/helper.rs | 3 ++- 7 files changed, 41 insertions(+), 7 deletions(-) diff --git a/.github/workflows/fuzzer-tester-prepare/action.yml b/.github/workflows/fuzzer-tester-prepare/action.yml index 5653a8bdff..2e81026495 100644 --- a/.github/workflows/fuzzer-tester-prepare/action.yml +++ b/.github/workflows/fuzzer-tester-prepare/action.yml @@ -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)" diff --git a/Dockerfile b/Dockerfile index f7cae1ffd2..d546292668 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 \ diff --git a/fuzzers/full_system/unicorn/Justfile b/fuzzers/full_system/unicorn/Justfile index ebaea03392..3f37bb3dff 100644 --- a/fuzzers/full_system/unicorn/Justfile +++ b/fuzzers/full_system/unicorn/Justfile @@ -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": diff --git a/fuzzers/full_system/unicorn/bin/Justfile b/fuzzers/full_system/unicorn/bin/Justfile index 119661f145..5b0bdd5e4f 100644 --- a/fuzzers/full_system/unicorn/bin/Justfile +++ b/fuzzers/full_system/unicorn/bin/Justfile @@ -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 diff --git a/fuzzers/full_system/unicorn/src/main.rs b/fuzzers/full_system/unicorn/src/main.rs index 0f0294142e..9faff784d3 100644 --- a/fuzzers/full_system/unicorn/src/main.rs +++ b/fuzzers/full_system/unicorn/src/main.rs @@ -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, }; diff --git a/libafl_unicorn/src/emu.rs b/libafl_unicorn/src/emu.rs index f2e67f640b..2070e38059 100644 --- a/libafl_unicorn/src/emu.rs +++ b/libafl_unicorn/src/emu.rs @@ -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() diff --git a/libafl_unicorn/src/helper.rs b/libafl_unicorn/src/helper.rs index 45e8379778..f5ff5881d8 100644 --- a/libafl_unicorn/src/helper.rs +++ b/libafl_unicorn/src/helper.rs @@ -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, }