Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fuzzing infrastructure #512

Merged
merged 9 commits into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,63 @@ jobs:
$(find ./target/debug -type f -perm -100 | grep gimli | head -n 1) \
> /dev/null

build_fuzz_targets:
name: Build fuzz targets
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install rustup
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal
- name: Install nightly rust
run: |
rustup install nightly
rustup default nightly
- name: Install `cargo fuzz`
run: cargo install cargo-fuzz --vers "^0.7.4"
- run: cargo fuzz build -Oa
- uses: actions/upload-artifact@v2
with:
name: fuzz-targets
path: fuzz/target/x86_64-unknown-linux-gnu/release/debug_*
- uses: actions/upload-artifact@v2
with:
name: fuzz-targets
path: fuzz/target/x86_64-unknown-linux-gnu/release/eh_*

run_fuzz_targets:
strategy:
matrix:
fuzz_target: ["debug_abbrev", "debug_aranges", "debug_info", "debug_line", "eh_frame", "eh_frame_hdr"]
name: "Run `${{matrix.fuzz_target}}` fuzz target"
needs: build_fuzz_targets
runs-on: ubuntu-latest
steps:
- name: Clone the fuzz corpora
uses: actions/checkout@v2
with:
repository: gimli-rs/gimli-libfuzzer-corpora
path: corpora
- name: Download fuzz targets
uses: actions/download-artifact@v1
with:
name: fuzz-targets
# Note: -max_total_time=300 == 300 seconds == 5 minutes.
- name: "Run `${{matrix.fuzz_target}}` fuzz target"
run: |
mkdir ${{matrix.fuzz_target}}_artifacts
chmod +x ./fuzz-targets/${{matrix.fuzz_target}}
./fuzz-targets/${{matrix.fuzz_target}} ./corpora/${{matrix.fuzz_target}} \
-max_total_time=300 \
-artifact_prefix=./${{matrix.fuzz_target}}_artifacts/
# If fuzzing finds a new crash/panic/etc, upload the input artifacts so we
# can debug them.
- name: Upload fuzz artifacts
if: failure()
uses: actions/upload-artifact@v2
with:
name: ${{matrix.fuzz_target}}_artifacts
path: ./${{matrix.fuzz_target}}_artifacts

