Skip to content

Commit

Permalink
Merge pull request #512 from fitzgen/fuzzing
Browse files Browse the repository at this point in the history
Add fuzzing infrastructure
  • Loading branch information
fitzgen authored May 20, 2020
2 parents 08f36f0 + b7d1a19 commit ea707d7
Show file tree
Hide file tree
Showing 12 changed files with 268 additions and 0 deletions.
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");
}

0 comments on commit ea707d7

Please sign in to comment.