2020-06-12 19:13:05 +00:00
|
|
|
---
|
|
|
|
layout: default
|
|
|
|
title: Integrating a Rust project
|
|
|
|
parent: Setting up a new project
|
|
|
|
grand_parent: Getting started
|
|
|
|
nav_order: 2
|
|
|
|
permalink: /getting-started/new-project-guide/rust-lang/
|
|
|
|
---
|
|
|
|
|
|
|
|
# Integrating a Rust project
|
|
|
|
{: .no_toc}
|
|
|
|
|
|
|
|
- TOC
|
|
|
|
{:toc}
|
|
|
|
---
|
|
|
|
|
|
|
|
The process of integrating a project written in Rust with OSS-Fuzz is very
|
|
|
|
similar to the general [Setting up a new project]({{ site.baseurl
|
|
|
|
}}/getting-started/new-project-guide/) process. The key specifics of integrating
|
|
|
|
a Rust project are outlined below.
|
|
|
|
|
|
|
|
## cargo-fuzz support
|
|
|
|
|
|
|
|
Rust integration with OSS-Fuzz is expected to use [`cargo
|
|
|
|
fuzz`](https://github.com/rust-fuzz/cargo-fuzz) to build fuzzers. The `cargo
|
|
|
|
fuzz` tool will build code with required compiler flags as well as link to the
|
|
|
|
correct libFuzzer on OSS-Fuzz itself. Note that using `cargo fuzz` also makes it
|
|
|
|
quite easy to run the fuzzers locally yourself if you get a failing test case!
|
|
|
|
|
|
|
|
## Project files
|
|
|
|
|
|
|
|
First you'll want to follow the [setup instructions for `cargo fuzz`
|
|
|
|
itself](https://rust-fuzz.github.io/book/). Afterwards your project should have:
|
|
|
|
|
2020-06-22 15:05:20 +00:00
|
|
|
* A top-level `fuzz` directory.
|
|
|
|
* A `fuzz/Cargo.toml` manifest which pulls in necessary dependencies to fuzz.
|
2020-06-12 19:13:05 +00:00
|
|
|
* Some `fuzz/fuzz_targets/*.rs` files which are the fuzz targets that will be
|
|
|
|
compiled and run on OSS-Fuzz.
|
|
|
|
|
|
|
|
Note that you can customize this layout as well, but you'll need to edit some
|
|
|
|
the scripts below to integrate into OSS-Fuzz.
|
|
|
|
|
|
|
|
### project.yaml
|
|
|
|
|
|
|
|
The `language` attribute must be specified.
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
language: rust
|
|
|
|
```
|
|
|
|
|
|
|
|
The only supported fuzzing engine and sanitizer are `libfuzzer` and `address`,
|
|
|
|
respectively.
|
|
|
|
[Example](https://github.com/google/oss-fuzz/blob/12ef3654b3e9adfd20b5a6afdde54819ba71493d/projects/serde_json/project.yaml#L3-L6)
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
sanitizers:
|
|
|
|
- address
|
|
|
|
fuzzing_engines:
|
|
|
|
- libfuzzer
|
|
|
|
```
|
|
|
|
|
|
|
|
### Dockerfile
|
|
|
|
|
|
|
|
The OSS-Fuzz builder image has the latest nightly release of Rust as well as
|
|
|
|
`cargo fuzz` pre-installed and in `PATH`. In the `Dockerfile` for your project
|
|
|
|
all you'll need to do is fetch the latest copy of your code and install any
|
|
|
|
system dependencies necessary to build your project.
|
|
|
|
[Example](https://github.com/google/oss-fuzz/blob/12ef3654b3e9adfd20b5a6afdde54819ba71493d/projects/serde_json/Dockerfile#L18-L20)
|
|
|
|
|
|
|
|
```dockerfile
|
|
|
|
RUN git clone --depth 1 https://github.com/serde-rs/json json
|
|
|
|
```
|
|
|
|
|
|
|
|
### build.sh
|
|
|
|
|
|
|
|
Here it's expected that you'll build the fuzz targets for your project and then
|
|
|
|
copy the final binaries into the output directory.
|
|
|
|
[Example](https://github.com/google/oss-fuzz/blob/12ef3654b3e9adfd20b5a6afdde54819ba71493d/projects/serde_json/build.sh#L20):
|
|
|
|
|
|
|
|
```sh
|
|
|
|
cd $SRC/json
|
|
|
|
cargo fuzz build -O
|
|
|
|
cp fuzz/target/x86_64-unknown-linux-gnu/release/from_slice $OUT/
|
|
|
|
```
|
|
|
|
|
|
|
|
Note that you likely want to pass the `-O` flag to `cargo fuzz build` which
|
|
|
|
builds fuzzers in release mode. You may also want to pass the
|
|
|
|
`--debug-assertions` flag to enable more checks while fuzzing. In this example
|
|
|
|
the `from_slice` binary is the fuzz target.
|
|
|
|
|
|
|
|
With some bash-fu you can also automatically copy over all fuzz targets into
|
|
|
|
the output directory so when you add a fuzz target to your project it's
|
|
|
|
automatically integrated into OSS-Fuzz:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
FUZZ_TARGET_OUTPUT_DIR=target/x86_64-unknown-linux-gnu/release
|
|
|
|
for f in fuzz/fuzz_targets/*.rs
|
|
|
|
do
|
|
|
|
FUZZ_TARGET_NAME=$(basename ${f%.*})
|
|
|
|
cp $FUZZ_TARGET_OUTPUT_DIR/$FUZZ_TARGET_NAME $OUT/
|
|
|
|
done
|
|
|
|
```
|
2021-06-05 15:44:21 +00:00
|
|
|
|
|
|
|
## Writing fuzzers using a test-style strategy
|
|
|
|
|
|
|
|
In Rust you will often have tests written in a way so they are only
|
|
|
|
compiled into the final binary when build in test-mode. This is, achieved by
|
|
|
|
wrapping your test code in `cfg(test)`, e.g.
|
|
|
|
```rust
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
|
|
|
Cargo-fuzz automatically enables the `fuzzing` feature, which means you can
|
|
|
|
follow a similar strategy to writing fuzzers as you do when writing tests.
|
|
|
|
Specifically, you can create modules wrapped in the `fuzzing` feature:
|
|
|
|
```rust
|
|
|
|
#[cfg(fuzzing)]
|
|
|
|
pub mod fuzz_logic {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
...
|
|
|
|
```
|
|
|
|
and then call the logic within `fuzz_logic` from your fuzzer.
|
|
|
|
|
|
|
|
Furthermore, within your `.toml` files, you can then specify fuzzing-specific
|
|
|
|
depedencies by wrapping them as follows:
|
|
|
|
```
|
|
|
|
[target.'cfg(fuzzing)'.dependencies]
|
|
|
|
```
|
|
|
|
similar to how you wrap test-dependencies as follows:
|
|
|
|
```
|
|
|
|
[dev-dependencies]
|
|
|
|
```
|
|
|
|
|
|
|
|
Finally, you can also combine the testing logic you have and the fuzz logic. This
|
|
|
|
can be achieved simply by using
|
|
|
|
```rust
|
|
|
|
#[cfg(any(test, fuzzing))]
|
|
|
|
```
|
|
|
|
|
|
|
|
A project that follows this structure is Linkerd2-proxy and the project files can be
|
|
|
|
seen [here](https://github.com/google/oss-fuzz/tree/master/projects/linkerd2-proxy).
|