From 2557bdcf39bdcc63d711d904cfa2ff8e638a96a8 Mon Sep 17 00:00:00 2001 From: "Daniel J. Hofmann" Date: Tue, 12 Apr 2016 11:58:43 +0200 Subject: [PATCH] Basic Fuzz Testing. [100%] Fuzzing libosrm /tmp/osrm-backend/build/fuzz/driver -max_len=4096 corpus > fuzz-0.log 2>&1 /tmp/osrm-backend/build/fuzz/driver -max_len=4096 corpus > fuzz-1.log 2>&1 /tmp/osrm-backend/build/fuzz/driver -max_len=4096 corpus > fuzz-2.log 2>&1 /tmp/osrm-backend/build/fuzz/driver -max_len=4096 corpus > fuzz-3.log 2>&1 References: - http://llvm.org/docs/LibFuzzer.html - http://llvm.org/releases/3.8.0/docs/LibFuzzer.html - https://github.com/Project-OSRM/osrm-backend/issues/1678 --- CMakeLists.txt | 9 +++++++++ fuzz/CMakeLists.txt | 25 +++++++++++++++++++++++++ fuzz/driver.cc | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 fuzz/CMakeLists.txt create mode 100644 fuzz/driver.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 362eefcaa..bf72b5c20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ option(ENABLE_ASSERTIONS OFF) option(COVERAGE OFF) option(SANITIZER OFF) option(ENABLE_LTO "Use LTO if available" ON) +option(ENABLE_FUZZING "Fuzz testing using LLVM's libFuzzer" OFF) include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/) @@ -244,6 +245,7 @@ if(UNIX AND NOT APPLE) set(MAYBE_RT_LIBRARY rt) endif() + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/cmake") set(OSMIUM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libosmium/include") find_package(Osmium REQUIRED COMPONENTS io) @@ -498,3 +500,10 @@ add_custom_target(uninstall # Modular build system: each directory registered here provides its own CMakeLists.txt add_subdirectory(unit_tests) add_subdirectory(src/benchmarks) + +if (ENABLE_FUZZING) + # TODO(daniel-j-h): fuzz against configurable ubsan,msan,asan libosrm builds + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-coverage=edge,indirect-calls,8bit-counters -fsanitize=address") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") + add_subdirectory(fuzz) +endif () diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt new file mode 100644 index 000000000..12db5f5b2 --- /dev/null +++ b/fuzz/CMakeLists.txt @@ -0,0 +1,25 @@ +# Fuzz testing using LLVM's libFuzzer. +# +# See: +# - http://llvm.org/docs/LibFuzzer.html +# - http://llvm.org/releases/3.8.0/docs/LibFuzzer.html +# +# TODO(daniel-j-h): +# - make more user friendly, at the moment we require you to build and install libFuzzer.a +# - pick up LLVM_ROOT +# - build libFuzzer on the fly +# +# clang++ -std=c++11 -stdlib=libc++ -c -g -O2 ~/llvm/lib/Fuzzer/*.cpp -I~/llvm/lib/Fuzzer +# ar ruv libFuzzer.a Fuzzer*.o + +if (ENABLE_FUZZING) + add_executable(driver driver.cc $ $) + target_link_libraries(driver Fuzzer osrm) + + add_custom_target(fuzz + DEPENDS driver + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory corpus + COMMAND driver -jobs=4 -workers=4 -max_len=4096 corpus + COMMENT "Fuzzing libosrm" VERBATIM) +endif () diff --git a/fuzz/driver.cc b/fuzz/driver.cc new file mode 100644 index 000000000..5910ef488 --- /dev/null +++ b/fuzz/driver.cc @@ -0,0 +1,32 @@ +#include "server/api/parameters_parser.hpp" + +#include "engine/api/base_parameters.hpp" +#include "engine/api/match_parameters.hpp" +#include "engine/api/nearest_parameters.hpp" +#include "engine/api/route_parameters.hpp" +#include "engine/api/table_parameters.hpp" +#include "engine/api/tile_parameters.hpp" +#include "engine/api/trip_parameters.hpp" + +#include +#include + +/* + * First pass at fuzzing the server, without any libosrm setup. + * Later we want keep state across fuzz testing invocations via: + * + * struct State { State() { setup_osrm(); } }; + * static State state; + */ + +extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) +{ + std::string in(reinterpret_cast(data), size); + + auto first = begin(in); + const auto last = end(in); + + (void)osrm::server::api::parseParameters(first, last); + + return 0; /* Always return zero, sanitizers hard-abort */ +}