blob: 76b2424b506a87a56df85f14f26b321bc13c2df1 [file] [view]
# Getting started with fuzzing in Chromium
This document explains how to add fuzz tests to Chromium using [FuzzTest].
If you need to maintain an existing libFuzzer target, see
[Getting Started with libFuzzer]. libFuzzer is deprecated for new fuzz targets.
[TOC]
## What to fuzz
You should fuzz any function that takes input from an untrusted source, such as
the internet. If the code parses, decodes, or otherwise manipulates that input,
you should write a fuzz test for it.
To view directories that currently lack fuzz coverage, see
[go/chrome-fuzzing-dashboard].
## Write the FuzzTest code
We recommend writing your fuzz tests in the same file as your standard unit tests.
Open your existing unit test file and include the FuzzTest header:
```c++
#include "third_party/fuzztest/src/fuzztest/fuzztest.h"`
```
Create a function with assertions that verify the expected behavior. For example:
```c++
void MyApiCanSuccessfullyParseAnyString(std::string input) {
bool success = MyApi(input);
EXPECT_TRUE(success);
}
```
In the same file, declare the `FUZZ_TEST` macro directly below your function:
```c++
FUZZ_TEST(MyApiTest, MyApiCanSuccessfullyParseAnyString);
```
The fuzzing infrastructure mutates the input based on code coverage to explore
branches within your API. Because generating all possible strings requires
infinite time, the fuzzer crafts inputs designed to maximize code coverage and
find bugs efficiently.
Fuzz tests do not replace traditional unit tests. Use fuzzing as a supplementary
testing strategy to help prevent unexpected security flaws.
For complex cases, specify the expected domains of valid input. For example:
```c++
void MyApiAlwaysSucceedsOnPositiveIntegers(int i) {
bool success = MyApi(i);
EXPECT_TRUE(success);
}
FUZZ_TEST(MyApiTest, MyApiAlwaysSucceedsOnPositiveIntegers)
.WithDomains(/*i:*/fuzztest::Positive<int>());
```
For more information about configuring input domains, see the
[FuzzTest Domain Reference].
## Configure the GN build target
Now that your test is written, add it to your existing unit test target. Open
your `BUILD.gn` file, locate your existing `test` target, and add the
`fuzztests` list containing the name of your new test.
```gn
import("//testing/test.gni")
test("my_component_unittests") {
sources = [
"my_component_unittest.cc", # Your FUZZ_TEST macros are in this file.
]
# Add your FuzzTest names here:
fuzztests = [ "MyApiTest.MyApiCanSuccessfullyParseAnyString" ]
deps = [
":my_component",
# Chromium unit tests usually already include this dependency.
# It provides the standard test main() that initializes FuzzTest.
"//base/test:test_support",
]
}
```
Because Chromium's [`test` template] automatically injects FuzzTest dependencies
and initializes the framework, you do not need to add any specific FuzzTest
libraries to your `deps`.
## Update your DEPS file
If your component's directory enforces include rules, you must add
`+third_party/fuzztest` to your local DEPS file so that your C++ files can
successfully include the FuzzTest headers.
## Run the FuzzTest locally
In a local terminal, build and run your unit tests. If your platform supports
FuzzTest, the test runs for one second and produces the following output:
```shell
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from ScaleFuzz
[ RUN ] ApiTest.MyApiCanSuccessfullyParseAnyString
[ OK ] ApiTest.MyApiCanSuccessfullyParseAnyString (1000 ms)
[----------] 1 test from ScaleFuzz (1000 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (1000 ms total)
[ PASSED ] 1 test.
```
On unsupported platforms, the system ignores the test.
To perform continuous fuzzing with FuzzTest locally, add the following to your
gn arguments:
```gn
enable_fuzztest_fuzz=true
is_component_build=false
```
Run your unit test and append the `--fuzz=` argument. You can optionally specify
a target test name by using `--fuzz=TEST_NAME`. The command produces
the following output as it explores your code:
```shell
[*] Corpus size: 1 | Edges covered: 73 | Fuzzing time: 1.60482ms | Total runs: 1.00e+00 | Runs/secs: 623 | Max stack usage: 0
[*] Corpus size: 2 | Edges covered: 103 | Fuzzing time: 1.844ms | Total runs: 2.00e+00 | Runs/secs: 1084 | Max stack usage: 0
[*] Corpus size: 3 | Edges covered: 111 | Fuzzing time: 2.747931ms | Total runs: 3.00e+00 | Runs/secs: 1091 | Max stack usage: 0
[*] Corpus size: 4 | Edges covered: 135 | Fuzzing time: 2.92305ms | Total runs: 4.00e+00 | Runs/secs: 1368 | Max stack usage: 0
[*] Corpus size: 5 | Edges covered: 173 | Fuzzing time: 3.35237ms | Total runs: 5.00e+00 | Runs/secs: 1491 | Max stack usage: 0
[*] Corpus size: 6 | Edges covered: 178 | Fuzzing time: 4.15666ms | Total runs: 6.00e+00 | Runs/secs: 1443 | Max stack usage: 0
```
The **Edges covered** metric indicates the number of unique code blocks the
fuzzer explores. Over time, the fuzzer explores more blocks until it exhausts
new edges.
## Submit the Fuzztest
Submit your changelist by using standard Chromium contribution processes.
[ClusterFuzz] typically begins running your new fuzzer within two days. To view
the fuzzer, go to [ClusterFuzz Fuzzer Stats] and search for your test target's
name. FuzzTest targets typically use the `centipede_` or `libfuzzer_` prefix in
the dashboard.
Thanks very much for doing your part in making Chromium more secure!
## Get help with advanced cases
If FuzzTest and libFuzzer do not meet your requirements, you can explore
advanced options, such as uploading blackbox fuzzers to ClusterFuzz or running
external fuzzers that upload results to ClusterFuzz for triage. To discuss these
options, contact the fuzzing team at chrome-fuzzing-core@google.com.
[ClusterFuzz]: https://clusterfuzz.com/
[FuzzTest Domain Reference]: https://github.com/google/fuzztest/blob/main/doc/domains-reference.md
[ClusterFuzz Fuzzer Stats]: https://clusterfuzz.com/fuzzer-stats/by-fuzzer/fuzzer/libFuzzer/job/libfuzzer_chrome_asan
[fuzzer builders]: https://ci.chromium.org/p/chromium/g/chromium.fuzz/console
[FuzzTest]: https://github.com/google/fuzztest
[Getting Started with libFuzzer]: getting_started_with_libfuzzer.md
[go/chrome-fuzzing-dashboard]: (https://analysis.chromium.org/coverage/p/chromium?platform=fuzz).
[`test` template]: https://source.chromium.org/chromium/chromium/src/+/main:testing/test.gni?q=test.gni