diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml new file mode 100644 index 0000000..eea8fb7 --- /dev/null +++ b/.github/workflows/cifuzz.yml @@ -0,0 +1,39 @@ +name: CIFuzz +on: + push: + branches: + - master + pull_request: +permissions: {} +jobs: + Fuzzing: + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Build Fuzzers + id: build + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'tomlplusplus' + language: c++ + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'tomlplusplus' + language: c++ + fuzz-seconds: 800 + output-sarif: true + - name: Upload Crash + uses: actions/upload-artifact@v3 + if: failure() && steps.build.outcome == 'success' + with: + name: artifacts + path: ./out/artifacts + - name: Upload Sarif + if: always() && steps.build.outcome == 'success' + uses: github/codeql-action/upload-sarif@v2 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: cifuzz-sarif/results.sarif + checkout_path: cifuzz-sarif diff --git a/CMakeLists.txt b/CMakeLists.txt index bfef032..a913cdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,11 +30,15 @@ target_include_directories( target_compile_features(tomlplusplus_tomlplusplus INTERFACE cxx_std_17) -# ---- Install rules and examples ---- +# ---- Install rules, examples, and fuzzing ---- if(PROJECT_IS_TOP_LEVEL) include(cmake/install-rules.cmake) option(BUILD_EXAMPLES "Build examples tree." OFF) + option(BUILD_FUZZER "Build fuzzer." OFF) if(BUILD_EXAMPLES) add_subdirectory(examples) endif() + if(BUILD_FUZZER AND DEFINED ENV{LIB_FUZZING_ENGINE}) + add_subdirectory(fuzzing) + endif() endif() diff --git a/README.md b/README.md index be589c3..e3b8f3f 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,7 @@ UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[ - **[@whiterabbit963](https://github.com/whiterabbit963)** - Fixed a bug with value_or conversions - **[@ximion](https://github.com/ximion)** - Added support for installation with meson - **[@a-is](https://github.com/a-is)** - Fixed a bug - + -**[@capuanob](https://github.com/capuanob)** - Integrated this project into OSSFuzz
## Contact diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt new file mode 100644 index 0000000..1e62a54 --- /dev/null +++ b/fuzzing/CMakeLists.txt @@ -0,0 +1,31 @@ +# Utilized by OSSFuzz to build the harness(es) for continuous fuzz-testing +# OSSFuzz defines the following environment variables, that this target relies upon: +# CXX, CFLAGS, LIB_FUZZING_ENGINE, OUT +cmake_minimum_required(VERSION 3.14) + +project(Fuzzer LANGUAGES CXX) + +include(../cmake/project-is-top-level.cmake) + +add_definitions(-DNDEBUG) # Do not want assertions + +if (DEFINED ENV{CFLAGS}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} $ENV{CFLAGS}") +endif () +if (DEFINED ENV{CXXFLAGS}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} $ENV{CXXFLAGS}") +endif () + +if(PROJECT_IS_TOP_LEVEL) + find_package(tomlplusplus REQUIRED) +endif() + +add_executable(toml_fuzzer toml_fuzzer.cpp) +target_link_libraries(toml_fuzzer PRIVATE tomlplusplus::tomlplusplus $ENV{LIB_FUZZING_ENGINE}) +target_compile_features(toml_fuzzer PRIVATE cxx_std_17) + +if (DEFINED ENV{OUT}) + install(TARGETS toml_fuzzer DESTINATION $ENV{OUT}) +else () + message(WARNING "Cannot install if $OUT is not defined!") +endif () \ No newline at end of file diff --git a/fuzzing/build.sh b/fuzzing/build.sh new file mode 100755 index 0000000..cec2086 --- /dev/null +++ b/fuzzing/build.sh @@ -0,0 +1,8 @@ +cd $SRC/tomlplusplus +mkdir -p build +cmake -S . -B build -DBUILD_FUZZER=ON && cmake --build build --target install + +# Build the corpus using the existing toml files in the source +mkdir -p corpus +find $SRC/tomlplusplus -name "*.toml" -exec cp {} corpus \; +zip -q $OUT/toml_fuzzer_seed_corpus.zip corpus/* diff --git a/fuzzing/toml_fuzzer.cpp b/fuzzing/toml_fuzzer.cpp new file mode 100644 index 0000000..654e857 --- /dev/null +++ b/fuzzing/toml_fuzzer.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include + +enum class SerializationTest +{ + NONE = 0, + JSON, + YAML, + TOML, + kMaxValue = YAML +}; + +extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, const std::size_t size) +{ + FuzzedDataProvider fdp{data, size}; + try + { + const toml::table tbl = toml::parse(fdp.ConsumeRandomLengthString()); + + switch (fdp.ConsumeEnum()) + { + case SerializationTest::JSON: + static_cast(toml::json_formatter{tbl}); + break; + case SerializationTest::YAML: + static_cast(toml::yaml_formatter{tbl}); + break; + case SerializationTest::TOML: + static_cast(toml::toml_formatter{tbl}); + default: + break; + } + } + catch (const toml::parse_error&) + { + return -1; + } + return 0; +}