From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp51.i.mail.ru (smtp51.i.mail.ru [94.100.177.111]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 6C88B4696C3 for ; Mon, 20 Apr 2020 11:47:37 +0300 (MSK) Date: Mon, 20 Apr 2020 11:47:37 +0300 From: Sergey Bronnikov Message-ID: <33ba1d50585e101aa025d899116c48d56be59202.1587372354.git.sergeyb@tarantool.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Subject: [Tarantool-patches] [PATCH v2] Add infrastructure for fuzzing testing and fuzzers List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org Cc: o.piskunov@tarantool.org - introduce CMake flag to enable building fuzzers - add fuzzers based on LibFuzzer[1] to csv, http_parser and uri modules [1] https://llvm.org/docs/LibFuzzer.html Note: LibFuzzer requires Clang compiler How-To Use: $ mkdir build && cd build $ CC=clang CXX=clang++ cmake -DENABLE_FUZZER=ON .. $ make -j $ ./Testing/test_csv corpus/ -max_total_time=60*60*60 -workers=4 ... Follows: #1809 --- CMakeLists.txt | 2 +- cmake/profile.cmake | 5 +++++ src/lib/csv/CMakeLists.txt | 11 +++++++++++ src/lib/csv/test_csv.c | 23 +++++++++++++++++++++++ src/lib/http_parser/CMakeLists.txt | 11 +++++++++++ src/lib/http_parser/test_http_parser.c | 22 ++++++++++++++++++++++ src/lib/uri/CMakeLists.txt | 12 ++++++++++++ src/lib/uri/test_uri.c | 22 ++++++++++++++++++++++ 8 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/lib/csv/test_csv.c create mode 100644 src/lib/http_parser/test_http_parser.c create mode 100644 src/lib/uri/test_uri.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d80b6806..99a502e3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -571,7 +571,7 @@ set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(options PACKAGE VERSION BUILD C_COMPILER CXX_COMPILER C_FLAGS CXX_FLAGS PREFIX ENABLE_SSE2 ENABLE_AVX - ENABLE_GCOV ENABLE_GPROF ENABLE_VALGRIND ENABLE_ASAN + ENABLE_GCOV ENABLE_GPROF ENABLE_VALGRIND ENABLE_ASAN ENABLE_FUZZER ENABLE_BACKTRACE ENABLE_DOC ENABLE_DIST diff --git a/cmake/profile.cmake b/cmake/profile.cmake index bc4bf67f5..b9fcd7655 100644 --- a/cmake/profile.cmake +++ b/cmake/profile.cmake @@ -42,6 +42,11 @@ else() add_definitions(-DNVALGRIND=1) endif() +option(ENABLE_FUZZER "Enable fuzzing testing" OFF) +if (ENABLE_FUZZER) + set(TESTING_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Testing") +endif () + option(ENABLE_ASAN "Enable AddressSanitizer, a fast memory error detector based on compiler instrumentation" OFF) if (ENABLE_ASAN) if (CMAKE_COMPILER_IS_GNUCC) diff --git a/src/lib/csv/CMakeLists.txt b/src/lib/csv/CMakeLists.txt index 3580e4da2..d5a3ed1f6 100644 --- a/src/lib/csv/CMakeLists.txt +++ b/src/lib/csv/CMakeLists.txt @@ -4,3 +4,14 @@ set(lib_sources set_source_files_compile_flags(${lib_sources}) add_library(csv STATIC ${lib_sources}) + +if (ENABLE_FUZZER AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(TestName "test_csv") + add_executable(${TestName} ${TestName}.c) + set_target_properties(${TestName} + PROPERTIES + COMPILE_FLAGS "-fsanitize=fuzzer,address -g -O1" + LINK_FLAGS "-fsanitize=fuzzer,address") + target_link_libraries(${TestName} PRIVATE csv) + set_target_properties(${TestName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") +endif () diff --git a/src/lib/csv/test_csv.c b/src/lib/csv/test_csv.c new file mode 100644 index 000000000..aa1703514 --- /dev/null +++ b/src/lib/csv/test_csv.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include "csv.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + struct csv csv; + csv_create(&csv); + char *buf = calloc(size, sizeof(char*)); + if (buf == NULL) { + return -1; + } + memcpy(buf, data, size); + buf[size] = '\0'; + char *end = buf + size; + csv_parse_chunk(&csv, buf, end); + csv_finish_parsing(&csv); + csv_destroy(&csv); + free(buf); + + return 0; +} diff --git a/src/lib/http_parser/CMakeLists.txt b/src/lib/http_parser/CMakeLists.txt index a48f83cb6..7af922fbb 100644 --- a/src/lib/http_parser/CMakeLists.txt +++ b/src/lib/http_parser/CMakeLists.txt @@ -1 +1,12 @@ add_library(http_parser STATIC http_parser.c) + +if (ENABLE_FUZZER AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(TestName "test_http_parser") + add_executable(${TestName} ${TestName}.c) + set_target_properties(${TestName} + PROPERTIES + COMPILE_FLAGS "-fsanitize=fuzzer,address -g -O1" + LINK_FLAGS "-fsanitize=fuzzer,address") + target_link_libraries(${TestName} PRIVATE http_parser) + set_target_properties(${TestName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") +endif () diff --git a/src/lib/http_parser/test_http_parser.c b/src/lib/http_parser/test_http_parser.c new file mode 100644 index 000000000..a189e71e9 --- /dev/null +++ b/src/lib/http_parser/test_http_parser.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include "http_parser.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + struct http_parser parser; + char *buf = (char*)data; + http_parser_create(&parser); + parser.hdr_name = (char *)calloc((int)size, sizeof(char)); + if (parser.hdr_name == NULL) { + return -1; + } + char *end_buf = buf + size; + int rc = http_parse_header_line(&parser, &buf, end_buf, size); + free(parser.hdr_name); + if (rc != 0) { + return rc; + } + + return 0; +} diff --git a/src/lib/uri/CMakeLists.txt b/src/lib/uri/CMakeLists.txt index 96410e5bf..77f5c5d57 100644 --- a/src/lib/uri/CMakeLists.txt +++ b/src/lib/uri/CMakeLists.txt @@ -8,3 +8,15 @@ if (CC_HAS_WNO_IMPLICIT_FALLTHROUGH) -Wno-implicit-fallthrough) endif() add_library(uri STATIC uri.c) + +if (ENABLE_FUZZER AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(TestName "test_uri") + add_executable(${TestName} ${TestName}.c) + add_compile_options(-fsanitize=fuzzer,address -g -O1) + set_target_properties(${TestName} + PROPERTIES + COMPILE_FLAGS "-fsanitize=fuzzer,address -g -O1" + LINK_FLAGS "-fsanitize=fuzzer,address") + target_link_libraries(${TestName} PRIVATE uri) + set_target_properties(${TestName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") +endif () diff --git a/src/lib/uri/test_uri.c b/src/lib/uri/test_uri.c new file mode 100644 index 000000000..ad8db6ef2 --- /dev/null +++ b/src/lib/uri/test_uri.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include "uri.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + char *buf = calloc(size, sizeof(char*)); + if (!buf) { + return -1; + } + strncpy(buf, (char*)data, size); + buf[size] = '\0'; + struct uri uri; + int rc = uri_parse(&uri, buf); + free(buf); + if (rc != 0) { + return rc; + } + + return 0; +} -- 2.23.0 -- sergeyb@