From 8e214ec4116d1458efae934b66cf8986a65905f1 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Thu, 4 Jan 2024 20:45:35 +0900 Subject: [PATCH] fix: limit value recursion in array/inl-table to avoid parse_value/parse_array recursion --- toml/literal.hpp | 2 +- toml/parser.hpp | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/toml/literal.hpp b/toml/literal.hpp index 04fbbc1..5086a76 100644 --- a/toml/literal.hpp +++ b/toml/literal.hpp @@ -53,7 +53,7 @@ literal_internal_impl(::toml::detail::location loc) // If it is neither a table-key or a array-of-table-key, it may be a value. if(!is_table_key && !is_aots_key) { - if(auto data = ::toml::detail::parse_value(loc)) + if(auto data = ::toml::detail::parse_value(loc, 0)) { return data.unwrap(); } diff --git a/toml/parser.hpp b/toml/parser.hpp index 497d5a2..9c1a83e 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -8,6 +8,7 @@ #include "combinator.hpp" #include "lexer.hpp" +#include "macros.hpp" #include "region.hpp" #include "result.hpp" #include "types.hpp" @@ -22,6 +23,8 @@ #endif // __cpp_lib_filesystem #endif // TOML11_DISABLE_STD_FILESYSTEM +#define TOML11_VALUE_RECURSION_LIMIT 64 + namespace toml { namespace detail @@ -1138,15 +1141,23 @@ parse_key(location& loc) // forward-decl to implement parse_array and parse_table template -result parse_value(location&); +result parse_value(location&, const std::size_t n_rec); template result, std::string> -parse_array(location& loc) +parse_array(location& loc, const std::size_t n_rec) { using value_type = Value; using array_type = typename value_type::array_type; + if(n_rec > TOML11_VALUE_RECURSION_LIMIT) + { + // parse_array does not have any way to handle recursive error currently... + throw syntax_error(std::string("toml::parse_array: recursion limit (" + TOML11_STRINGIZE(TOML11_VALUE_RECURSION_LIMIT) ") exceeded"), + source_location(loc)); + } + const auto first = loc.iter(); if(loc.iter() == loc.end()) { @@ -1173,7 +1184,7 @@ parse_array(location& loc) region(loc, first, loc.iter()))); } - if(auto val = parse_value(loc)) + if(auto val = parse_value(loc, n_rec+1)) { // After TOML v1.0.0-rc.1, array becomes to be able to have values // with different types. So here we will omit this by default. @@ -1247,7 +1258,7 @@ parse_array(location& loc) template result, region>, Value>, std::string> -parse_key_value_pair(location& loc) +parse_key_value_pair(location& loc, const std::size_t n_rec) { using value_type = Value; @@ -1294,7 +1305,7 @@ parse_key_value_pair(location& loc) } const auto after_kvsp = loc.iter(); // err msg - auto val = parse_value(loc); + auto val = parse_value(loc, n_rec); if(!val) { std::string msg; @@ -1341,7 +1352,7 @@ result, region>, std::string> parse_array_table_key(location& loc); template result, std::string> -parse_inline_table(location& loc); +parse_inline_table(location& loc, const std::size_t n_rec); // The following toml file is allowed. // ```toml @@ -1379,7 +1390,7 @@ bool is_valid_forward_table_definition(const Value& fwd, const Value& inserting, inserting_reg = ptr->str(); } location inserting_def("internal", std::move(inserting_reg)); - if(const auto inlinetable = parse_inline_table(inserting_def)) + if(const auto inlinetable = parse_inline_table(inserting_def, 0)) { // check if we are overwriting existing table. // ```toml @@ -1810,11 +1821,18 @@ insert_nested_key(typename Value::table_type& root, const Value& v, template result, std::string> -parse_inline_table(location& loc) +parse_inline_table(location& loc, const std::size_t n_rec) { using value_type = Value; using table_type = typename value_type::table_type; + if(n_rec > TOML11_VALUE_RECURSION_LIMIT) + { + throw syntax_error(std::string("toml::parse_inline_table: recursion limit (" + TOML11_STRINGIZE(TOML11_VALUE_RECURSION_LIMIT) ") exceeded"), + source_location(loc)); + } + const auto first = loc.iter(); table_type retval; if(!(loc.iter() != loc.end() && *loc.iter() == '{')) @@ -1835,7 +1853,7 @@ parse_inline_table(location& loc) // it starts from "{". it should be formatted as inline-table while(loc.iter() != loc.end()) { - const auto kv_r = parse_key_value_pair(loc); + const auto kv_r = parse_key_value_pair(loc, n_rec+1); if(!kv_r) { return err(kv_r.unwrap_err()); @@ -2079,7 +2097,7 @@ parse_value_helper(result, std::string> rslt) } template -result parse_value(location& loc) +result parse_value(location& loc, const std::size_t n_rec) { const auto first = loc.iter(); if(first == loc.end()) @@ -2104,8 +2122,8 @@ result parse_value(location& loc) case value_t::local_datetime : {return parse_value_helper(parse_local_datetime(loc) );} case value_t::local_date : {return parse_value_helper(parse_local_date(loc) );} case value_t::local_time : {return parse_value_helper(parse_local_time(loc) );} - case value_t::array : {return parse_value_helper(parse_array(loc) );} - case value_t::table : {return parse_value_helper(parse_inline_table(loc));} + case value_t::array : {return parse_value_helper(parse_array(loc, n_rec));} + case value_t::table : {return parse_value_helper(parse_inline_table(loc, n_rec));} default: { const auto msg = format_underline("toml::parse_value: " @@ -2270,7 +2288,7 @@ parse_ml_table(location& loc) return ok(tab); } - if(const auto kv = parse_key_value_pair(loc)) + if(const auto kv = parse_key_value_pair(loc, 0)) { const auto& kvpair = kv.unwrap(); const std::vector& keys = kvpair.first.first;