xref: /freebsd-src/crypto/openssl/fuzz/README.md (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
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