-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
By leveraging the LLVM's LibFuzzer, we will be able to test our emulator code more thoroughly. The seed corpus being added automatically are all the elf files in the build folder. Major changes: - Conditional compilation for the main function, as the fuzzer will generate its own main function - Need to use the clang toolchain - Introduce loading buffer as elf file, as the input from fuzzer will be passed into the emulator directly instead of going through a file - Fixed ELF verification logic as the fuzzer already breaks the code Other minor changes are: - Fix Codacy issue "rejecting SARIF, as there are more runs than allowed"
- Loading branch information
1 parent
2c096fb
commit c463882
Showing
12 changed files
with
277 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#!/usr/bin/env bash | ||
set -e -u -o pipefail | ||
|
||
# check the existence of the clang toolchain | ||
command -v clang &> /dev/null | ||
|
||
# compile | ||
make clean | ||
clang \ | ||
-g -O1 \ | ||
-fsanitize=fuzzer,address,undefined \ | ||
-include src/common.h \ | ||
-D RV32_FEATURE_EXT_F=0 \ | ||
-D RV32_FEATURE_SDL=0 \ | ||
-D DEFAULT_STACK_ADDR=0xFFFFE000 \ | ||
-D DEFAULT_ARGS_ADDR=0xFFFFF000 \ | ||
-D FUZZER \ | ||
-o build/rv32emu_fuzz \ | ||
src/fuzz-target.cc \ | ||
src/map.c \ | ||
src/utils.c \ | ||
src/decode.c \ | ||
src/io.c \ | ||
src/syscall.c \ | ||
src/emulate.c \ | ||
src/riscv.c \ | ||
src/elf.c \ | ||
src/cache.c \ | ||
src/mpool.c \ | ||
src/main.c | ||
|
||
# populate the initial CORPUS for the fuzzer using valid elf | ||
mkdir -p build/fuzz/CORPUS_DIR | ||
cp build/*.elf build/fuzz/CORPUS_DIR | ||
|
||
# execute | ||
./build/rv32emu_fuzz build/fuzz/CORPUS_DIR -timeout=3 -max_total_time=1200 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
exclude_paths: | ||
- ".github/**" | ||
- "build/**" | ||
- "docs/**" | ||
- "tests/**" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
name: Fuzz Test | ||
|
||
on: [push, pull_request] | ||
|
||
jobs: | ||
rv32emu: | ||
runs-on: ubuntu-22.04 | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: install-dependencies | ||
run: | | ||
sudo apt-get update | ||
sudo apt-get install clang | ||
shell: bash | ||
- name: Run fuzzer | ||
run: .ci/fuzz.sh | ||
shell: bash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Fuzzing | ||
|
||
We are using the [LLVM Fuzzer](https://llvm.org/docs/LibFuzzer.html). | ||
|
||
The fuzzer used here is without structured input generation. Instead, we rely | ||
on the fuzzer to mutate the input. | ||
|
||
The initial seeds are all the ELF files in the `build` directory. | ||
|
||
## Execution | ||
|
||
The script compiles the emulator and links it with the LibFuzzer, prepares the seed corpus, and executes the fuzzing tests. | ||
|
||
- `.ci/fuzz.sh` | ||
|
||
## References | ||
|
||
> Inspired by the fuzzer from [libriscv](/~https://github.com/fwsGonzo/libriscv/tree/master/fuzz). | ||
- [LLVM official LibFuzzer documentation](https://llvm.org/docs/LibFuzzer.html#corpus) | ||
- [Chromium - Getting started with LibFuzzer](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/testing/libfuzzer/getting_started_with_libfuzzer.md) | ||
- [Fuzzing tutorial](/~https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md) | ||
- [UBSAN](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include "riscv.h" | ||
|
||
const int max_cycles = 5000; | ||
const char *fake_rv32emu_name = "./fake_rv32emu"; | ||
const char *fake_elf_name = "fake_elf"; | ||
|
||
/* In order to be able to inspect a coredump we want to crash on every ASAN | ||
* error. | ||
*/ | ||
extern "C" void __asan_on_error() | ||
{ | ||
abort(); | ||
} | ||
extern "C" void __msan_on_error() | ||
{ | ||
abort(); | ||
} | ||
|
||
static void fuzz_elf_loader(const uint8_t *data, size_t len) | ||
{ | ||
int argc = 1 + 2 * 3 + 1; | ||
char **args = (char **) malloc(sizeof(char *) * argc); | ||
|
||
char *arg0 = (char *) malloc(strlen(fake_rv32emu_name) + 1); | ||
strncpy(arg0, fake_rv32emu_name, strlen(fake_rv32emu_name) + 1); | ||
args[0] = arg0; | ||
|
||
char *arg1 = (char *) malloc(3); | ||
strncpy(arg1, "-s", 3); | ||
args[1] = arg1; | ||
args[2] = (char *) data; | ||
|
||
char *arg3 = (char *) malloc(3); | ||
strncpy(arg3, "-l", 3); | ||
args[3] = arg3; | ||
char *len_str = (char *) malloc(20 + 1); /* LLONG_MIN in base 10 has 20 chars */ | ||
sprintf(len_str, "%zu", len); | ||
args[4] = len_str; | ||
|
||
char *arg5 = (char *) malloc(3); | ||
strncpy(arg5, "-k", 3); | ||
args[5] = arg5; | ||
char *max_cycles_str = | ||
(char *) malloc(11 + 1); /* INT_MIN in base 10 has 11 chars */ | ||
sprintf(max_cycles_str, "%d", max_cycles); | ||
args[6] = max_cycles_str; | ||
|
||
char *arg7 = (char *) malloc(strlen(fake_elf_name) + 1); | ||
strncpy(arg7, fake_elf_name, strlen(fake_elf_name) + 1); | ||
args[7] = arg7; | ||
|
||
int ret = rv_init_and_execute_elf(argc, args); | ||
if (ret == 0) { | ||
fprintf(stderr, "Executed successfully\n"); | ||
} else { | ||
fprintf(stderr, "Executed with failure\n"); | ||
} | ||
|
||
free(arg0); | ||
free(arg1); | ||
free(arg3); | ||
free(len_str); | ||
free(arg5); | ||
free(max_cycles_str); | ||
free(arg7); | ||
free(args); | ||
} | ||
|
||
extern "C" void LLVMFuzzerTestOneInput(const uint8_t *data, size_t len) | ||
{ | ||
fuzz_elf_loader(data, len); | ||
} |
Oops, something went wrong.