Modern fuzz testers are very effective and we wish to use them to ensure that no silly bugs creep into BoringSSL.
We primarily use Clang's libFuzzer 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.
In 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
CXX environment variables too, like this:
CC=clang CXX=clang++ cmake -GNinja -DFUZZ=1 ..
In 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 and do the following:
svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer clang++ -c -g -O2 -std=c++11 Fuzzer/*.cpp -IFuzzer ar ruv libFuzzer.a Fuzzer*.o
libFuzzer.a to the top-level of your BoringSSL source directory.
build/ directory, you can then run the fuzzers. For example:
./fuzz/cert -max_len=3072 -jobs=32 -workers=32 ../fuzz/cert_corpus/
The arguments to
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.
The recommended values of
max_len for each test may be found in
.options files alongside the test source. These were determined by rounding up the length of the largest case in the corpus. When writing a new fuzzer, configure
max_len in a similar file.
There 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.)
When 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.
In 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.
-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:
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.
Modify the TLS stack to perform all signature checks (CertificateVerify and ServerKeyExchange) and the Finished check, but always act as if the check succeeded.
Treat every cipher as the NULL cipher.
This is to prevent the fuzzer from getting stuck at a cryptographic invariant in the protocol.