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