This document will walk you through:
Use use_libfuzzer
GN argument together with sanitizer to generate build files:
# 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[1] undefined behavior like integer overflow. |
Create a new .cc file and define a LLVMFuzzerTestOneInput
function:
#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 fuzzer_test
GN target:
import("//testing/libfuzzer/fuzzer_test.gni") fuzzer_test("my_fuzzer") { sources = [ "my_fuzzer.cc" ] deps = [ ... ] }
Build with ninja as usual and run:
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.
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.
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.
[1] By default UBSan doesn't crash once undefined behavior has been detected. To make it crash the following additional option should be provided:
UBSAN_OPTIONS=halt_on_error=1 ./fuzzer <corpus_directory_or_single_testcase_path>
Other useful options (used by ClusterFuzz) are:
UBSAN_OPTIONS=symbolize=1:halt_on_error=1:print_stacktrace=1 ./fuzzer <corpus_directory_or_single_testcase_path>