From c48481d1bc292bd7510830e1402764bcb2bedd6e Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Fri, 23 Jun 2017 14:51:55 +0200 Subject: [PATCH] Create fuzzing basis + base64 fuzzer Signed-off-by: Guido Vranken --- configure.ac | 6 + src/openvpn/Makefile.am | 43 +++-- src/openvpn/dummy.cpp | 0 src/openvpn/fuzzer-base64.c | 52 ++++++ src/openvpn/fuzzer-standalone-loader.c | 30 ++++ src/openvpn/fuzzing.c | 236 +++++++++++++++++++++++++ src/openvpn/fuzzing.h | 47 +++++ src/openvpn/openvpn.c | 2 + 8 files changed, 405 insertions(+), 11 deletions(-) create mode 100644 src/openvpn/dummy.cpp create mode 100644 src/openvpn/fuzzer-base64.c create mode 100644 src/openvpn/fuzzer-standalone-loader.c create mode 100644 src/openvpn/fuzzing.c create mode 100644 src/openvpn/fuzzing.h diff --git a/configure.ac b/configure.ac index 22f91cb60..0d4e00b12 100644 --- a/configure.ac +++ b/configure.ac @@ -364,6 +364,7 @@ esac PKG_PROG_PKG_CONFIG AC_PROG_CPP +AC_PROG_CXX AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_SED @@ -582,6 +583,11 @@ AC_COMPILE_IFELSE( [AC_MSG_RESULT([no])] ) +CFLAGS="${CFLAGS} -DFUZZING -g3 -fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp -fsanitize=address -fsanitize=undefined -fsanitize-recover=alignment" +CXXFLAGS="${CXXFLAGS} -DFUZZING -g3 -fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp -fsanitize=address -fsanitize=undefined -fsanitize-recover=alignment" +CC="clang" +CXX="clang++" + saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--wrap=exit" AC_MSG_CHECKING([linker supports --wrap]) diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index fcc22d684..83126a234 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -35,9 +35,8 @@ if WIN32 AM_CFLAGS += -municode -UUNICODE endif -sbin_PROGRAMS = openvpn - -openvpn_SOURCES = \ +lib_LTLIBRARIES = libopenvpn.la +libopenvpn_la_SOURCES = \ argv.c argv.h \ base64.c base64.h \ basic.h \ @@ -120,17 +119,39 @@ openvpn_SOURCES = \ tun.c tun.h \ win32.h win32.c \ cryptoapi.h cryptoapi.c -openvpn_LDADD = \ - $(top_builddir)/src/compat/libcompat.la \ + +libopenvpn_la_SOURCES += \ + fuzzing.h fuzzing.c + +extra_PROGRAMS = \ + openvpn-fuzzer-base64 openvpn-fuzzer-base64-standalone +extradir = . +fuzzer_sources = dummy.cpp +fuzzer_cflags = \ + $(TAP_CFLAGS) \ + $(OPTIONAL_CRYPTO_CFLAGS) \ + $(OPTIONAL_LZO_CFLAGS) \ + $(OPTIONAL_LZ4_CFLAGS) \ + $(OPTIONAL_PKCS11_HELPER_CFLAGS) \ + -DPLUGIN_LIBDIR=\"${plugindir}\" +fuzzer_ldflags = -static +fuzzer_ldadd = \ $(SOCKETS_LIBS) \ - $(OPTIONAL_LZO_LIBS) \ $(OPTIONAL_LZ4_LIBS) \ $(OPTIONAL_PKCS11_HELPER_LIBS) \ $(OPTIONAL_CRYPTO_LIBS) \ $(OPTIONAL_SELINUX_LIBS) \ $(OPTIONAL_SYSTEMD_LIBS) \ - $(OPTIONAL_DL_LIBS) -if WIN32 -openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h -openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -endif + $(OPTIONAL_DL_LIBS) \ + libopenvpn.la \ + $(top_builddir)/src/compat/libcompat.la \ + $(OPTIONAL_LZO_LIBS) + +openvpn_fuzzer_base64_SOURCES = $(fuzzer_sources) +openvpn_fuzzer_base64_LDFLAGS = $(fuzzer_ldflags) +openvpn_fuzzer_base64_CFLAGS = $(fuzzer_cflags) +openvpn_fuzzer_base64_LDADD = $(fuzzer_ldadd) fuzzer-base64.o libFuzzer.a +openvpn_fuzzer_base64_standalone_SOURCES = fuzzer-standalone-loader.c +openvpn_fuzzer_base64_standalone_LDFLAGS = $(fuzzer_ldflags) +openvpn_fuzzer_base64_standalone_CFLAGS = $(fuzzer_cflags) +openvpn_fuzzer_base64_standalone_LDADD = $(fuzzer_ldadd) fuzzer-base64.o diff --git a/src/openvpn/dummy.cpp b/src/openvpn/dummy.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/openvpn/fuzzer-base64.c b/src/openvpn/fuzzer-base64.c new file mode 100644 index 000000000..cddd1b1bf --- /dev/null +++ b/src/openvpn/fuzzer-base64.c @@ -0,0 +1,52 @@ +#include "config.h" +#include "syshead.h" +#ifdef FUZZING +#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) +#elif defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) +#else +#error "This fuzzing target cannot be built" +#endif + + +#include "fuzzing.h" +#include "base64.h" + +int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + return 1; +} +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + char* str = NULL; + unsigned char* outbuf; + uint16_t* outsize; + int ret; + if ( size < sizeof(*outsize) ) + { + return 0; + } + outsize = (uint16_t*)data; + data += sizeof(*outsize); + size -= sizeof(*outsize); + if ( openvpn_base64_encode(data, size, &str) > 0 ) + { +#ifdef MSAN + test_undefined_memory(str, strlen(str)+1); +#endif + } + free(str); + str = malloc(size+1); + memcpy(str, (char*)data, size); + str[size] = 0; + outbuf = malloc(*outsize); + if ( (ret = openvpn_base64_decode(str, outbuf, *outsize)) > 0 ) + { +#ifdef MSAN + test_undefined_memory(outbuf, ret); +#endif + } + free(str); + free(outbuf); + return 0; +} +#endif /* FUZZING */ diff --git a/src/openvpn/fuzzer-standalone-loader.c b/src/openvpn/fuzzer-standalone-loader.c new file mode 100644 index 000000000..c7382878e --- /dev/null +++ b/src/openvpn/fuzzer-standalone-loader.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +int LLVMFuzzerInitialize(int *argc, char ***argv); + +int main(int argc, char **argv) { + int n; + + for (n = 1; n < argc; ++n) { + struct stat st; + FILE *f; + unsigned char *buf; + size_t s; + + stat(argv[n], &st); + f = fopen(argv[n], "rb"); + if (f == NULL) + continue; + buf = malloc(st.st_size); + s = fread(buf, 1, st.st_size, f); + LLVMFuzzerInitialize(NULL, NULL); + LLVMFuzzerTestOneInput(buf, s); + free(buf); + fclose(f); + } + return 0; +} diff --git a/src/openvpn/fuzzing.c b/src/openvpn/fuzzing.c new file mode 100644 index 000000000..2bf31750c --- /dev/null +++ b/src/openvpn/fuzzing.c @@ -0,0 +1,236 @@ +#ifdef FUZZING +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif +#include "syshead.h" +#include "buffer.h" +#include "fuzzing.h" + +static unsigned char* fuzzer_data = NULL; +static size_t fuzzer_data_size = 0; + +void fuzzer_set_input(unsigned char* data, size_t size) +{ + fuzzer_data = data; + fuzzer_data_size = size; +} + +unsigned char* fuzzer_get_current_data(void) +{ + return fuzzer_data; +} + +size_t fuzzer_get_current_size(void) +{ + return fuzzer_data_size; +} + +static int recv_no_rnd = 0; +void fuzzer_set_recv_no_rnd(int yesno) +{ + recv_no_rnd = yesno; +} + +ssize_t fuzzer_get_data(void* dest, size_t size) +{ + if ( size > fuzzer_data_size ) + { + return -1; + } + + memcpy(dest, fuzzer_data, size); + + fuzzer_data += size; + fuzzer_data_size -= size; + + return size; +} + +ssize_t fuzzer_get_data_rnd(void* dest, size_t size) +{ + size_t realsize; + unsigned int realsize_ui; + unsigned short realsize_us; + unsigned char realsize_uc; + + if ( size == 0 ) + { + return 0; + } + + if ( size > 0x7FFFFFFF ) + { + return 0; + } + + if ( size > 65535 ) + { + if ( fuzzer_get_data(&realsize_ui, sizeof(realsize_ui)) < 0 ) + { + return -1; + } + realsize = realsize_ui; + } + else if ( size > 255 ) + { + if ( fuzzer_get_data(&realsize_us, sizeof(realsize_us)) < 0 ) + { + return -1; + } + realsize = realsize_us; + } + else + { + if ( fuzzer_get_data(&realsize_uc, sizeof(realsize_uc)) < 0 ) + { + return -1; + } + realsize = realsize_uc; + } + + realsize %= (size+1); + + return fuzzer_get_data(dest, realsize); +} + +ssize_t fuzzer_get_integer(size_t max) +{ + size_t s; + + if ( max == 0 ) + { + return 0; + } + + /* + if ( max > 0x7FFFFFFF ) + { + return -1; + } + */ + + if ( fuzzer_get_data(&s, sizeof(s)) < 0 ) + { + return -1; + } + + return s % (max+1); +} + +static char* fuzzer_get_string_inner(size_t maxsize, struct gc_arena* gc) +{ + ssize_t strsize; + char* ret; + + if ( (strsize = fuzzer_get_integer(maxsize)) < 0 ) + { + return NULL; + } + + if ( gc == NULL ) + { + ret = malloc(strsize+1); + } + else + { + ALLOC_ARRAY_GC(ret, char, strsize+1, gc); + } + + if ( ret == NULL ) + { + return NULL; + } + + if ( fuzzer_get_data(ret, strsize) < 0 ) + { + if ( gc == NULL ) + { + free(ret); + } + return NULL; + } + + ret[strsize] = 0; + + return ret; +} + +char* fuzzer_get_string(size_t maxsize) +{ + return fuzzer_get_string_inner(maxsize, NULL); +} + +char* fuzzer_get_string_gc(size_t maxsize, struct gc_arena* gc) +{ + return fuzzer_get_string_inner(maxsize, gc); +} + +ssize_t fuzzer_read(void* dest, size_t size) +{ + if ( recv_no_rnd ) + { + return fuzzer_get_data(dest, size); + } + else + { + return fuzzer_get_data_rnd(dest, size); + } +} + +ssize_t fuzzer_recv(void* dest, size_t size) +{ + if ( recv_no_rnd ) + { + return fuzzer_get_data(dest, size); + } + else + { + return fuzzer_get_data_rnd(dest, size); + } +} + +ssize_t fuzzer_send(size_t size) +{ + /* + ssize_t r = fuzzer_get_integer(size); + + if ( r < 0 ) + { + return -1; + } + */ + return size; + //return r; +} + +void fuzzer_alter_buffer(struct buffer* buffer) +{ + ssize_t newoffset, newlen; + if ( buffer->capacity == 0 ) + { + return; + } + FUZZER_GET_INTEGER(newoffset, buffer->capacity); + newlen = buffer->capacity - newoffset; + if ( newlen != 0 ) + { + FUZZER_GET_INTEGER(newlen, newlen); + } + buffer->offset = newoffset; + buffer->len = newlen; + + return; +cleanup: + return; +} + +void test_undefined_memory(void* vp, size_t s) +{ + FILE* fp = fopen("/dev/null", "wb"); + unsigned char* p = (unsigned char*)vp; + fwrite(p, s, 1, fp); + fclose(fp); +} +#endif diff --git a/src/openvpn/fuzzing.h b/src/openvpn/fuzzing.h new file mode 100644 index 000000000..0dec200ac --- /dev/null +++ b/src/openvpn/fuzzing.h @@ -0,0 +1,47 @@ +#ifdef FUZZING +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif +#include "syshead.h" +#include "buffer.h" +void fuzzer_set_input(unsigned char* data, size_t size); +unsigned char* fuzzer_get_current_data(void); +size_t fuzzer_get_current_size(void); +void fuzzer_set_recv_no_rnd(int yesno); +ssize_t fuzzer_get_data(void* dest, size_t size); +ssize_t fuzzer_get_data_rnd(void* dest, size_t size); +ssize_t fuzzer_get_integer(size_t max); +char* fuzzer_get_string(size_t maxsize); +char* fuzzer_get_string_gc(size_t maxsize, struct gc_arena* gc); +ssize_t fuzzer_read(void* dest, size_t size); +ssize_t fuzzer_recv(void* dest, size_t size); +ssize_t fuzzer_send(size_t size); +void fuzzer_alter_buffer(struct buffer* buffer); +void test_undefined_memory(void* vp, size_t s); +#define FUZZER_GET_DATA(dest, size) { \ + if ( fuzzer_get_data((dest), (size)) < 0 ) { \ + goto cleanup; \ + } \ +} +#define FUZZER_GET_INTEGER(dest, max) { \ + (dest) = fuzzer_get_integer(max); \ + if ( (dest) < 0 ) { \ + goto cleanup; \ + } \ +} +#define FUZZER_GET_STRING(dest, max) { \ + (dest) = NULL; \ + if ( ((dest) = fuzzer_get_string(max)) == NULL ) { \ + goto cleanup; \ + } \ +} + +#define FUZZER_GET_STRING_GC(dest, max, gc) { \ + (dest) = NULL; \ + if ( ((dest) = fuzzer_get_string_gc((max), (gc))) == NULL ) { \ + goto cleanup; \ + } \ +} +#endif diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 08c09e6be..a89beba89 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -329,6 +329,7 @@ openvpn_main(int argc, char *argv[]) return 0; /* NOTREACHED */ } +#if 0 #ifdef _WIN32 int wmain(int argc, wchar_t *wargv[]) @@ -366,3 +367,4 @@ main(int argc, char *argv[]) return openvpn_main(argc, argv); } #endif /* ifdef _WIN32 */ +#endif -- 2.47.2