1*e0c4386eSCy SchubertFuzzing OpenSSL 2*e0c4386eSCy Schubert=============== 3*e0c4386eSCy Schubert 4*e0c4386eSCy SchubertOpenSSL can use either LibFuzzer or AFL to do fuzzing. 5*e0c4386eSCy Schubert 6*e0c4386eSCy SchubertLibFuzzer 7*e0c4386eSCy Schubert--------- 8*e0c4386eSCy Schubert 9*e0c4386eSCy SchubertHow to fuzz OpenSSL with [libfuzzer](http://llvm.org/docs/LibFuzzer.html), 10*e0c4386eSCy Schubertstarting from a vanilla+OpenSSH server Ubuntu install. 11*e0c4386eSCy Schubert 12*e0c4386eSCy SchubertWith `clang` from a package manager 13*e0c4386eSCy Schubert----------------------------------- 14*e0c4386eSCy Schubert 15*e0c4386eSCy SchubertInstall `clang`, which [ships with `libfuzzer`](http://llvm.org/docs/LibFuzzer.html#fuzzer-usage) 16*e0c4386eSCy Schubertsince version 6.0: 17*e0c4386eSCy Schubert 18*e0c4386eSCy Schubert sudo apt-get install clang 19*e0c4386eSCy Schubert 20*e0c4386eSCy SchubertConfigure `openssl` for fuzzing. For now, you'll still need to pass in the path 21*e0c4386eSCy Schubertto the `libFuzzer` library file while configuring; this is represented as 22*e0c4386eSCy Schubert`$PATH_TO_LIBFUZZER` below. A typical value would be 23*e0c4386eSCy Schubert`/usr/lib/llvm-7/lib/clang/7.0.1/lib/linux/libclang_rt.fuzzer-x86_64.a`. 24*e0c4386eSCy Schubert 25*e0c4386eSCy Schubert CC=clang ./config enable-fuzz-libfuzzer \ 26*e0c4386eSCy Schubert --with-fuzzer-lib=$PATH_TO_LIBFUZZER \ 27*e0c4386eSCy Schubert -DPEDANTIC enable-asan enable-ubsan no-shared \ 28*e0c4386eSCy Schubert -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION \ 29*e0c4386eSCy Schubert -fsanitize=fuzzer-no-link \ 30*e0c4386eSCy Schubert enable-ec_nistp_64_gcc_128 -fno-sanitize=alignment \ 31*e0c4386eSCy Schubert enable-weak-ssl-ciphers enable-rc5 enable-md2 \ 32*e0c4386eSCy Schubert enable-ssl3 enable-ssl3-method enable-nextprotoneg \ 33*e0c4386eSCy Schubert --debug 34*e0c4386eSCy Schubert 35*e0c4386eSCy SchubertCompile: 36*e0c4386eSCy Schubert 37*e0c4386eSCy Schubert sudo apt-get install make 38*e0c4386eSCy Schubert make clean 39*e0c4386eSCy Schubert LDCMD=clang++ make -j4 40*e0c4386eSCy Schubert 41*e0c4386eSCy SchubertFinally, perform the actual fuzzing: 42*e0c4386eSCy Schubert 43*e0c4386eSCy Schubert fuzz/helper.py $FUZZER 44*e0c4386eSCy Schubert 45*e0c4386eSCy Schubertwhere $FUZZER is one of the executables in `fuzz/`. 46*e0c4386eSCy SchubertIt will run until you stop it. 47*e0c4386eSCy Schubert 48*e0c4386eSCy SchubertIf you get a crash, you should find a corresponding input file in 49*e0c4386eSCy Schubert`fuzz/corpora/$FUZZER-crash/`. 50*e0c4386eSCy Schubert 51*e0c4386eSCy SchubertWith `clang` from source/pre-built binaries 52*e0c4386eSCy Schubert------------------------------------------- 53*e0c4386eSCy Schubert 54*e0c4386eSCy SchubertYou may also wish to use a pre-built binary from the [LLVM Download 55*e0c4386eSCy Schubertsite](http://releases.llvm.org/download.html), or to [build `clang` from 56*e0c4386eSCy Schubertsource](https://clang.llvm.org/get_started.html). After adding `clang` to your 57*e0c4386eSCy Schubertpath and locating the `libfuzzer` library file, the procedure for configuring 58*e0c4386eSCy Schubertfuzzing is the same, except that you also need to specify 59*e0c4386eSCy Schuberta `--with-fuzzer-include` option, which should be the parent directory of the 60*e0c4386eSCy Schubertprebuilt fuzzer library. This is represented as `$PATH_TO_LIBFUZZER_DIR` below. 61*e0c4386eSCy Schubert 62*e0c4386eSCy Schubert CC=clang ./config enable-fuzz-libfuzzer \ 63*e0c4386eSCy Schubert --with-fuzzer-include=$PATH_TO_LIBFUZZER_DIR \ 64*e0c4386eSCy Schubert --with-fuzzer-lib=$PATH_TO_LIBFUZZER \ 65*e0c4386eSCy Schubert -DPEDANTIC enable-asan enable-ubsan no-shared \ 66*e0c4386eSCy Schubert -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION \ 67*e0c4386eSCy Schubert -fsanitize=fuzzer-no-link \ 68*e0c4386eSCy Schubert enable-ec_nistp_64_gcc_128 -fno-sanitize=alignment \ 69*e0c4386eSCy Schubert enable-weak-ssl-ciphers enable-rc5 enable-md2 \ 70*e0c4386eSCy Schubert enable-ssl3 enable-ssl3-method enable-nextprotoneg \ 71*e0c4386eSCy Schubert --debug 72*e0c4386eSCy Schubert 73*e0c4386eSCy SchubertAFL 74*e0c4386eSCy Schubert--- 75*e0c4386eSCy Schubert 76*e0c4386eSCy SchubertThis is an alternative to using LibFuzzer. 77*e0c4386eSCy Schubert 78*e0c4386eSCy SchubertConfigure for fuzzing: 79*e0c4386eSCy Schubert 80*e0c4386eSCy Schubert sudo apt-get install afl-clang 81*e0c4386eSCy Schubert CC=afl-clang-fast ./config enable-fuzz-afl no-shared no-module \ 82*e0c4386eSCy Schubert -DPEDANTIC enable-tls1_3 enable-weak-ssl-ciphers enable-rc5 \ 83*e0c4386eSCy Schubert enable-md2 enable-ssl3 enable-ssl3-method enable-nextprotoneg \ 84*e0c4386eSCy Schubert enable-ec_nistp_64_gcc_128 -fno-sanitize=alignment \ 85*e0c4386eSCy Schubert --debug 86*e0c4386eSCy Schubert make clean 87*e0c4386eSCy Schubert make 88*e0c4386eSCy Schubert 89*e0c4386eSCy SchubertThe following options can also be enabled: enable-asan, enable-ubsan, enable-msan 90*e0c4386eSCy Schubert 91*e0c4386eSCy SchubertRun one of the fuzzers: 92*e0c4386eSCy Schubert 93*e0c4386eSCy Schubert afl-fuzz -i fuzz/corpora/$FUZZER -o fuzz/corpora/$FUZZER/out fuzz/$FUZZER 94*e0c4386eSCy Schubert 95*e0c4386eSCy SchubertWhere $FUZZER is one of the executables in `fuzz/`. 96*e0c4386eSCy Schubert 97*e0c4386eSCy SchubertReproducing issues 98*e0c4386eSCy Schubert------------------ 99*e0c4386eSCy Schubert 100*e0c4386eSCy SchubertIf a fuzzer generates a reproducible error, you can reproduce the problem using 101*e0c4386eSCy Schubertthe fuzz/*-test binaries and the file generated by the fuzzer. They binaries 102*e0c4386eSCy Schubertdon't need to be built for fuzzing, there is no need to set CC or the call 103*e0c4386eSCy Schubertconfig with enable-fuzz-* or -fsanitize-coverage, but some of the other options 104*e0c4386eSCy Schubertabove might be needed. For instance the enable-asan or enable-ubsan option might 105*e0c4386eSCy Schubertbe useful to show you when the problem happens. For the client and server fuzzer 106*e0c4386eSCy Schubertit might be needed to use -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION to 107*e0c4386eSCy Schubertreproduce the generated random numbers. 108*e0c4386eSCy Schubert 109*e0c4386eSCy SchubertTo reproduce the crash you can run: 110*e0c4386eSCy Schubert 111*e0c4386eSCy Schubert fuzz/$FUZZER-test $file 112*e0c4386eSCy Schubert 113*e0c4386eSCy SchubertTo do all the tests of a specific fuzzer such as asn1 you can run 114*e0c4386eSCy Schubert 115*e0c4386eSCy Schubert fuzz/asn1-test fuzz/corpora/asn1 116*e0c4386eSCy Schubertor 117*e0c4386eSCy Schubert make test TESTS=fuzz_test_asn1 118*e0c4386eSCy Schubert 119*e0c4386eSCy SchubertTo run several fuzz tests you can use for instance: 120*e0c4386eSCy Schubert 121*e0c4386eSCy Schubert make test TESTS='test_fuzz_cmp test_fuzz_cms' 122*e0c4386eSCy Schubert 123*e0c4386eSCy SchubertTo run all fuzz tests you can use: 124*e0c4386eSCy Schubert 125*e0c4386eSCy Schubert make test TESTS='test_fuzz_*' 126*e0c4386eSCy Schubert 127*e0c4386eSCy SchubertRandom numbers 128*e0c4386eSCy Schubert-------------- 129*e0c4386eSCy Schubert 130*e0c4386eSCy SchubertThe client and server fuzzer normally generate random numbers as part of the TLS 131*e0c4386eSCy Schubertconnection setup. This results in the coverage of the fuzzing corpus changing 132*e0c4386eSCy Schubertdepending on the random numbers. This also has an effect for coverage of the 133*e0c4386eSCy Schubertrest of the test suite and you see the coverage change for each commit even when 134*e0c4386eSCy Schubertno code has been modified. 135*e0c4386eSCy Schubert 136*e0c4386eSCy SchubertSince we want to maximize the coverage of the fuzzing corpus, the client and 137*e0c4386eSCy Schubertserver fuzzer will use predictable numbers instead of the random numbers. This 138*e0c4386eSCy Schubertis controlled by the FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION define. 139*e0c4386eSCy Schubert 140*e0c4386eSCy SchubertThe coverage depends on the way the numbers are generated. We don't disable any 141*e0c4386eSCy Schubertcheck of hashes, but the corpus has the correct hash in it for the random 142*e0c4386eSCy Schubertnumbers that were generated. For instance the client fuzzer will always generate 143*e0c4386eSCy Schubertthe same client hello with the same random number in it, and so the server, as 144*e0c4386eSCy Schubertemulated by the file, can be generated for that client hello. 145*e0c4386eSCy Schubert 146*e0c4386eSCy SchubertCoverage changes 147*e0c4386eSCy Schubert---------------- 148*e0c4386eSCy Schubert 149*e0c4386eSCy SchubertSince the corpus depends on the default behaviour of the client and the server, 150*e0c4386eSCy Schubertchanges in what they send by default will have an impact on the coverage. The 151*e0c4386eSCy Schubertcorpus will need to be updated in that case. 152*e0c4386eSCy Schubert 153*e0c4386eSCy SchubertUpdating the corpus 154*e0c4386eSCy Schubert------------------- 155*e0c4386eSCy Schubert 156*e0c4386eSCy SchubertThe client and server corpus is generated with multiple config options: 157*e0c4386eSCy Schubert 158*e0c4386eSCy Schubert- The options as documented above 159*e0c4386eSCy Schubert- Without enable-ec_nistp_64_gcc_128 and without --debug 160*e0c4386eSCy Schubert- With no-asm 161*e0c4386eSCy Schubert- Using 32 bit 162*e0c4386eSCy Schubert- A default config, plus options needed to generate the fuzzer. 163*e0c4386eSCy Schubert 164*e0c4386eSCy SchubertThe libfuzzer merge option is used to add the additional coverage 165*e0c4386eSCy Schubertfrom each config to the minimal set. 166*e0c4386eSCy Schubert 167*e0c4386eSCy SchubertMinimizing the corpus 168*e0c4386eSCy Schubert--------------------- 169*e0c4386eSCy Schubert 170*e0c4386eSCy SchubertWhen you have gathered corpus data from more than one fuzzer run 171*e0c4386eSCy Schubertor for any other reason want to minimize the data 172*e0c4386eSCy Schubertin some corpus subdirectory `fuzz/corpora/DIR` this can be done as follows: 173*e0c4386eSCy Schubert 174*e0c4386eSCy Schubert mkdir fuzz/corpora/NEWDIR 175*e0c4386eSCy Schubert fuzz/$FUZZER -merge=1 fuzz/corpora/NEWDIR fuzz/corpora/DIR 176