diff --git a/Configure b/Configure index e8fc933872..3064151fe4 100755 --- a/Configure +++ b/Configure @@ -301,7 +301,8 @@ my @disablables = ( "engine", "err", "filenames", - "fuzz", + "fuzz-libfuzzer", + "fuzz-afl", "gost", "heartbeats", "hw(-.+)?", @@ -365,7 +366,8 @@ our %disabled = ( # "what" => "comment" "asan" => "default", "ec_nistp_64_gcc_128" => "default", "egd" => "default", - "fuzz" => "default", + "fuzz-libfuzzer" => "default", + "fuzz-afl" => "default", "md2" => "default", "rc5" => "default", "sctp" => "default", @@ -698,6 +700,14 @@ foreach (@argvcopy) { $withargs{zlib_include}=$1; } + elsif (/^--with-fuzzer-lib=(.*)$/) + { + $withargs{fuzzer_lib}=$1; + } + elsif (/^--with-fuzzer-include=(.*)$/) + { + $withargs{fuzzer_include}=$1; + } elsif (/^--with-fipslibdir=(.*)$/) { $config{fipslibdir}="$1/"; @@ -1042,11 +1052,15 @@ if ($disabled{"dynamic-engine"}) { $config{dynamic_engines} = 1; } -unless ($disabled{fuzz}) { +unless ($disabled{"fuzz-libfuzzer"}) { push @{$config{dirs}}, "fuzz"; $config{cflags} .= "-fsanitize-coverage=edge,indirect-calls "; } +unless ($disabled{"fuzz-afl"}) { + push @{$config{dirs}}, "fuzz"; +} + unless ($disabled{asan}) { $config{cflags} .= "-fsanitize=address "; } @@ -1379,6 +1393,7 @@ if ($builder eq "unified") { $template->fill_in(HASH => { config => \%config, target => \%target, disabled => \%disabled, + withargs => \%withargs, builddir => abs2rel($buildd, $blddir), sourcedir => abs2rel($sourced, $blddir), buildtop => abs2rel($blddir, $blddir), diff --git a/fuzz/README.md b/fuzz/README.md index 9b6d7d7980..e9ec88b8c6 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -1,5 +1,8 @@ # I Can Haz Fuzz? +LibFuzzer +========= + Or, how to fuzz OpenSSL with [libfuzzer](llvm.org/docs/LibFuzzer.html). Starting from a vanilla+OpenSSH server Ubuntu install. @@ -32,7 +35,10 @@ https://github.com/llvm-mirror/llvm/tree/master/lib/Fuzzer if you prefer): Configure for fuzzing: - $ CC=clang ./config enable-fuzz enable-asan enable-ubsan no-shared + $ CC=clang ./config enable-fuzz-libfuzzer \ + --with-fuzzer-include=../../svn-work/Fuzzer \ + --with-fuzzer-lib=../../svn-work/Fuzzer/libFuzzer \ + enable-asan enable-ubsan no-shared $ sudo apt-get install make $ LDCMD=clang++ make -j $ fuzz/helper.py @@ -45,3 +51,20 @@ If you get a crash, you should find a corresponding input file in `fuzz/corpora/-crash/`. You can reproduce the crash with $ fuzz/ + +AFL +=== + +Configure for fuzzing: + + $ sudo apt-get install afl-clang + $ CC=afl-clang-fast ./config enable-fuzz-afl no-shared + $ make + +Run one of the fuzzers: + + $ afl-fuzz fuzz/ -i fuzz/corpora/ -o fuzz/corpora//out + +Where `` is one of the executables in `fuzz/`. Most fuzzers do not +need any command line arguments, but, for example, `asn1` needs the name of a +data type. diff --git a/fuzz/asn1.c b/fuzz/asn1.c index fdf4c5ee29..66825f1b2c 100644 --- a/fuzz/asn1.c +++ b/fuzz/asn1.c @@ -60,7 +60,7 @@ static const ASN1_ITEM *item_type[] = { NULL }; -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { for (int n = 0; item_type[n] != NULL; ++n) { const uint8_t *b = buf; ASN1_VALUE *o = ASN1_item_d2i(NULL, &b, len, item_type[n]); diff --git a/fuzz/asn1parse.c b/fuzz/asn1parse.c index 63104fb7d0..2fe420b140 100644 --- a/fuzz/asn1parse.c +++ b/fuzz/asn1parse.c @@ -18,7 +18,7 @@ #include #include "fuzzer.h" -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { static BIO *bio_out; if (bio_out == NULL) diff --git a/fuzz/bignum.c b/fuzz/bignum.c index 28a439e7d7..643e6e7c65 100644 --- a/fuzz/bignum.c +++ b/fuzz/bignum.c @@ -17,7 +17,7 @@ #include #include "fuzzer.h" -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { int success = 0; static BN_CTX *ctx; static BN_MONT_CTX *mont; diff --git a/fuzz/bndiv.c b/fuzz/bndiv.c index c897de99b5..521281109b 100644 --- a/fuzz/bndiv.c +++ b/fuzz/bndiv.c @@ -17,7 +17,7 @@ #include #include "fuzzer.h" -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { int success = 0; static BN_CTX *ctx; static BIGNUM *b1; diff --git a/fuzz/build.info b/fuzz/build.info index 3569418c0d..762ddf83a5 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -1,33 +1,42 @@ +{- use File::Spec::Functions; + our $ex_inc = $withargs{fuzzer_include} && + (file_name_is_absolute($withargs{fuzzer_include}) ? + $withargs{fuzzer_include} : catdir(updir(), $withargs{fuzzer_include})); + our $ex_lib = $withargs{fuzzer_lib} && + (file_name_is_absolute($withargs{fuzzer_lib}) ? + $withargs{fuzzer_lib} : catfile(updir(), $withargs{fuzzer_lib})); + "" +-} PROGRAMS=asn1 asn1parse bignum bndiv cms conf ct server -SOURCE[asn1]=asn1.c -INCLUDE[asn1]=../include ../../../svn-work/Fuzzer -DEPEND[asn1]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer +SOURCE[asn1]=asn1.c driver.c +INCLUDE[asn1]=../include {- $ex_inc -} +DEPEND[asn1]=../libcrypto {- $ex_lib -} -SOURCE[asn1parse]=asn1parse.c -INCLUDE[asn1parse]=../include ../../../svn-work/Fuzzer -DEPEND[asn1parse]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer +SOURCE[asn1parse]=asn1parse.c driver.c +INCLUDE[asn1parse]=../include {- $ex_inc -} +DEPEND[asn1parse]=../libcrypto {- $ex_lib -} -SOURCE[bignum]=bignum.c -INCLUDE[bignum]=../include ../../../svn-work/Fuzzer -DEPEND[bignum]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer +SOURCE[bignum]=bignum.c driver.c +INCLUDE[bignum]=../include {- $ex_inc -} +DEPEND[bignum]=../libcrypto {- $ex_lib -} -SOURCE[bndiv]=bndiv.c -INCLUDE[bndiv]=../include ../../../svn-work/Fuzzer -DEPEND[bndiv]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer +SOURCE[bndiv]=bndiv.c driver.c +INCLUDE[bndiv]=../include {- $ex_inc -} +DEPEND[bndiv]=../libcrypto {- $ex_lib -} -SOURCE[cms]=cms.c -INCLUDE[cms]=../include ../../../svn-work/Fuzzer -DEPEND[cms]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer +SOURCE[cms]=cms.c driver.c +INCLUDE[cms]=../include {- $ex_inc -} +DEPEND[cms]=../libcrypto {- $ex_lib -} -SOURCE[conf]=conf.c -INCLUDE[conf]=../include ../../../svn-work/Fuzzer -DEPEND[conf]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer +SOURCE[conf]=conf.c driver.c +INCLUDE[conf]=../include {- $ex_inc -} +DEPEND[conf]=../libcrypto {- $ex_lib -} -SOURCE[ct]=ct.c -INCLUDE[ct]=../include ../../../svn-work/Fuzzer -DEPEND[ct]=../libcrypto ../../../svn-work/Fuzzer/libFuzzer +SOURCE[ct]=ct.c driver.c +INCLUDE[ct]=../include {- $ex_inc -} +DEPEND[ct]=../libcrypto {- $ex_lib -} -SOURCE[server]=server.c -INCLUDE[server]=../include ../../../svn-work/Fuzzer -DEPEND[server]=../libcrypto ../libssl ../../../svn-work/Fuzzer/libFuzzer +SOURCE[server]=server.c driver.c +INCLUDE[server]=../include {- $ex_inc -} +DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} diff --git a/fuzz/cms.c b/fuzz/cms.c index 7b4fc3d319..71f691f61b 100644 --- a/fuzz/cms.c +++ b/fuzz/cms.c @@ -16,7 +16,7 @@ #include #include "fuzzer.h" -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { BIO *in = BIO_new(BIO_s_mem()); OPENSSL_assert((size_t)BIO_write(in, buf, len) == len); CMS_ContentInfo *i = d2i_CMS_bio(in, NULL); diff --git a/fuzz/conf.c b/fuzz/conf.c index 3e3f7f184b..d10d6c7f33 100644 --- a/fuzz/conf.c +++ b/fuzz/conf.c @@ -15,7 +15,7 @@ #include #include "fuzzer.h" -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { CONF *conf = NCONF_new(NULL); BIO *in = BIO_new(BIO_s_mem()); long eline; diff --git a/fuzz/ct.c b/fuzz/ct.c index 7050461142..dbb7ab4872 100644 --- a/fuzz/ct.c +++ b/fuzz/ct.c @@ -16,7 +16,7 @@ #include #include "fuzzer.h" -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { const uint8_t **pp = &buf; STACK_OF(SCT) *scts = d2i_SCT_LIST(NULL, pp, len); SCT_LIST_free(scts); diff --git a/fuzz/driver.c b/fuzz/driver.c new file mode 100644 index 0000000000..de515748ce --- /dev/null +++ b/fuzz/driver.c @@ -0,0 +1,51 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL licenses, (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.openssl.org/source/license.html + * or in the file LICENSE in the source distribution. + */ +#include +#include +#include +#include "fuzzer.h" + +#ifndef OPENSSL_NO_FUZZ_LIBFUZZER + +int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + if (FuzzerInitialize) + return FuzzerInitialize(argc, argv); + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { + return FuzzerTestOneInput(buf, len); +} + +#elif !defined(OPENSSL_NO_FUZZ_AFL) + +#define BUF_SIZE 65536 + +int main(int argc, char** argv) +{ + if (FuzzerInitialize) + FuzzerInitialize(&argc, &argv); + + while (__AFL_LOOP(10000)) { + uint8_t *buf = malloc(BUF_SIZE); + size_t size = read(0, buf, BUF_SIZE); + + FuzzerTestOneInput(buf, size); + free(buf); + } + return 0; +} + +#else + +#error "Unsupported fuzzer" + +#endif diff --git a/fuzz/fuzzer.h b/fuzz/fuzzer.h index b3c3428c9b..289aee2f60 100644 --- a/fuzz/fuzzer.h +++ b/fuzz/fuzzer.h @@ -8,5 +8,5 @@ * or in the file LICENSE in the source distribution. */ -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); -int LLVMFuzzerInitialize(int *argc, char ***argv); +int FuzzerTestOneInput(const uint8_t *buf, size_t len); +__attribute__((weak)) int FuzzerInitialize(int *argc, char ***argv); diff --git a/fuzz/server.c b/fuzz/server.c index d3ed1adfe0..7b376c1abb 100644 --- a/fuzz/server.c +++ b/fuzz/server.c @@ -208,7 +208,7 @@ static void Init() { X509_free(cert); } -int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) { +int FuzzerTestOneInput(const uint8_t *buf, size_t len) { if (ctx == NULL) Init(); // TODO: make this work for OpenSSL. There's a PREDICT define that may do