From f59d0131cb6fc224aee0a0a92de1f04cdebe97c8 Mon Sep 17 00:00:00 2001 From: Kurt Roeckx Date: Sat, 7 May 2016 22:09:13 +0200 Subject: Add support for fuzzing with AFL Reviewed-by: Ben Laurie MR: #2740 --- fuzz/README.md | 25 ++++++++++++++++++++++++- fuzz/asn1.c | 2 +- fuzz/asn1parse.c | 2 +- fuzz/bignum.c | 2 +- fuzz/bndiv.c | 2 +- fuzz/build.info | 57 ++++++++++++++++++++++++++++++++------------------------ fuzz/cms.c | 2 +- fuzz/conf.c | 2 +- fuzz/ct.c | 2 +- fuzz/driver.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ fuzz/fuzzer.h | 4 ++-- fuzz/server.c | 2 +- 12 files changed, 118 insertions(+), 35 deletions(-) create mode 100644 fuzz/driver.c (limited to 'fuzz') 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 -- cgit v1.2.3