blob: c541a2d8cb3d96fc13aed4b1e4c0eb2c8d7c2c18 [file] [log] [blame] [view]
Adam Langley9a4beb82015-11-09 13:57:26 -08001# Fuzz testing
2
3Modern fuzz testers are very effective and we wish to use them to ensure that no silly bugs creep into BoringSSL.
4
5We primarily use Clang's [libFuzzer](http://llvm.org/docs/LibFuzzer.html) for fuzz testing and there are a number of fuzz testing functions in `fuzz/`. They are not built by default because they require libFuzzer at build time.
6
Adam Langley7104cc92015-11-10 15:00:51 -08007In order to build the fuzz tests you will need at least Clang 3.7. Pass `-DFUZZ=1` on the CMake command line to enable building BoringSSL with coverage and AddressSanitizer, and to build the fuzz test binaries. You'll probably need to set the `CC` and `CXX` environment variables too, like this:
8
9```
10CC=clang CXX=clang++ cmake -GNinja -DFUZZ=1 ..
11```
12
13In order for the fuzz tests to link, the linker needs to find libFuzzer. This is not commonly provided and you may need to download the [Clang source code](http://llvm.org/releases/download.html) and do the following:
Adam Langley9a4beb82015-11-09 13:57:26 -080014
15```
David Benjamine11988f2016-03-21 15:55:19 -040016svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer
17clang++ -c -g -O2 -std=c++11 Fuzzer/*.cpp -IFuzzer
18ar ruv libFuzzer.a Fuzzer*.o
Adam Langley9a4beb82015-11-09 13:57:26 -080019```
20
Adam Langley7104cc92015-11-10 15:00:51 -080021Then copy `libFuzzer.a` to the top-level of your BoringSSL source directory.
22
Adam Langley9a4beb82015-11-09 13:57:26 -080023From the `build/` directory, you can then run the fuzzers. For example:
24
25```
David Benjamin9539ebb2016-03-21 18:24:53 -040026./fuzz/cert -max_len=3072 -jobs=32 -workers=32 ../fuzz/cert_corpus/
Adam Langley9a4beb82015-11-09 13:57:26 -080027```
28
David Benjamin9539ebb2016-03-21 18:24:53 -040029The arguments to `jobs` and `workers` should be the number of cores that you wish to dedicate to fuzzing. By default, libFuzzer uses the largest test in the corpus (or 64 if empty) as the maximum test case length. The `max_len` argument overrides this.
30
Max Moroz188487f2016-04-11 15:36:49 +020031The recommended values of `max_len` for each test are:
32
Adam Langleyd09175f2016-05-20 10:51:48 -070033| Test | `max_len` value |
34|------------|-----------------|
35| `cert` | 3072 |
36| `client` | 20000 |
37| `pkcs8` | 2048 |
38| `privkey` | 2048 |
39| `server` | 4096 |
40| `spki` | 1024 |
41| `read_pem` | 512 |
Max Moroz188487f2016-04-11 15:36:49 +020042
43These were determined by rounding up the length of the largest case in the corpus.
Adam Langley9a4beb82015-11-09 13:57:26 -080044
45There are directories in `fuzz/` for each of the fuzzing tests which contain seed files for fuzzing. Some of the seed files were generated manually but many of them are interesting results generated by the fuzzing itself. (Where interesting means that it triggered a previously unknown path in the code.)
Adam Langley7104cc92015-11-10 15:00:51 -080046
Adam Langleyddcc1862016-03-03 09:50:25 -080047## Minimising the corpuses
48
49When a large number of new seeds are available, it's a good idea to minimise the corpus so that different seeds that trigger the same code paths can be deduplicated.
50
51In order to minimise all the corpuses, build for fuzzing and run `./fuzz/minimise_corpuses.sh`. Note that minimisation is, oddly, often not idempotent for unknown reasons.
David Benjamine11988f2016-03-21 15:55:19 -040052
53## Fuzzer mode
54
55When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` defined. This modifies the library, particularly the TLS stack, to be more friendly to fuzzers. It will:
56
57* Replace `RAND_bytes` with a deterministic PRNG. Call `RAND_reset_for_fuzzing()` at the start of fuzzers which use `RAND_bytes` to reset the PRNG state.
58
59* Modify the TLS stack to perform all signature checks (CertificateVerify and ServerKeyExchange) and the Finished check, but always act as if the check succeeded.
60
61* Treat every cipher as the NULL cipher.
62
David Benjamin01a90572016-09-22 00:11:43 -040063* Use a hard-coded time instead of the actual time.
64
David Benjaminfbc45d72016-09-22 01:21:24 -040065* Tickets are unencrypted and the MAC check is performed but ignored.
66
David Benjamine11988f2016-03-21 15:55:19 -040067This is to prevent the fuzzer from getting stuck at a cryptographic invariant in the protocol.
David Benjamin1e663e82016-09-22 01:02:13 -040068
69## TLS transcripts
70
71The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. To run the tests against a fuzzer-mode `bssl_shim`, run:
72
73```
74cd ssl/test/runner
75go test -fuzzer -deterministic -shim-config fuzzer_mode.json
76```
77
78For a different build directory from `build/`, pass the appropriate `-shim-path` flag. If those tests pass, record a set of transcripts with:
79
80```
81go test -fuzzer -deterministic -transcript-dir /tmp/transcripts/
82```
83
84Note the suppressions file is ignored so disabled tests record transcripts too. Then merge into the existing corpora:
85
86```
87cd build/
88./fuzz/client -max_len=50000 -merge=1 ../fuzz/client_corpus /tmp/transcripts/tls/client
89./fuzz/server -max_len=50000 -merge=1 ../fuzz/server_corpus /tmp/transcripts/tls/server
90```