[libFuzzer] remove large examples from the libFuzzer docs and link to the libFuzzer tutorial instead; also fix a build error in another file

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285337 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Kostya Serebryany 2016-10-27 20:14:03 +00:00
parent 245c383b96
commit f8e32dda35
2 changed files with 6 additions and 163 deletions

View File

@ -397,171 +397,13 @@ You should get an error pretty quickly::
artifact_prefix='./'; Test unit written to ./crash-b13e8756b13a00cf168300179061fb4b91fefbed
PCRE2
-----
More examples
-------------
Here we show how to use libFuzzer on something real, yet simple: pcre2_::
Examples of real-life fuzz targets and the bugs they find can be found
at http://tutorial.libfuzzer.info. Among other things you can learn how
to detect Heartbleed_ in one second.
COV_FLAGS=" -fsanitize-coverage=edge,indirect-calls,8bit-counters"
# Get PCRE2
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre2-10.20.tar.gz
tar xf pcre2-10.20.tar.gz
# Build PCRE2 with AddressSanitizer and coverage; requires autotools.
(cd pcre2-10.20; ./autogen.sh; CC="clang -fsanitize=address $COV_FLAGS" ./configure --prefix=`pwd`/../inst && make -j && make install)
# Build the fuzzing target function that does something interesting with PCRE2.
cat << EOF > pcre_fuzzer.cc
#include <string.h>
#include <stdint.h>
#include "pcre2posix.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 1) return 0;
char *str = new char[size+1];
memcpy(str, data, size);
str[size] = 0;
regex_t preg;
if (0 == regcomp(&preg, str, 0)) {
regexec(&preg, str, 0, 0, 0);
regfree(&preg);
}
delete [] str;
return 0;
}
EOF
clang++ -g -fsanitize=address $COV_FLAGS -c -std=c++11 -I inst/include/ pcre_fuzzer.cc
# Link.
clang++ -g -fsanitize=address -Wl,--whole-archive inst/lib/*.a -Wl,-no-whole-archive libFuzzer.a pcre_fuzzer.o -o pcre_fuzzer
This will give you a binary of the fuzzer, called ``pcre_fuzzer``.
Now, create a directory that will hold the test corpus:
.. code-block:: console
mkdir -p CORPUS
For simple input languages like regular expressions this is all you need.
For more complicated/structured inputs, the fuzzer works much more efficiently
if you can populate the corpus directory with a variety of valid and invalid
inputs for the code under test.
Now run the fuzzer with the corpus directory as the only parameter:
.. code-block:: console
./pcre_fuzzer ./CORPUS
Initially, you will see Output_ like this::
INFO: Seed: 2938818941
INFO: -max_len is not provided, using 64
INFO: A corpus is not provided, starting from an empty corpus
#0 READ units: 1 exec/s: 0
#1 INITED cov: 3 bits: 3 units: 1 exec/s: 0
#2 NEW cov: 176 bits: 176 indir: 3 units: 2 exec/s: 0 L: 64 MS: 0
#8 NEW cov: 176 bits: 179 indir: 3 units: 3 exec/s: 0 L: 63 MS: 2 ChangeByte-EraseByte-
...
#14004 NEW cov: 1500 bits: 4536 indir: 5 units: 406 exec/s: 0 L: 54 MS: 3 ChangeBit-ChangeBit-CrossOver-
Now, interrupt the fuzzer and run it again the same way. You will see::
INFO: Seed: 3398349082
INFO: -max_len is not provided, using 64
#0 READ units: 405 exec/s: 0
#405 INITED cov: 1499 bits: 4535 indir: 5 units: 286 exec/s: 0
#587 NEW cov: 1499 bits: 4540 indir: 5 units: 287 exec/s: 0 L: 52 MS: 2 InsertByte-EraseByte-
#667 NEW cov: 1501 bits: 4542 indir: 5 units: 288 exec/s: 0 L: 39 MS: 2 ChangeBit-InsertByte-
#672 NEW cov: 1501 bits: 4543 indir: 5 units: 289 exec/s: 0 L: 15 MS: 2 ChangeASCIIInt-ChangeBit-
#739 NEW cov: 1501 bits: 4544 indir: 5 units: 290 exec/s: 0 L: 64 MS: 4 ShuffleBytes-ChangeASCIIInt-InsertByte-ChangeBit-
...
On the second execution the fuzzer has a non-empty input corpus (405 items). As
the first step, the fuzzer minimized this corpus (the ``INITED`` line) to
produce 286 interesting items, omitting inputs that do not hit any additional
code.
(Aside: although the fuzzer only saves new inputs that hit additional code, this
does not mean that the corpus as a whole is kept minimized. For example, if
an input hitting A-B-C then an input that hits A-B-C-D are generated,
they will both be saved, even though the latter subsumes the former.)
You may run ``N`` independent fuzzer jobs in parallel on ``M`` CPUs:
.. code-block:: console
N=100; M=4; ./pcre_fuzzer ./CORPUS -jobs=$N -workers=$M
By default (``-reload=1``) the fuzzer processes will periodically scan the corpus directory
and reload any new tests. This way the test inputs found by one process will be picked up
by all others.
If ``-workers=$M`` is not supplied, ``min($N,NumberOfCpuCore/2)`` will be used.
Heartbleed
----------
Remember Heartbleed_?
As it was recently `shown <https://blog.hboeck.de/archives/868-How-Heartbleed-couldve-been-found.html>`_,
fuzzing with AddressSanitizer_ can find Heartbleed. Indeed, here are the step-by-step instructions
to find Heartbleed with libFuzzer::
wget https://www.openssl.org/source/openssl-1.0.1f.tar.gz
tar xf openssl-1.0.1f.tar.gz
COV_FLAGS="-fsanitize-coverage=edge,indirect-calls" # -fsanitize-coverage=8bit-counters
(cd openssl-1.0.1f/ && ./config &&
make -j 32 CC="clang -g -fsanitize=address $COV_FLAGS")
# Get and build libFuzzer
svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer
clang -c -g -O2 -std=c++11 Fuzzer/*.cpp -IFuzzer
# Get examples of key/pem files.
git clone https://github.com/hannob/selftls
cp selftls/server* . -v
cat << EOF > handshake-fuzz.cc
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
SSL_CTX *sctx;
int Init() {
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
assert (sctx = SSL_CTX_new(TLSv1_method()));
assert (SSL_CTX_use_certificate_file(sctx, "server.pem", SSL_FILETYPE_PEM));
assert (SSL_CTX_use_PrivateKey_file(sctx, "server.key", SSL_FILETYPE_PEM));
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
static int unused = Init();
SSL *server = SSL_new(sctx);
BIO *sinbio = BIO_new(BIO_s_mem());
BIO *soutbio = BIO_new(BIO_s_mem());
SSL_set_bio(server, sinbio, soutbio);
SSL_set_accept_state(server);
BIO_write(sinbio, Data, Size);
SSL_do_handshake(server);
SSL_free(server);
return 0;
}
EOF
# Build the fuzzer.
clang++ -g handshake-fuzz.cc -fsanitize=address \
openssl-1.0.1f/libssl.a openssl-1.0.1f/libcrypto.a Fuzzer*.o
# Run 20 independent fuzzer jobs.
./a.out -jobs=20 -workers=20
Voila::
#1048576 pulse cov 3424 bits 0 units 9 exec/s 24385
=================================================================
==17488==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x629000004748 at pc 0x00000048c979 bp 0x7fffe3e864f0 sp 0x7fffe3e85ca8
READ of size 60731 at 0x629000004748 thread T0
#0 0x48c978 in __asan_memcpy
#1 0x4db504 in tls1_process_heartbeat openssl-1.0.1f/ssl/t1_lib.c:2586:3
#2 0x580be3 in ssl3_read_bytes openssl-1.0.1f/ssl/s3_pkt.c:1092:4
Note: a `similar fuzzer <https://boringssl.googlesource.com/boringssl/+/HEAD/FUZZING.md>`_
is now a part of the BoringSSL_ source tree.
Advanced features
=================

View File

@ -337,6 +337,7 @@ Failure values are constructed using ``make_error<T>``, where ``T`` is any class
that inherits from the ErrorInfo utility, E.g.:
.. code-block:: c++
class BadFileFormat : public ErrorInfo<BadFileFormat> {
public:
static char ID;