From c4369ae1d8955cae20c4ab40b9813ef4b60e48be Mon Sep 17 00:00:00 2001 From: tyler92 Date: Thu, 14 Nov 2024 14:08:35 +0200 Subject: [PATCH] fix stack overflow by limiting the maximum depth of dotted keys (#242) --- README.md | 3 ++- fuzzing/build.sh | 2 +- include/toml++/impl/parser.inl | 8 +++++++- include/toml++/impl/preprocessor.hpp | 4 ++++ toml.hpp | 12 +++++++++++- tools/generate_single_header.py | 1 + 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 88fcae69..e1935f0d 100644 --- a/README.md +++ b/README.md @@ -306,7 +306,8 @@ 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 +- **[@capuanob](https://github.com/capuanob)** - Integrated this project into OSSFuzz +- **[@tyler92]** - Fixed stack overflow that occurred during fuzzing tests
## Contact diff --git a/fuzzing/build.sh b/fuzzing/build.sh index cec20868..9c06e7dc 100755 --- a/fuzzing/build.sh +++ b/fuzzing/build.sh @@ -5,4 +5,4 @@ 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/* +zip -q -j $OUT/toml_fuzzer_seed_corpus.zip corpus/* diff --git a/include/toml++/impl/parser.inl b/include/toml++/impl/parser.inl index 3207e6b4..8f1124b8 100644 --- a/include/toml++/impl/parser.inl +++ b/include/toml++/impl/parser.inl @@ -1063,7 +1063,8 @@ TOML_IMPL_NAMESPACE_START class parser { private: - static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES; + static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES; + static constexpr size_t max_dotted_keys_depth = TOML_MAX_DOTTED_KEYS_DEPTH; utf8_buffered_reader reader; table root; @@ -3085,6 +3086,11 @@ TOML_IMPL_NAMESPACE_START // store segment key_buffer.push_back(key_segment, key_begin, key_end); + if TOML_UNLIKELY(key_buffer.size() > max_dotted_keys_depth) + set_error_and_return_default("exceeded maximum dotted keys depth of "sv, + max_dotted_keys_depth, + " (TOML_MAX_DOTTED_KEYS_DEPTH)"sv); + // eof or no more key to come if (is_eof() || *cp != U'.') break; diff --git a/include/toml++/impl/preprocessor.hpp b/include/toml++/impl/preprocessor.hpp index 0d61a663..7228db11 100644 --- a/include/toml++/impl/preprocessor.hpp +++ b/include/toml++/impl/preprocessor.hpp @@ -1182,6 +1182,10 @@ // 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... #endif +#ifndef TOML_MAX_DOTTED_KEYS_DEPTH +#define TOML_MAX_DOTTED_KEYS_DEPTH 1024 +#endif + #ifdef TOML_CHAR_8_STRINGS #if TOML_CHAR_8_STRINGS #error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly. diff --git a/toml.hpp b/toml.hpp index 1bb9d665..15662c1d 100644 --- a/toml.hpp +++ b/toml.hpp @@ -1091,6 +1091,10 @@ // 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... #endif +#ifndef TOML_MAX_DOTTED_KEYS_DEPTH +#define TOML_MAX_DOTTED_KEYS_DEPTH 1024 +#endif + #ifdef TOML_CHAR_8_STRINGS #if TOML_CHAR_8_STRINGS #error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly. @@ -13554,7 +13558,8 @@ TOML_IMPL_NAMESPACE_START class parser { private: - static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES; + static constexpr size_t max_nested_values = TOML_MAX_NESTED_VALUES; + static constexpr size_t max_dotted_keys_depth = TOML_MAX_DOTTED_KEYS_DEPTH; utf8_buffered_reader reader; table root; @@ -15575,6 +15580,11 @@ TOML_IMPL_NAMESPACE_START // store segment key_buffer.push_back(key_segment, key_begin, key_end); + if TOML_UNLIKELY(key_buffer.size() > max_dotted_keys_depth) + set_error_and_return_default("exceeded maximum dotted keys depth of "sv, + max_dotted_keys_depth, + " (TOML_MAX_DOTTED_KEYS_DEPTH)"sv); + // eof or no more key to come if (is_eof() || *cp != U'.') break; diff --git a/tools/generate_single_header.py b/tools/generate_single_header.py index 805836df..f2874896 100755 --- a/tools/generate_single_header.py +++ b/tools/generate_single_header.py @@ -231,6 +231,7 @@ def main(): r'TOML_LIB_PATCH', r'TOML_LIB_SINGLE_HEADER', r'TOML_MAX_NESTED_VALUES', + r'TOML_MAX_DOTTED_KEYS_DEPTH', r'TOML_NAMESPACE_END', r'TOML_NAMESPACE_START', r'TOML_OPTIONAL_TYPE',