From d71375bf8a6a388db940cf5d1359638e8aa86606 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 28 Jun 2019 20:49:35 +0200 Subject: [PATCH 1/2] Add libFuzzer harnesses, a cmake option to build them --- .travis.yml | 3 ++ CMakeLists.txt | 22 ++++++++ snappy-compress-uncompress-fuzzer.cc | 80 ++++++++++++++++++++++++++++ snappy-uncompress-fuzzer.cc | 66 +++++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 snappy-compress-uncompress-fuzzer.cc create mode 100644 snappy-uncompress-fuzzer.cc diff --git a/.travis.yml b/.travis.yml index 717bac8..2dac1b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,8 +72,11 @@ before_script: - mkdir -p build && cd build - cmake .. -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSNAPPY_REQUIRE_${CPU_LEVEL}=ON + -DSNAPPY_BUILD_FUZZERS=ON - cmake --build . - cd .. script: - build/snappy_unittest +- build/snappy_compress_uncompress_fuzzer -runs=1000 -close_fd_mask=3 +- build/snappy_uncompress_fuzzer -runs=1000 -close_fd_mask=3 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d3a157..618b853 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,8 @@ option(BUILD_SHARED_LIBS "Build shared libraries(DLLs)." OFF) option(SNAPPY_BUILD_TESTS "Build Snappy's own tests." ON) +option(SNAPPY_BUILD_FUZZERS "Build Snappy's fuzzers." OFF) + option(SNAPPY_REQUIRE_AVX "Target processors with AVX support." OFF) option(SNAPPY_REQUIRE_AVX2 "Target processors with AVX2 support." OFF) @@ -185,6 +187,26 @@ if(SNAPPY_BUILD_TESTS) COMMAND "${PROJECT_BINARY_DIR}/snappy_unittest") endif(SNAPPY_BUILD_TESTS) +if(SNAPPY_BUILD_FUZZERS) + add_executable(snappy_compress_uncompress_fuzzer "") + target_sources(snappy_compress_uncompress_fuzzer + PRIVATE "${PROJECT_SOURCE_DIR}/snappy-compress-uncompress-fuzzer.cc" + ) + target_link_libraries(snappy_compress_uncompress_fuzzer snappy) + set_target_properties(snappy_compress_uncompress_fuzzer + PROPERTIES LINK_FLAGS "-fsanitize=fuzzer" + ) + + add_executable(snappy_uncompress_fuzzer "") + target_sources(snappy_uncompress_fuzzer + PRIVATE "${PROJECT_SOURCE_DIR}/snappy-uncompress-fuzzer.cc" + ) + target_link_libraries(snappy_uncompress_fuzzer snappy) + set_target_properties(snappy_uncompress_fuzzer + PROPERTIES LINK_FLAGS "-fsanitize=fuzzer" + ) +endif(SNAPPY_BUILD_FUZZERS) + include(GNUInstallDirs) install(TARGETS snappy EXPORT SnappyTargets diff --git a/snappy-compress-uncompress-fuzzer.cc b/snappy-compress-uncompress-fuzzer.cc new file mode 100644 index 0000000..b9fb3ac --- /dev/null +++ b/snappy-compress-uncompress-fuzzer.cc @@ -0,0 +1,80 @@ +// Copyright 2019 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// libFuzzer harness for fuzzing snappy compression-decompression routines. + +#include +#include +#include +#include + +#include "snappy.h" + +namespace snappy { + +// Supplies random data sourced from libFuzzer to the snappy compressor, +// decompressing its output and running some checks in the process. +// Most important of these checks is input == uncompress(compress(input)) +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + string input(reinterpret_cast(data), size); + + string compressed_out; + size_t compressed_len = snappy::Compress( + input.data(), + input.size(), + &compressed_out); + + assert(compressed_len == compressed_out.size()); + assert(compressed_len <= snappy::MaxCompressedLength(input.size())); + assert(snappy::IsValidCompressedBuffer( + compressed_out.data(), + compressed_out.size())); + + size_t uncompressed_len = 0; + bool getcomp_len_success = snappy::GetUncompressedLength( + compressed_out.data(), + compressed_out.size(), + &uncompressed_len); + // Check that GetUncompressedLength() does not return a very large + // value (1 MB) on success. + assert(!getcomp_len_success || uncompressed_len < (1 << 20)); + + // Uncompress + string uncompressed_out; + bool uncompress_success = snappy::Uncompress( + compressed_out.data(), + compressed_out.size(), + &uncompressed_out); + + assert(uncompress_success); + assert(input == uncompressed_out); + return 0; +} + +} // namespace snappy \ No newline at end of file diff --git a/snappy-uncompress-fuzzer.cc b/snappy-uncompress-fuzzer.cc new file mode 100644 index 0000000..68a0097 --- /dev/null +++ b/snappy-uncompress-fuzzer.cc @@ -0,0 +1,66 @@ +// Copyright 2019 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// libFuzzer harness for fuzzing snappy decompression routine. + +#include +#include +#include +#include + +#include "snappy.h" + +namespace snappy { + +// Supplies random data sourced from libFuzzer to the snappy uncompressor, +// decompressing its output and running some checks in the process. +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + string input(reinterpret_cast(data), size); + + size_t uncompressed_len = 0; + bool getcomp_len_success = snappy::GetUncompressedLength( + input.data(), + input.size(), + &uncompressed_len); + // Check that GetUncompressedLength() does not return a very large + // value (1 MB) on success. + assert(!getcomp_len_success || uncompressed_len < (1 << 20)); + + // Uncompress + string uncompressed_out; + bool uncompress_success = snappy::Uncompress( + input.data(), + input.size(), + &uncompressed_out); + + assert(uncompress_success); + return 0; +} + +} // namespace snappy \ No newline at end of file From a58d4b03c51e0c7e44df8693c16cd352503167ba Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Sat, 27 Jul 2019 10:57:49 +0200 Subject: [PATCH 2/2] Update travis config for fuzzer builds --- .travis.yml | 11 +++++++++-- snappy-compress-uncompress-fuzzer.cc | 16 ++++++++-------- snappy-uncompress-fuzzer.cc | 12 ++++++------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2dac1b6..c4140d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,9 +70,16 @@ install: before_script: - mkdir -p build && cd build -- cmake .. -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE +- if [ "$CXX" = "clang++-8"; then + # Build UBSan binary + export CXXFLAGS="-fsanitize=undefined -fsanitize-coverage=bb,trace-pc-guard"; + cmake .. -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSNAPPY_REQUIRE_${CPU_LEVEL}=ON - -DSNAPPY_BUILD_FUZZERS=ON + -DSNAPPY_BUILD_FUZZERS=ON; + else + cmake .. -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE + -DSNAPPY_REQUIRE_${CPU_LEVEL}=ON; + fi - cmake --build . - cd .. diff --git a/snappy-compress-uncompress-fuzzer.cc b/snappy-compress-uncompress-fuzzer.cc index b9fb3ac..273852d 100644 --- a/snappy-compress-uncompress-fuzzer.cc +++ b/snappy-compress-uncompress-fuzzer.cc @@ -53,14 +53,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) assert(compressed_len == compressed_out.size()); assert(compressed_len <= snappy::MaxCompressedLength(input.size())); assert(snappy::IsValidCompressedBuffer( - compressed_out.data(), - compressed_out.size())); + compressed_out.data(), + compressed_out.size())); size_t uncompressed_len = 0; bool getcomp_len_success = snappy::GetUncompressedLength( - compressed_out.data(), - compressed_out.size(), - &uncompressed_len); + compressed_out.data(), + compressed_out.size(), + &uncompressed_len); // Check that GetUncompressedLength() does not return a very large // value (1 MB) on success. assert(!getcomp_len_success || uncompressed_len < (1 << 20)); @@ -68,9 +68,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // Uncompress string uncompressed_out; bool uncompress_success = snappy::Uncompress( - compressed_out.data(), - compressed_out.size(), - &uncompressed_out); + compressed_out.data(), + compressed_out.size(), + &uncompressed_out); assert(uncompress_success); assert(input == uncompressed_out); diff --git a/snappy-uncompress-fuzzer.cc b/snappy-uncompress-fuzzer.cc index 68a0097..a516cc9 100644 --- a/snappy-uncompress-fuzzer.cc +++ b/snappy-uncompress-fuzzer.cc @@ -45,9 +45,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) size_t uncompressed_len = 0; bool getcomp_len_success = snappy::GetUncompressedLength( - input.data(), - input.size(), - &uncompressed_len); + input.data(), + input.size(), + &uncompressed_len); // Check that GetUncompressedLength() does not return a very large // value (1 MB) on success. assert(!getcomp_len_success || uncompressed_len < (1 << 20)); @@ -55,9 +55,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // Uncompress string uncompressed_out; bool uncompress_success = snappy::Uncompress( - input.data(), - input.size(), - &uncompressed_out); + input.data(), + input.size(), + &uncompressed_out); assert(uncompress_success); return 0;