# Linkerd2-proxy fuzz testing

The proxy is tested via fuzzing by way of [OSS-Fuzz](https://github.com/google/oss-fuzz) and we rely on [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz) as our underlying fuzzing engine. 

## Fuzz tests

### Folder structure

We place the fuzz tests into folders within the individual crates that the fuzz tests target. For example, we have a fuzz test that that target the crate `/linkerd/addr` and the code in `/linkerd/addr/src` and thus the fuzz test that targets this crate is put in `/linkerd/addr/fuzz`. The folder set up we use for each of the fuzz tests is automatically generated by `cargo fuzz init` (described [here](https://github.com/rust-fuzz/cargo-fuzz#cargo-fuzz-init)).


### Fuzz targets

The general idea behind the fuzz tests is to follow the testing set up of the rest of the proxy. As such, we both have fuzz tests that resemble small unit-test-like code pieces, as well as fuzz tests that resemble larger integration-test-like code pieces. 

#### Unit-test-like fuzzers

The code in `/linkerd/addr/fuzz/fuzz_targets/fuzz_target_1.rs` is an example of a unit-test-like fuzzer:

```rust
#![no_main]

#[cfg(fuzzing)]
use libfuzzer_sys::fuzz_target;

#[cfg(fuzzing)]
fuzz_target!(|data: &[u8]| {
    let _ = tracing_subscriber::fmt::try_init();
    if let Ok(s) = std::str::from_utf8(data) {
        tracing::info!(data = ?s, "running with input");
        linkerd_addr::fuzz_logic::fuzz_addr_1(s);
    }
});
```
`fuzz_target` is the entrypoint of the fuzzer and is what the underlying fuzzing engine cargo-fuzz will call with pseudo-random data in the `data` argument. The fuzzer further calls into code in the `linkerd2_addr` module, which is defined as follows:

```rust
#[cfg(fuzzing)]
pub mod fuzz_logic {
    use super::*;

    pub fn fuzz_addr_1(fuzz_data: &str) {
        if let Ok(addr) = Addr::from_str(fuzz_data) {
            addr.is_loopback();
            addr.to_http_authority();
            addr.is_loopback();
            addr.socket_addr();
        }

        if let Ok(name_addr) = NameAddr::from_str_and_port(fuzz_data, 1234) {
            name_addr.port();
            name_addr.as_http_authority();
        }
    }
}
```

We use this indirection of having fuzzing-related code in the modules themselves to align with the scoping of the proxy code. 

We wrap our fuzzing code in `[#cfg(fuzzing)]` to avoid shipping the fuzzing code when build the release binaries.

We compile and run the above fuzzer with the following commands:

```
# Build the fuzzer
cd linkerd/addr
cargo +nightly fuzz build

# Run fuzzer
./fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_target_1
```

This is also the sequence of commands to use for running the fuzzers locally.

#### Integration-test-like fuzzers

The larger fuzzers we keep follow a similar structural set up as to the unit-test-like fuzzers, but are essentially just more substantial in nature. The idea behind these fuzzers is to test end-to-end concepts more so than individual components of the proxy. 

The inbound fuzzer [here](/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs) is an example of this.
