| aizatsky | 9c8c5b0 | 2016-03-30 22:09:09 | [diff] [blame] | 1 | # Getting Started with libFuzzer in Chrome |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 2 | |
| 3 | *** note |
| mmoroz | 27ea9c2 | 2016-04-07 21:17:48 | [diff] [blame] | 4 | **Prerequisites:** libFuzzer in Chrome is supported with GN on Linux only. |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 5 | *** |
| 6 | |
| 7 | This document will walk you through: |
| 8 | |
| 9 | * setting up your build enviroment. |
| 10 | * creating your first fuzzer. |
| 11 | * running the fuzzer and verifying its vitals. |
| 12 | |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 13 | ## Configure Build |
| 14 | |
| 15 | Use `use_libfuzzer` GN argument together with sanitizer to generate build files: |
| 16 | |
| 17 | ```bash |
| 18 | # With address sanitizer |
| 19 | gn gen out/libfuzzer '--args=use_libfuzzer=true is_asan=true enable_nacl=false' --check |
| 20 | ``` |
| 21 | |
| 22 | Supported sanitizer configurations are: |
| 23 | |
| 24 | | GN Argument | Description | |
| 25 | |--------------|----| |
| aizatsky | 8f19edd | 2016-09-01 20:54:50 | [diff] [blame^] | 26 | | `is_asan=true` | enables [Address Sanitizer] to catch problems like buffer overruns. | |
| 27 | | `is_msan=true` | enables [Memory Sanitizer] to catch problems like uninitialed reads. | |
| 28 | | `is_ubsan_security=true` | enables [Undefined Behavior Sanitizer] to catch<sup>\[[1](#Notes)\]</sup> undefined behavior like integer overflow. | |
| 29 | | | it is possible to run libfuzzer without any sanitizers; *probably not what you want*.| |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 30 | |
| 31 | |
| 32 | ## Write Fuzzer Function |
| 33 | |
| 34 | Create a new .cc file and define a `LLVMFuzzerTestOneInput` function: |
| 35 | |
| 36 | ```cpp |
| reillyg | 21fe4450 | 2016-05-20 22:28:50 | [diff] [blame] | 37 | #include <stddef.h> |
| 38 | #include <stdint.h> |
| 39 | |
| 40 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 41 | // put your fuzzing code here and use data+size as input. |
| 42 | return 0; |
| 43 | } |
| 44 | ``` |
| 45 | |
| 46 | [url_parse_fuzzer.cc] is a simple example of real-world fuzzer. |
| 47 | |
| 48 | ## Define GN Target |
| 49 | |
| 50 | Define `fuzzer_test` GN target: |
| 51 | |
| 52 | ``` |
| 53 | import("//testing/libfuzzer/fuzzer_test.gni") |
| 54 | fuzzer_test("my_fuzzer") { |
| 55 | sources = [ "my_fuzzer.cc" ] |
| 56 | deps = [ ... ] |
| 57 | } |
| 58 | ``` |
| 59 | |
| 60 | ## Build and Run Fuzzer Locally |
| 61 | |
| 62 | Build with ninja as usual and run: |
| 63 | |
| 64 | ```bash |
| 65 | ninja -C out/libfuzzer url_parse_fuzzer |
| mmoroz | 27ea9c2 | 2016-04-07 21:17:48 | [diff] [blame] | 66 | ./out/libfuzzer/url_parse_fuzzer |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 67 | ``` |
| 68 | |
| 69 | Your fuzzer should produce output like this: |
| 70 | |
| 71 | ``` |
| 72 | INFO: Seed: 1787335005 |
| 73 | INFO: -max_len is not provided, using 64 |
| 74 | INFO: PreferSmall: 1 |
| 75 | #0 READ units: 1 exec/s: 0 |
| 76 | #1 INITED cov: 2361 bits: 95 indir: 29 units: 1 exec/s: 0 |
| 77 | #2 NEW cov: 2710 bits: 359 indir: 36 units: 2 exec/s: 0 L: 64 MS: 0 |
| 78 | #3 NEW cov: 2715 bits: 371 indir: 37 units: 3 exec/s: 0 L: 64 MS: 1 ShuffleBytes- |
| 79 | #5 NEW cov: 2728 bits: 375 indir: 38 units: 4 exec/s: 0 L: 63 MS: 3 ShuffleBytes-ShuffleBytes-EraseByte- |
| 80 | #6 NEW cov: 2729 bits: 384 indir: 38 units: 5 exec/s: 0 L: 10 MS: 4 ShuffleBytes-ShuffleBytes-EraseByte-CrossOver- |
| 81 | #7 NEW cov: 2733 bits: 424 indir: 39 units: 6 exec/s: 0 L: 63 MS: 1 ShuffleBytes- |
| 82 | #8 NEW cov: 2733 bits: 426 indir: 39 units: 7 exec/s: 0 L: 63 MS: 2 ShuffleBytes-ChangeByte- |
| 83 | #11 NEW cov: 2733 bits: 447 indir: 39 units: 8 exec/s: 0 L: 33 MS: 5 ShuffleBytes-ChangeByte-ChangeASCIIInt-ChangeBit-CrossOver- |
| 84 | #12 NEW cov: 2733 bits: 451 indir: 39 units: 9 exec/s: 0 L: 62 MS: 1 CrossOver- |
| 85 | #16 NEW cov: 2733 bits: 454 indir: 39 units: 10 exec/s: 0 L: 61 MS: 5 CrossOver-ChangeBit-ChangeBit-EraseByte-ChangeBit- |
| 86 | #18 NEW cov: 2733 bits: 458 indir: 39 units: 11 exec/s: 0 L: 24 MS: 2 CrossOver-CrossOver- |
| 87 | ``` |
| 88 | |
| aizatsky | 9c8c5b0 | 2016-03-30 22:09:09 | [diff] [blame] | 89 | The `... NEW ...` line appears when libFuzzer finds new and interesting input. The |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 90 | efficient fuzzer should be able to finds lots of them rather quickly. |
| 91 | |
| aizatsky | 9b70cf1b | 2016-03-18 19:33:50 | [diff] [blame] | 92 | The `... pulse ...` line will appear periodically to show the current status. |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 93 | |
| 94 | |
| mmoroz | 9e07559 | 2016-05-06 08:37:53 | [diff] [blame] | 95 | ### Default value for maximum testcase length |
| 96 | |
| 97 | By default, when run manually, libFuzzer uses `-max_len=64` or takes the length |
| 98 | of the biggest testcase in corpus if corpus is not empty. ClusterFuzz takes |
| 99 | random value in range from `1` to `10000` for each fuzzing session and passes |
| 100 | that value to libFuzzers. If corpus contains testcases of size greater than |
| 101 | `max_len`, libFuzzer will use only first `max_len` bytes of such testcases. |
| 102 | |
| 103 | |
| 104 | You can specify custom `max_len` value to be used by ClusterFuzz. For more |
| 105 | information check out [Maximum Testcase Length] section of the [Efficient Fuzzer |
| 106 | Guide]. |
| 107 | |
| robert.bradford | 160c598 | 2016-08-30 17:04:30 | [diff] [blame] | 108 | ## Disable noisy error message logging |
| 109 | |
| 110 | If the code that you are a fuzzing generates error messages when encountering |
| 111 | incorrect or invalid data then you need to silence those errors in the fuzzer. |
| 112 | |
| 113 | If the target uses the Chromium logging APIs, the best way to do that is to |
| 114 | override the environment used for logging in your fuzzer: |
| 115 | |
| 116 | ```cpp |
| 117 | struct Environment { |
| 118 | Environment() { |
| 119 | logging::SetMinLogLevel(logging::LOG_FATAL); |
| 120 | } |
| 121 | }; |
| 122 | |
| 123 | Environment* env = new Environment(); |
| 124 | ``` |
| 125 | |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 126 | ## Submitting Fuzzer to ClusterFuzz |
| 127 | |
| 128 | ClusterFuzz builds and executes all `fuzzer_test` targets in the source tree. |
| 129 | The only thing you should do is to submit a fuzzer into Chrome. |
| 130 | |
| 131 | ## Next Steps |
| 132 | |
| 133 | * After your fuzzer is submitted, you should check its [ClusterFuzz status] in |
| 134 | a day or two. |
| 135 | * Check the [Efficient Fuzzer Guide] to better understand your fuzzer |
| 136 | performance and for optimization hints. |
| 137 | |
| 138 | |
| mmoroz | 5a2604d4 | 2016-04-21 10:08:13 | [diff] [blame] | 139 | ## Notes |
| 140 | [1] By default UBSan doesn't crash once undefined behavior has been detected. |
| 141 | To make it crash the following additional option should be provided: |
| 142 | |
| 143 | ```bash |
| 144 | UBSAN_OPTIONS=halt_on_error=1 ./fuzzer <corpus_directory_or_single_testcase_path> |
| 145 | ``` |
| 146 | |
| 147 | Other useful options (used by ClusterFuzz) are: |
| 148 | ```bash |
| 149 | UBSAN_OPTIONS=symbolize=1:halt_on_error=1:print_stacktrace=1 ./fuzzer <corpus_directory_or_single_testcase_path> |
| 150 | ``` |
| 151 | |
| 152 | |
| aizatsky | a6f8629 | 2016-03-18 00:22:24 | [diff] [blame] | 153 | [Address Sanitizer]: http://clang.llvm.org/docs/AddressSanitizer.html |
| aizatsky | 62c7a84 | 2016-05-13 19:23:01 | [diff] [blame] | 154 | [Memory Sanitizer]: http://clang.llvm.org/docs/MemorySanitizer.html |
| 155 | [Undefined Behavior Sanitizer]: http://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html |
| mmoroz | 9e07559 | 2016-05-06 08:37:53 | [diff] [blame] | 156 | [ClusterFuzz status]: clusterfuzz.md#Status-Links |
| 157 | [crbug/598448]: https://bugs.chromium.org/p/chromium/issues/detail?id=598448 |
| 158 | [Efficient Fuzzer Guide]: efficient_fuzzer.md |
| 159 | [Maximum Testcase Length]: efficient_fuzzer.md#Maximum-Testcase-Length |
| aizatsky | 9c8c5b0 | 2016-03-30 22:09:09 | [diff] [blame] | 160 | [url_parse_fuzzer.cc]: https://code.google.com/p/chromium/codesearch#chromium/src/testing/libfuzzer/fuzzers/url_parse_fuzzer.cc |