blob: f34f460f30c1ede5c03569063d9933cbb2908048 [file] [log] [blame] [view]
Max Moroz0266b682019-07-29 17:30:301# Getting started with fuzzing in Chromium
aizatskya6f86292016-03-18 00:22:242
Adrian Taylor6a886ec62023-10-25 23:45:273This document walks through how to get started adding fuzz tests to Chromium.
4
5It guides you how to use our latest fuzzing technology, called [FuzzTest]. This
6replaces earlier technology called [libfuzzer]. See the section at the end
7for reasons why you might sometimes still want to use libfuzzer.
aizatskya6f86292016-03-18 00:22:248
Max Moroz0266b682019-07-29 17:30:309[TOC]
aizatskya6f86292016-03-18 00:22:2410
Adrian Taylor6a886ec62023-10-25 23:45:2711## What to fuzz
aizatskya6f86292016-03-18 00:22:2412
Adrian Taylor6a886ec62023-10-25 23:45:2713You should fuzz any function which takes input from any
14untrusted source, such as the internet. If the code parses, decodes, or
15otherwise manipulates that input, it definitely should be fuzzed!
aizatskya6f86292016-03-18 00:22:2416
Adrian Taylore3fbcd462024-02-27 11:18:2817To decide how best to fuzz it, you should decide which of these two situations
18best matches your input:
19
20* *Binary data*: the input is a single buffer of contiguous bytes, for example
21 an image or some binary format which your code decodes.
22* *Function arguments*: the input is multiple different chunks of data, for
23 example the arguments to a function.
24
25In the latter case, go ahead and read this guide - it will show you how to use
26our latest fuzzing technology, FuzzTest.
27
28If however your input more closely matches the former description - just a
29single binary blob of data - then instead use our older fuzzing technology
30[libfuzzer] - click that link for a separate getting started guide. (libfuzzer
31will work a little better in these cases because if the fuzzer finds a problem,
32the test case will exactly match the binary format.)
33
Adrian Taylor6a886ec62023-10-25 23:45:2734## How to fuzz
mmorozdb4e66a12016-11-04 22:14:2435
Adrian Taylor6a886ec62023-10-25 23:45:27361. Find your existing unit test target. Create a new similar target
37 alongside. (In the future, you'll be able to add them right into your
38 unit test code directly.)
Adrian Taylor82c71d02023-10-30 19:13:43392. Add a gn target definition a lot like a normal unit test, but with
Adrian Taylora20bc5a2024-01-29 23:22:2640 `fuzztests = [ list-of-fuzztests ]`. See below for details. Create a `.cc` file.
Adrian Taylor6a886ec62023-10-25 23:45:27413. In the unit tests code, `#include "third_party/fuzztest/src/fuzztest/fuzztest.h"`
424. Add a `FUZZ_TEST` macro, which might be as simple as `FUZZ_TEST(MyApiTest, ExistingFunctionWhichTakesUntrustedInput)`
43 (though you may wish to structure things differently, see below)
445. Run the unit tests and ensure they pass.
456. Land the CL.
Bo Majewski3bd1cb82023-06-13 05:30:1246
Adrian Taylor6a886ec62023-10-25 23:45:2747That's it!
Bo Majewski3bd1cb82023-06-13 05:30:1248
Adrian Taylor6a886ec62023-10-25 23:45:2749This fuzzer will be built automatically, using various [sanitizers], and run
50on our distributed fuzzing infrastructure [ClusterFuzz]. If it finds bugs,
51they'll be reported back to you.
Bo Majewski3bd1cb82023-06-13 05:30:1252
Adrian Taylor6a886ec62023-10-25 23:45:2753More detail in all the following sections.
54
Adrian Taylor82c71d02023-10-30 19:13:4355## Creating a new `FUZZ_TEST` target
Adrian Taylor6a886ec62023-10-25 23:45:2756
aizatskya6f86292016-03-18 00:22:2457```
Adrian Taylor598c72c2023-11-02 09:10:5458import("//testing/test.gni")
Adrian Taylor82c71d02023-10-30 19:13:4359
Adrian Taylor714aaa42024-03-11 13:32:1660test("hypothetical_fuzztests") {
61 sources = [ "hypothetical_fuzztests.cc" ]
aizatskya6f86292016-03-18 00:22:2462
Andrew Paseltinerb55d15f2024-03-12 15:00:1663 fuzztests = ["MyApiTest.MyApiCanSuccessfullyParseAnyString"]
Juan Jose Lopez Jaimezc43c7c12022-07-26 22:33:0564
Adrian Taylor714aaa42024-03-11 13:32:1665 deps = [
66 ":hypothetical_component",
67 "//third_party/fuzztest:fuzztest_gtest_main",
68 ]
Max Morozeae4cef2018-11-06 00:26:2869}
robert.bradford160c5982016-08-30 17:04:3070```
71
Hubert Chao839f32aa2024-01-18 19:37:0572You may also need to add `third_party/fuzztest` to your DEPS file.
73
Adrian Taylor82c71d02023-10-30 19:13:4374## Adding `FUZZ_TEST` support to a target
75
Adrian Taylorc96daf22024-12-06 14:47:2176We also support adding `FUZZ_TEST`s alongside existing
Adrian Taylora20bc5a2024-01-29 23:22:2677unit tests, even in the same .cc file.
Adrian Taylor82c71d02023-10-30 19:13:4378
79```
Adrian Taylor5294aad2024-04-18 12:25:3980test("existing_unit_tests") {
81 sources = [ "existing_unit_tests.cc" ] # add FUZZ_TESTs here
Adrian Taylor82c71d02023-10-30 19:13:4382
Adrian Taylor5294aad2024-04-18 12:25:3983 fuzztests = ["MyApiTest.ApiWorksAlways"]
84 # Add this!
Adrian Taylor82c71d02023-10-30 19:13:4385
Adrian Taylor5294aad2024-04-18 12:25:3986 deps = [
87 ":existing_component",
88 # Other stuff
89 ]
Adrian Taylor82c71d02023-10-30 19:13:4390}
91```
Max Moroz9b370752018-03-20 22:05:3292
Adrian Taylor6a886ec62023-10-25 23:45:2793This will:
94* add a dependency on the appropriate fuzztest libraries;
95* cause the target to be built on all our [fuzzer builders]
96* construct metadata so that [ClusterFuzz] knows how to run the resulting
97 binary.
Max Moroz9b370752018-03-20 22:05:3298
Adrian Taylor82c71d02023-10-30 19:13:4399This relies on something, somewhere, calling `base::LaunchUnitTests` within
100your executable to initialize FuzzTest. This should be the case already.
101
Adrian Taylorf4c96162023-10-30 09:25:41102(If you have other code targets, such as `source_set`s, contributing to your
103unit test target they may need to explicitly depend upon `//third_party/fuzztest`
104too.)
105
Adrian Taylor82c71d02023-10-30 19:13:43106*** note
Adrian Taylorc96daf22024-12-06 14:47:21107**Note:** This may not yet work reliably in `browser_test`s. We're working on
108it.
Adrian Taylor82c71d02023-10-30 19:13:43109***
110
Adrian Taylor6a886ec62023-10-25 23:45:27111## Adding `FUZZ_TEST`s in the code
Max Moroz9b370752018-03-20 22:05:32112
Adrian Taylor6a886ec62023-10-25 23:45:27113First, `#include "third_party/fuzztest/src/fuzztest/fuzztest.h"`.
Max Moroz9b370752018-03-20 22:05:32114
Adrian Taylor6a886ec62023-10-25 23:45:27115Then, it's normal to create a function named after the thing you're trying to
116prove, with assertions to prove it.
Max Moroz9b370752018-03-20 22:05:32117
Adrian Taylor6a886ec62023-10-25 23:45:27118For instance,
Max Moroz9b370752018-03-20 22:05:32119
120```
Adrian Taylor6a886ec62023-10-25 23:45:27121void MyApiCanSuccessfullyParseAnyString(std::string input) {
122 bool success = MyApi(input);
123 EXPECT_TRUE(success);
124}
125```
Max Moroz9b370752018-03-20 22:05:32126
Adrian Taylor6a886ec62023-10-25 23:45:27127Then, declare the `FUZZ_TEST` macro:
Max Moroz9b370752018-03-20 22:05:32128
Adrian Taylor6a886ec62023-10-25 23:45:27129```
130FUZZ_TEST(MyApiTest, MyApiCanSuccessfullyParseAnyString);
131```
132
133Our fuzzing infrastructure will generate all possible strings and prove it works.
134Obviously, that takes infinite time, so instead our fuzzing infrastructure will
135carefully craft strings to explore more and more branches within `MyApi`,
136mutating the input according to code coverage, so there's a good chance bugs
137will be found quickly.
138
139Fuzzing should always be alongside traditional unit testing - never rely on it
140to find all the bugs! It should be a backstop to prevent unexpected security
141flaws sneaking past your regular testing.
142
143In more complex cases, you'll need to tell FuzzTest about the expected domains
144of valid input. For example:
145
146```
147void MyApiAlwaysSucceedsOnPositiveIntegers(int i) {
148 bool success = MyApi(i);
149 EXPECT_TRUE(success);
150}
151FUZZ_TEST(MyApiTest, MyApiAlwaysSucceedsOnPositiveIntegers)
152 .WithDomains(/*i:*/fuzztest::Positive<int>());
153```
154
155See the [FuzzTest reference] for all your options here.
156
157## Running this locally
158
159Simply build and run your unit tests as normal. `FUZZ_TEST`s are supported only
160on some platforms. If you're on such a platform, you'll see your fuzz test
161run for one second:
162
163```
164[==========] Running 1 test from 1 test suite.
165[----------] Global test environment set-up.
166[----------] 1 test from ScaleFuzz
167[ RUN ] ApiTest.MyApiCanSuccessfullyParseAnyString
168[ OK ] ApiTest.MyApiCanSuccessfullyParseAnyString (1000 ms)
169[----------] 1 test from ScaleFuzz (1000 ms total)
170
171[----------] Global test environment tear-down
172[==========] 1 test from 1 test suite ran. (1000 ms total)
173[ PASSED ] 1 test.
174```
175
176On other platforms, the test will be ignored.
177
Hubert Chao839f32aa2024-01-18 19:37:05178If you want to try actually fuzzing with FuzzTest, modify your gn arguments to
179contain:
180
181```
182enable_fuzztest_fuzz=true
183is_component_build=false
184```
185
186You can then run your unit test with the extra command line argument `--fuzz=`,
187optionally specifying a test name. You'll see lots of output as it explores your
188code:
Adrian Taylor6a886ec62023-10-25 23:45:27189
190```
191[*] Corpus size: 1 | Edges covered: 73 | Fuzzing time: 1.60482ms | Total runs: 1.00e+00 | Runs/secs: 623 | Max stack usage: 0
192[*] Corpus size: 2 | Edges covered: 103 | Fuzzing time: 1.844ms | Total runs: 2.00e+00 | Runs/secs: 1084 | Max stack usage: 0
193[*] Corpus size: 3 | Edges covered: 111 | Fuzzing time: 2.747931ms | Total runs: 3.00e+00 | Runs/secs: 1091 | Max stack usage: 0
194[*] Corpus size: 4 | Edges covered: 135 | Fuzzing time: 2.92305ms | Total runs: 4.00e+00 | Runs/secs: 1368 | Max stack usage: 0
195[*] Corpus size: 5 | Edges covered: 173 | Fuzzing time: 3.35237ms | Total runs: 5.00e+00 | Runs/secs: 1491 | Max stack usage: 0
196[*] Corpus size: 6 | Edges covered: 178 | Fuzzing time: 4.15666ms | Total runs: 6.00e+00 | Runs/secs: 1443 | Max stack usage: 0
197```
198
199("Edges covered") is how many different code blocks have been explored (that is,
200sections between branches). Over time, you'll see it explore more and more until
201it runs out of new edges to explore.
202
203## Landing the CL
204
205Nothing special is required here!
206
207After a day or two, we should see [ClusterFuzz] starting to run your new fuzzer,
208and it should be visible on [ClusterFuzz Fuzzer Stats]. Look for fuzzers starting
Adrian Taylorc96daf22024-12-06 14:47:21209with `centipede_` or 'libfuzzer_' and your test target's name.
Adrian Taylor598c72c2023-11-02 09:10:54210
Adrian Taylor6a886ec62023-10-25 23:45:27211Thanks very much for doing your part in making Chromium more secure!
212
213## Unusual cases
214
215There are some situations where FuzzTests may not work. For example:
216
217* You need to run on platforms not currently supported by FuzzTest
218* You need more structured input
219* You need to mutate the input in a more precise way
Adrian Taylore3fbcd462024-02-27 11:18:28220* Your fuzzer input is a single binary blob
Adrian Taylor6a886ec62023-10-25 23:45:27221
222In these cases, you may be best off creating a standalone fuzzer using our
223older fuzzing technology, [libfuzzer]. There are further options beyond
224that, e.g. uploading "black box" fuzzers to ClusterFuzz, or even running
225fuzzers outside of ClusterFuzz which then upload results to ClusterFuzz
226for triage and diagnosis. To explore any of those options, please discuss
227with the fuzzing team (email [email protected] if you're outside Google).
228
229
230[FuzzTest]: https://github.com/google/fuzztest#how-do-i-use-it
231[libfuzzer]: getting_started_with_libfuzzer.md
232[`test` template]: https://source.chromium.org/chromium/chromium/src/+/main:testing/test.gni?q=test.gni
233[fuzzer builders]: https://ci.chromium.org/p/chromium/g/chromium.fuzz/console
234[ClusterFuzz]: https://clusterfuzz.com/
235[FuzzTest reference]: https://github.com/google/fuzztest#how-do-i-use-it
236[ClusterFuzz Fuzzer Stats]: https://clusterfuzz.com/fuzzer-stats/by-fuzzer/fuzzer/libFuzzer/job/libfuzzer_chrome_asan