Add initial honggfuzz fuzzing infrastructure

This initially includes fuzzers for the AVB and boot image parsers. The
initial input corpus are the same test files we use for the round trip
tests.

Issue: #160

Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
This commit is contained in:
Andrew Gunnerson
2023-09-27 17:19:04 -04:00
parent 11d19de0a1
commit 5b22d7b603
18 changed files with 179 additions and 1 deletions
+4
View File
@@ -0,0 +1,4 @@
/hfuzz_target/
HONGGFUZZ.REPORT.TXT
*.honggfuzz.cov
*.fuzz
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "fuzz"
version.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# There's currently no good way to exclude a workspace member for a specific
# platform, so we just compile empty stubs on Windows (which isn't supported by
# honggfuzz).
# https://github.com/rust-lang/cargo/issues/5220
# https://github.com/rust-lang/cargo/issues/6179
[target.'cfg(unix)'.dependencies]
avbroot = { path = "../avbroot" }
honggfuzz = "0.5.55"
+53
View File
@@ -0,0 +1,53 @@
# Fuzzing
While avbroot's parsers are all memory-safe, it is still possible for panics or crashes to occur, for example due to excessive memory allocation, integer overflow, or division by zero. Fuzzing helps to identify these issues by randomizing inputs in a way that tries to increase code coverage.
## Running the fuzzers
1. Install the cargo honggfuzz commands.
```bash
cargo install honggfuzz
```
2. Pick a fuzz target to run. A fuzz target is the name of the source file in [`src/bin/`](./src/bin) without the `.rs` extension.
The list of targets can be queried programmatically with:
```bash
cargo read-manifest | jq -r '.targets[].name'
```
3. Run the fuzzer.
```bash
cargo hfuzz run <fuzz target>
```
This will run forever until it is manually killed. At the top of the screen, a summary section like the following is shown:
```
Iterations : 31,243 [31.24k]
Mode [1/3] : Feedback Driven Dry Run [2486/4085]
Target : hfuzz_target/x86_64-unknown-linux-gnu/release/bootimage
Threads : 8, CPUs: 16, CPU%: 800% [50%/CPU]
Speed : 36,126/sec [avg: 31,243]
Crashes : 53 [unique: 1, blocklist: 0, verified: 0]
Timeouts : 0 [1 sec]
Corpus Size : 1,424, max: 24,576 bytes, init: 4,085 files
Cov Update : 0 days 00 hrs 00 mins 00 secs ago
Coverage : edge: 897/224,621 [0%] pc: 2 cmp: 34,736
```
When a crash occurs, the `Crashes` counter will increment and the input data that triggered the crash will be written to `hfuzz_workspace/<fuzz target>/*.fuzz`. New files are only written for unique crashes.
4. If a crash occurs, run the following command to trigger the crash in a debugger.
```bash
cargo hfuzz run-debug <fuzz target> \
hfuzz_workspace/<fuzz_target>/<input file>.fuzz
```
This defaults to using `rust-lldb`. To use `rust-gdb` instead, set the `HFUZZ_DEBUGGER` environment variable to `rust-gdb`.
Alternatively, just feed the input file to the appropriate avbroot command directly (eg. `avbroot boot info -i hfuzz_workspace/<fuzz_target>/<input file>.fuzz` for boot images).
@@ -0,0 +1 @@
../../../../avbroot/tests/data/vbmeta_appended_hash.img
@@ -0,0 +1 @@
../../../../avbroot/tests/data/vbmeta_appended_hash_tree.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/vbmeta_root.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/boot_v0.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/boot_v1.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/boot_v2.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/boot_v3.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/boot_v4.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/boot_v4_vts.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/vendor_v3.img
+1
View File
@@ -0,0 +1 @@
../../../../avbroot/tests/data/vendor_v4.img
+21
View File
@@ -0,0 +1,21 @@
#[cfg(not(windows))]
mod fuzz {
use std::io::Cursor;
use avbroot::format::avb;
use honggfuzz::fuzz;
pub fn main() {
loop {
fuzz!(|data: &[u8]| {
let reader = Cursor::new(data);
let _ = avb::load_image(reader);
});
}
}
}
fn main() {
#[cfg(not(windows))]
fuzz::main();
}
+21
View File
@@ -0,0 +1,21 @@
#[cfg(not(windows))]
mod fuzz {
use std::io::Cursor;
use avbroot::{format::bootimage::BootImage, stream::FromReader};
use honggfuzz::fuzz;
pub fn main() {
loop {
fuzz!(|data: &[u8]| {
let reader = Cursor::new(data);
let _ = BootImage::from_reader(reader);
});
}
}
}
fn main() {
#[cfg(not(windows))]
fuzz::main();
}