From b19649478c614afdbd8c7bb91f00e3da14266657 Mon Sep 17 00:00:00 2001
From: Bailey Capuano <32396237+capuanob@users.noreply.github.com>
Date: Sun, 19 Nov 2023 07:40:31 -0500
Subject: [PATCH] OSSFuzz integration (#214)
---
.github/workflows/cifuzz.yml | 39 ++++++++++++++++++++++++++++++++++
CMakeLists.txt | 6 +++++-
README.md | 2 +-
fuzzing/CMakeLists.txt | 31 +++++++++++++++++++++++++++
fuzzing/build.sh | 8 +++++++
fuzzing/toml_fuzzer.cpp | 41 ++++++++++++++++++++++++++++++++++++
6 files changed, 125 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/cifuzz.yml
create mode 100644 fuzzing/CMakeLists.txt
create mode 100755 fuzzing/build.sh
create mode 100644 fuzzing/toml_fuzzer.cpp
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
new file mode 100644
index 00000000..eea8fb79
--- /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 bfef0322..a913cdc5 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 be589c30..e3b8f3f6 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 00000000..1e62a54a
--- /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 00000000..cec20868
--- /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 00000000..654e8574
--- /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;
+}