features:
runs-on: ubuntu-latest
steps:
Expand Down
22 changes: 22 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ out to us in a GitHub issue, or ping `fitzgen` in `#rust` on `irc.mozilla.org`.
* [Testing `gimli`](#testing)
* [Test Coverage](#coverage)
* [Using `test-assembler`](#test-assembler)
* [Fuzzing](#fuzzing)
* [Benchmarking](#benchmarking)
* [Style](#style)

Expand Down Expand Up @@ -81,6 +82,27 @@ construct binary test data. It makes building complex test cases readable.

[Here is an example usage in `gimli`](https://github.com/gimli-rs/gimli/blob/156451f3fe6eeb2fa62b84b362c33fcb176e1171/src/loc.rs#L263)

### <a id="fuzzing"></a> Fuzzing

First, install `cargo fuzz`:

```
$ cargo install cargo-fuzz
```

Optionally, [set up the corpora for our fuzz targets by following these
instructions](https://github.com/gimli-rs/gimli-libfuzzer-corpora/blob/master/README.md#using-these-corpora).

Finally, run a fuzz target! In this case, we are running the `eh_frame` fuzz
target:

```
$ cargo fuzz run eh_frame
```

The fuzz target definitions live in `fuzz/fuzz_targets/*`. You can add new ones
via `cargo fuzz add <my_new_target>`.

## <a id="benchmarking"></a> Benchmarking

The benchmarks require nightly `rustc`, so use `rustup`:
Expand Down
Binary file added fixtures/self/eh_frame_hdr
Binary file not shown.
4 changes: 4 additions & 0 deletions fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

target
corpus
artifacts
44 changes: 44 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

[package]
name = "gimli-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2018"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.3"

[dependencies.gimli]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "debug_info"
path = "fuzz_targets/debug_info.rs"

[[bin]]
name = "debug_abbrev"
path = "fuzz_targets/debug_abbrev.rs"

[[bin]]
name = "debug_line"
path = "fuzz_targets/debug_line.rs"

[[bin]]
name = "eh_frame"
path = "fuzz_targets/eh_frame.rs"

[[bin]]
name = "debug_aranges"
path = "fuzz_targets/debug_aranges.rs"

[[bin]]
name = "eh_frame_hdr"
path = "fuzz_targets/eh_frame_hdr.rs"
16 changes: 16 additions & 0 deletions fuzz/fuzz_targets/debug_abbrev.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![no_main]

use gimli::{read::DebugAbbrev, DebugAbbrevOffset, LittleEndian};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|debug_abbrev: &[u8]| {
let len = debug_abbrev.len();
let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);

let offset = DebugAbbrevOffset(0);
if let Ok(abbreviations) = debug_abbrev.abbreviations(offset) {
for i in 1..len {
let _ = abbreviations.get(i as u64);
}
}
});
12 changes: 12 additions & 0 deletions fuzz/fuzz_targets/debug_aranges.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![no_main]

use gimli::{read::DebugAranges, LittleEndian};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|debug_aranges: &[u8]| {
let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian);
let mut items = debug_aranges.items();
while let Ok(Some(_entry)) = items.next() {
continue;
}
});
26 changes: 26 additions & 0 deletions fuzz/fuzz_targets/debug_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![no_main]

use gimli::{
read::{DebugAbbrev, DebugInfo},
LittleEndian,
};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|sections: (Vec<u8>, Vec<u8>)| {
let (debug_abbrev, debug_info) = sections;
let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
let debug_info = DebugInfo::new(&debug_info, LittleEndian);

let mut units = debug_info.units();
while let Ok(Some(unit)) = units.next() {
if let Ok(abbrevs) = unit.abbreviations(&debug_abbrev) {
let mut cursor = unit.entries(&abbrevs);
while let Ok(Some((_delta, entry))) = cursor.next_dfs() {
let mut attrs = entry.attrs();
while let Ok(Some(_attr)) = attrs.next() {
continue;
}
}
}
}
});
17 changes: 17 additions & 0 deletions fuzz/fuzz_targets/debug_line.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![no_main]

use gimli::{read::DebugLine, DebugLineOffset, LittleEndian};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|debug_line: &[u8]| {
let debug_line = DebugLine::new(&debug_line, LittleEndian);

let offset = DebugLineOffset(0);
let address_size = 8;
if let Ok(program) = debug_line.program(offset, address_size, None, None) {
let mut rows = program.rows();
while let Ok(Some(row)) = rows.next_row() {
let _ = row;
}
}
});
34 changes: 34 additions & 0 deletions fuzz/fuzz_targets/eh_frame.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#![no_main]

use gimli::{
read::{BaseAddresses, CieOrFde, EhFrame, UninitializedUnwindContext, UnwindSection},
LittleEndian,
};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|eh_frame: &[u8]| {
let eh_frame = EhFrame::new(&eh_frame, LittleEndian);

let mut ctx = UninitializedUnwindContext::new();
let bases = BaseAddresses::default()
.set_eh_frame(0)
.set_eh_frame_hdr(0)
.set_text(0)
.set_got(0);

let mut entries = eh_frame.entries(&bases);
while let Ok(Some(entry)) = entries.next() {
match entry {
CieOrFde::Cie(_) => continue,
CieOrFde::Fde(partial) => {
if let Ok(fde) = partial.parse(EhFrame::cie_from_offset) {
if let Ok(mut table) = fde.rows(&eh_frame, &bases, &mut ctx) {
while let Ok(Some(_row)) = table.next_row() {
continue;
}
}
}
}
};
}
});
15 changes: 15 additions & 0 deletions fuzz/fuzz_targets/eh_frame_hdr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![no_main]

use gimli::{read::EhFrameHdr, BaseAddresses, LittleEndian};
use libfuzzer_sys::fuzz_target;

fuzz_target!(|eh_frame_hdr: &[u8]| {
let eh_frame_hdr = EhFrameHdr::new(eh_frame_hdr, LittleEndian);
let bases = BaseAddresses::default()
.set_eh_frame(0)
.set_eh_frame_hdr(0)
.set_text(0)
.set_got(0);
let address_size = 8;
let _ = eh_frame_hdr.parse(&bases, address_size);
});
21 changes: 21 additions & 0 deletions tests/parse_self.rs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -404,3 +404,24 @@ fn test_parse_self_eh_frame() {
}
}
}

#[test]
fn test_parse_self_eh_frame_hdr() {
use gimli::{BaseAddresses, EhFrameHdr};

let eh_frame_hdr = read_section("eh_frame_hdr");
let eh_frame_hdr = EhFrameHdr::new(&eh_frame_hdr, LittleEndian);

let bases = BaseAddresses::default()
.set_eh_frame(0)
.set_eh_frame_hdr(0)
.set_text(0)
.set_got(0);

// `.eh_frame_hdr` was generated on a 64 bit machine.
let address_size = 8;

let _parsed_header = eh_frame_hdr
.parse(&bases, address_size)
.expect("we can parse the `.eh_frame_hdr` section OK");
}