diff --git a/CMakeLists.txt b/CMakeLists.txt index aabb3dca..e4f0093d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ option( EXIV2_ENABLE_BMFF "Build with BMFF support" option( EXIV2_BUILD_SAMPLES "Build sample applications" ON ) option( EXIV2_BUILD_EXIV2_COMMAND "Build exiv2 command-line executable" ON ) option( EXIV2_BUILD_UNIT_TESTS "Build unit tests" OFF ) +option( EXIV2_BUILD_FUZZ_TESTS "Build fuzz tests (libFuzzer)" OFF ) option( EXIV2_BUILD_DOC "Add 'doc' target to generate documentation" OFF ) # Only intended to be used by Exiv2 developers/contributors @@ -91,6 +92,14 @@ if( EXIV2_BUILD_UNIT_TESTS ) add_subdirectory ( unitTests ) endif() +if( EXIV2_BUILD_FUZZ_TESTS) + if ((NOT COMPILER_IS_CLANG) OR (NOT EXIV2_TEAM_USE_SANITIZERS)) + message(FATAL_ERROR "You need to build with Clang and sanitizers for the fuzzers to work. " + "Use Clang and -DEXIV2_TEAM_USE_SANITIZERS=ON") + endif() + add_subdirectory ( fuzz ) +endif() + if( EXIV2_BUILD_SAMPLES ) add_subdirectory( samples ) get_directory_property(SAMPLES DIRECTORY samples DEFINITION APPLICATIONS) diff --git a/README.md b/README.md index aa4dbe64..b7217b4d 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ The file ReadMe.txt in a build bundle describes how to install the library on th 3. [Unit tests](#4-3) 4. [Python tests](#4-4) 5. [Test Summary](#4-5) + 6. [Fuzzing](#4-6) 5. [Platform Notes](#5) 1. [Linux](#5-1) 2. [macOS](#5-2) @@ -1039,6 +1040,29 @@ $ cd /build $ make python_tests 2>&1 | grep FAIL ``` +### 4.6 Fuzzing + +The code for the fuzzers is in `exiv2dir/fuzz` + +To build the fuzzers, use the *cmake* option `-DEXIV2_BUILD_FUZZ_TESTS=ON` and `-DEXIV2_TEAM_USE_SANITIZERS=ON`. +Note that it only works with clang compiler as libFuzzer is integrate with clang > 6.0 + +To build the fuzzers: + +```bash +$ cd +$ rm -rf build-fuzz ; mkdir build-fuzz ; cd build-fuzz +$ cmake .. -DCMAKE_CXX_COMPILER=$(which clang++) -DEXIV2_BUILD_FUZZ_TESTS=ON -DEXIV2_TEAM_USE_SANITIZERS=ON +$ cmake --build . +``` + +To execute the fuzzers: + +```bash +cd /build-fuzz +bin/ # for example ./bin/read-metadata.cpp +``` + [TOC](#TOC)
diff --git a/cmake/printSummary.cmake b/cmake/printSummary.cmake index 15f9bbda..71e4a0cf 100644 --- a/cmake/printSummary.cmake +++ b/cmake/printSummary.cmake @@ -66,6 +66,7 @@ endif() OptionOutput( "Building exiv2 command: " EXIV2_BUILD_EXIV2_COMMAND ) OptionOutput( "Building samples: " EXIV2_BUILD_SAMPLES ) OptionOutput( "Building unit tests: " EXIV2_BUILD_UNIT_TESTS ) +OptionOutput( "Building fuzz tests: " EXIV2_BUILD_FUZZ_TESTS ) OptionOutput( "Building doc: " EXIV2_BUILD_DOC ) OptionOutput( "Building with coverage flags: " BUILD_WITH_COVERAGE ) OptionOutput( "Using ccache: " BUILD_WITH_CCACHE ) diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt new file mode 100644 index 00000000..281ff570 --- /dev/null +++ b/fuzz/CMakeLists.txt @@ -0,0 +1,14 @@ + +macro(fuzzer name) + add_executable(${name} ${name}.cpp) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "-fsanitize=fuzzer" + LINK_FLAGS "-fsanitize=fuzzer") + target_link_libraries(${name} + PRIVATE + exiv2lib + ) +endmacro() + +fuzzer(read-metadata) \ No newline at end of file diff --git a/fuzz/read-metadata.cpp b/fuzz/read-metadata.cpp new file mode 100644 index 00000000..9f0b5979 --- /dev/null +++ b/fuzz/read-metadata.cpp @@ -0,0 +1,24 @@ +#include + +#include +#include +#include + + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t * Data, size_t Size) +try { + Exiv2::Image::UniquePtr image = Exiv2::ImageFactory::open(Data, Size); + assert(image.get() != 0); + image->readMetadata(); + + Exiv2::ExifData &exifData = image->exifData(); + if (exifData.empty()) { + return -1; + } + + + return 0; +} +catch (Exiv2::Error& e) { + return -1; +}