blob: cfe1ab25aa46f2a811c1c5f31da03e170d12dbd2 [file] [log] [blame] [view]
# Getting Started with libFuzzer in Chrome
*** note
**Prerequisites:** libFuzzer in Chrome is supported with GN on Linux only.
***
This document will walk you through:
* setting up your build enviroment.
* creating your first fuzzer.
* running the fuzzer and verifying its vitals.
## Configure Build
Use `use_libfuzzer` GN argument together with sanitizer to generate build files:
```bash
# With address sanitizer
gn gen out/libfuzzer '--args=use_libfuzzer=true is_asan=true enable_nacl=false' --check
```
Supported sanitizer configurations are:
| GN Argument | Description |
|--------------|----|
| is_asan=true | enables [Address Sanitizer] to catch problems like buffer overruns. |
| is_msan=true | enables [Memory Sanitizer] to catch problems like uninitialed reads. |
| is_ubsan_security=true | enables [Undefined Behavior Sanitizer] to catch<sup>\[[1](#Notes)\]</sup> undefined behavior like integer overflow. |
## Write Fuzzer Function
Create a new .cc file and define a `LLVMFuzzerTestOneInput` function:
```cpp
#include <stddef.h>
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// put your fuzzing code here and use data+size as input.
return 0;
}
```
[url_parse_fuzzer.cc] is a simple example of real-world fuzzer.
## Define GN Target
Define `fuzzer_test` GN target:
```
import("//testing/libfuzzer/fuzzer_test.gni")
fuzzer_test("my_fuzzer") {
sources = [ "my_fuzzer.cc" ]
deps = [ ... ]
}
```
## Build and Run Fuzzer Locally
Build with ninja as usual and run:
```bash
ninja -C out/libfuzzer url_parse_fuzzer
./out/libfuzzer/url_parse_fuzzer
```
Your fuzzer should produce output like this:
```
INFO: Seed: 1787335005
INFO: -max_len is not provided, using 64
INFO: PreferSmall: 1
#0 READ units: 1 exec/s: 0
#1 INITED cov: 2361 bits: 95 indir: 29 units: 1 exec/s: 0
#2 NEW cov: 2710 bits: 359 indir: 36 units: 2 exec/s: 0 L: 64 MS: 0
#3 NEW cov: 2715 bits: 371 indir: 37 units: 3 exec/s: 0 L: 64 MS: 1 ShuffleBytes-
#5 NEW cov: 2728 bits: 375 indir: 38 units: 4 exec/s: 0 L: 63 MS: 3 ShuffleBytes-ShuffleBytes-EraseByte-
#6 NEW cov: 2729 bits: 384 indir: 38 units: 5 exec/s: 0 L: 10 MS: 4 ShuffleBytes-ShuffleBytes-EraseByte-CrossOver-
#7 NEW cov: 2733 bits: 424 indir: 39 units: 6 exec/s: 0 L: 63 MS: 1 ShuffleBytes-
#8 NEW cov: 2733 bits: 426 indir: 39 units: 7 exec/s: 0 L: 63 MS: 2 ShuffleBytes-ChangeByte-
#11 NEW cov: 2733 bits: 447 indir: 39 units: 8 exec/s: 0 L: 33 MS: 5 ShuffleBytes-ChangeByte-ChangeASCIIInt-ChangeBit-CrossOver-
#12 NEW cov: 2733 bits: 451 indir: 39 units: 9 exec/s: 0 L: 62 MS: 1 CrossOver-
#16 NEW cov: 2733 bits: 454 indir: 39 units: 10 exec/s: 0 L: 61 MS: 5 CrossOver-ChangeBit-ChangeBit-EraseByte-ChangeBit-
#18 NEW cov: 2733 bits: 458 indir: 39 units: 11 exec/s: 0 L: 24 MS: 2 CrossOver-CrossOver-
```
The `... NEW ...` line appears when libFuzzer finds new and interesting input. The
efficient fuzzer should be able to finds lots of them rather quickly.
The `... pulse ...` line will appear periodically to show the current status.
### Default value for maximum testcase length
By default, when run manually, libFuzzer uses `-max_len=64` or takes the length
of the biggest testcase in corpus if corpus is not empty. ClusterFuzz takes
random value in range from `1` to `10000` for each fuzzing session and passes
that value to libFuzzers. If corpus contains testcases of size greater than
`max_len`, libFuzzer will use only first `max_len` bytes of such testcases.
You can specify custom `max_len` value to be used by ClusterFuzz. For more
information check out [Maximum Testcase Length] section of the [Efficient Fuzzer
Guide].
## Submitting Fuzzer to ClusterFuzz
ClusterFuzz builds and executes all `fuzzer_test` targets in the source tree.
The only thing you should do is to submit a fuzzer into Chrome.
## Next Steps
* After your fuzzer is submitted, you should check its [ClusterFuzz status] in
a day or two.
* Check the [Efficient Fuzzer Guide] to better understand your fuzzer
performance and for optimization hints.
## Notes
[1] By default UBSan doesn't crash once undefined behavior has been detected.
To make it crash the following additional option should be provided:
```bash
UBSAN_OPTIONS=halt_on_error=1 ./fuzzer <corpus_directory_or_single_testcase_path>
```
Other useful options (used by ClusterFuzz) are:
```bash
UBSAN_OPTIONS=symbolize=1:halt_on_error=1:print_stacktrace=1 ./fuzzer <corpus_directory_or_single_testcase_path>
```
[Address Sanitizer]: http://clang.llvm.org/docs/AddressSanitizer.html
[Memory Sanitizer]: http://clang.llvm.org/docs/MemorySanitizer.html
[Undefined Behavior Sanitizer]: http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
[ClusterFuzz status]: clusterfuzz.md#Status-Links
[crbug/598448]: https://bugs.chromium.org/p/chromium/issues/detail?id=598448
[Efficient Fuzzer Guide]: efficient_fuzzer.md
[Maximum Testcase Length]: efficient_fuzzer.md#Maximum-Testcase-Length
[url_parse_fuzzer.cc]: https://code.google.com/p/chromium/codesearch#chromium/src/testing/libfuzzer/fuzzers/url_parse_fuzzer.cc