1--- 2layout: default 3title: Integrating a Rust project 4parent: Setting up a new project 5grand_parent: Getting started 6nav_order: 2 7permalink: /getting-started/new-project-guide/rust-lang/ 8--- 9 10# Integrating a Rust project 11{: .no_toc} 12 13- TOC 14{:toc} 15--- 16 17The process of integrating a project written in Rust with OSS-Fuzz is very 18similar to the general [Setting up a new project]({{ site.baseurl 19}}/getting-started/new-project-guide/) process. The key specifics of integrating 20a Rust project are outlined below. 21 22## cargo-fuzz support 23 24Rust integration with OSS-Fuzz is expected to use [`cargo 25fuzz`](https://github.com/rust-fuzz/cargo-fuzz) to build fuzzers. The `cargo 26fuzz` tool will build code with required compiler flags as well as link to the 27correct libFuzzer on OSS-Fuzz itself. Note that using `cargo fuzz` also makes it 28quite easy to run the fuzzers locally yourself if you get a failing test case! 29 30## Project files 31 32First you'll want to follow the [setup instructions for `cargo fuzz` 33itself](https://rust-fuzz.github.io/book/). Afterwards your project should have: 34 35* A top-level `fuzz` directory. 36* A `fuzz/Cargo.toml` manifest which pulls in necessary dependencies to fuzz. 37* Some `fuzz/fuzz_targets/*.rs` files which are the fuzz targets that will be 38 compiled and run on OSS-Fuzz. 39 40Note that you can customize this layout as well, but you'll need to edit some 41the scripts below to integrate into OSS-Fuzz. 42 43### project.yaml 44 45The `language` attribute must be specified. 46 47```yaml 48language: rust 49``` 50 51The only supported fuzzing engine and sanitizer are `libfuzzer` and `address`, 52respectively. 53[Example](https://github.com/google/oss-fuzz/blob/12ef3654b3e9adfd20b5a6afdde54819ba71493d/projects/serde_json/project.yaml#L3-L6) 54 55```yaml 56sanitizers: 57 - address 58fuzzing_engines: 59 - libfuzzer 60``` 61 62### Dockerfile 63 64The Dockerfile should start by `FROM gcr.io/oss-fuzz-base/base-builder-rust` 65 66The OSS-Fuzz builder image has the latest nightly release of Rust as well as 67`cargo fuzz` pre-installed and in `PATH`. In the `Dockerfile` for your project 68all you'll need to do is fetch the latest copy of your code and install any 69system dependencies necessary to build your project. 70[Example](https://github.com/google/oss-fuzz/blob/12ef3654b3e9adfd20b5a6afdde54819ba71493d/projects/serde_json/Dockerfile#L18-L20) 71 72```dockerfile 73RUN git clone --depth 1 https://github.com/serde-rs/json json 74``` 75 76### build.sh 77 78Here it's expected that you'll build the fuzz targets for your project and then 79copy the final binaries into the output directory. 80[Example](https://github.com/google/oss-fuzz/blob/12ef3654b3e9adfd20b5a6afdde54819ba71493d/projects/serde_json/build.sh#L20): 81 82```sh 83cd $SRC/json 84cargo fuzz build -O 85cp fuzz/target/x86_64-unknown-linux-gnu/release/from_slice $OUT/ 86``` 87 88Note that you likely want to pass the `-O` flag to `cargo fuzz build` which 89builds fuzzers in release mode. You may also want to pass the 90`--debug-assertions` flag to enable more checks while fuzzing. In this example 91the `from_slice` binary is the fuzz target. 92 93With some bash-fu you can also automatically copy over all fuzz targets into 94the output directory so when you add a fuzz target to your project it's 95automatically integrated into OSS-Fuzz: 96 97```sh 98FUZZ_TARGET_OUTPUT_DIR=target/x86_64-unknown-linux-gnu/release 99for f in fuzz/fuzz_targets/*.rs 100do 101 FUZZ_TARGET_NAME=$(basename ${f%.*}) 102 cp $FUZZ_TARGET_OUTPUT_DIR/$FUZZ_TARGET_NAME $OUT/ 103done 104``` 105 106## Writing fuzzers using a test-style strategy 107 108In Rust you will often have tests written in a way so they are only 109compiled into the final binary when build in test-mode. This is, achieved by 110wrapping your test code in `cfg(test)`, e.g. 111```rust 112#[cfg(test)] 113mod tests { 114 use super::*; 115 116 ... 117``` 118 119Cargo-fuzz automatically enables the `fuzzing` feature, which means you can 120follow a similar strategy to writing fuzzers as you do when writing tests. 121Specifically, you can create modules wrapped in the `fuzzing` feature: 122```rust 123#[cfg(fuzzing)] 124pub mod fuzz_logic { 125 use super::*; 126 127 ... 128``` 129and then call the logic within `fuzz_logic` from your fuzzer. 130 131Furthermore, within your `.toml` files, you can then specify fuzzing-specific 132depedencies by wrapping them as follows: 133``` 134[target.'cfg(fuzzing)'.dependencies] 135``` 136similar to how you wrap test-dependencies as follows: 137``` 138[dev-dependencies] 139``` 140 141Finally, you can also combine the testing logic you have and the fuzz logic. This 142can be achieved simply by using 143```rust 144#[cfg(any(test, fuzzing))] 145``` 146 147A project that follows this structure is Linkerd2-proxy and the project files can be 148seen [here](https://github.com/google/oss-fuzz/tree/master/projects/linkerd2-proxy). 149