From 89fe0e1c81718afe1882e526a2f0244e4dadae5c Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Wed, 6 Jan 2021 13:19:58 +0000 Subject: [PATCH] storages: overridable limits for loading portable_storage from binary --- .../include/storages/http_abstract_invoke.h | 7 ++- .../include/storages/levin_abstract_invoke2.h | 15 +++-- .../epee/include/storages/portable_storage.h | 15 ++++- .../storages/portable_storage_from_bin.h | 55 +++++++++++-------- .../portable_storage_template_helper.h | 4 +- 5 files changed, 63 insertions(+), 33 deletions(-) diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h index a8bc945a8..08ac4c2ca 100644 --- a/contrib/epee/include/storages/http_abstract_invoke.h +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -97,7 +97,12 @@ namespace epee return false; } - return serialization::load_t_from_binary(result_struct, epee::strspan(pri->m_body)); + static const constexpr epee::serialization::portable_storage::limits_t default_http_bin_limits = { + 65536 * 3, // objects + 65536 * 3, // fields + 65536 * 3, // strings + }; + return serialization::load_t_from_binary(result_struct, epee::strspan(pri->m_body), &default_http_bin_limits); } template diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h index cf1262486..e35ee30c5 100644 --- a/contrib/epee/include/storages/levin_abstract_invoke2.h +++ b/contrib/epee/include/storages/levin_abstract_invoke2.h @@ -50,6 +50,11 @@ namespace snprintf(buf, sizeof(buf), "command-%u", command); return on_levin_traffic(context, initiator, sent, error, bytes, buf); } + static const constexpr epee::serialization::portable_storage::limits_t default_levin_limits = { + 8192, // objects + 16384, // fields + 16384, // strings + }; } namespace epee @@ -75,7 +80,7 @@ namespace epee return false; } serialization::portable_storage stg_ret; - if(!stg_ret.load_from_binary(buff_to_recv)) + if(!stg_ret.load_from_binary(buff_to_recv, &default_levin_limits)) { LOG_ERROR("Failed to load_from_binary on command " << command); return false; @@ -121,7 +126,7 @@ namespace epee return false; } typename serialization::portable_storage stg_ret; - if(!stg_ret.load_from_binary(buff_to_recv)) + if(!stg_ret.load_from_binary(buff_to_recv, &default_levin_limits)) { on_levin_traffic(context, true, false, true, buff_to_recv.size(), command); LOG_ERROR("Failed to load_from_binary on command " << command); @@ -152,7 +157,7 @@ namespace epee return false; } serialization::portable_storage stg_ret; - if(!stg_ret.load_from_binary(buff)) + if(!stg_ret.load_from_binary(buff, &default_levin_limits)) { on_levin_traffic(context, true, false, true, buff.size(), command); LOG_ERROR("Failed to load_from_binary on command " << command); @@ -202,7 +207,7 @@ namespace epee int buff_to_t_adapter(int command, const epee::span in_buff, std::string& buff_out, callback_t cb, t_context& context ) { serialization::portable_storage strg; - if(!strg.load_from_binary(in_buff)) + if(!strg.load_from_binary(in_buff, &default_levin_limits)) { on_levin_traffic(context, false, false, true, in_buff.size(), command); LOG_ERROR("Failed to load_from_binary in command " << command); @@ -236,7 +241,7 @@ namespace epee int buff_to_t_adapter(t_owner* powner, int command, const epee::span in_buff, callback_t cb, t_context& context) { serialization::portable_storage strg; - if(!strg.load_from_binary(in_buff)) + if(!strg.load_from_binary(in_buff, &default_levin_limits)) { on_levin_traffic(context, false, false, true, in_buff.size(), command); LOG_ERROR("Failed to load_from_binary in notify " << command); diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h index 634af2d4e..1e68605ab 100644 --- a/contrib/epee/include/storages/portable_storage.h +++ b/contrib/epee/include/storages/portable_storage.h @@ -54,6 +54,13 @@ namespace epee typedef epee::serialization::harray harray; typedef storage_entry meta_entry; + struct limits_t + { + size_t n_objects; + size_t n_fields; + size_t n_strings; // not counting field names + }; + portable_storage(){} virtual ~portable_storage(){} hsection open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist = false); @@ -84,8 +91,8 @@ namespace epee //------------------------------------------------------------------------------- bool store_to_binary(binarybuffer& target); - bool load_from_binary(const epee::span target); - bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan(target)); } + bool load_from_binary(const epee::span target, const limits_t *limits = NULL); + bool load_from_binary(const std::string& target, const limits_t *limits = NULL) { return load_from_binary(epee::strspan(target), limits); } template bool dump_as_xml(std::string& targetObj, const std::string& root_name = ""); bool dump_as_json(std::string& targetObj, size_t indent = 0, bool insert_newlines = true); @@ -150,7 +157,7 @@ namespace epee CATCH_ENTRY("portable_storage::store_to_binary", false) } inline - bool portable_storage::load_from_binary(const epee::span source) + bool portable_storage::load_from_binary(const epee::span source, const limits_t *limits) { m_root.m_entries.clear(); if(source.size() < sizeof(storage_block_header)) @@ -173,6 +180,8 @@ namespace epee } TRY_ENTRY(); throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header)); + if (limits) + buf_reader.set_limits(limits->n_objects, limits->n_fields, limits->n_strings); buf_reader.read(m_root); return true;//TODO: CATCH_ENTRY("portable_storage::load_from_binary", false); diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h index 08aad4b77..a31a794da 100644 --- a/contrib/epee/include/storages/portable_storage_from_bin.h +++ b/contrib/epee/include/storages/portable_storage_from_bin.h @@ -37,9 +37,6 @@ #else #define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL 100 #endif -#define EPEE_PORTABLE_STORAGE_OBJECT_LIMIT_INTERNAL 65536 -#define EPEE_PORTABLE_STORAGE_OBJECT_FIELD_LIMIT_INTERNAL 65536 -#define EPEE_PORTABLE_STORAGE_STRING_LIMIT_INTERNAL 65536 // does not include field names namespace epee { @@ -48,21 +45,20 @@ namespace epee template struct ps_min_bytes { static constexpr const size_t strict = 4096; // actual low bound - static constexpr const size_t rough = 4096; // when we want to be stricter for DoS prevention }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 8, rough = 8; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 8, rough = 8; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 4, rough = 4; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 4, rough = 4; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 2, rough = 2; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 2, rough = 2; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 1, rough = 1; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 1, rough = 1; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 8, rough = 8; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 1, rough = 1; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 2, rough = 16; }; - template<> struct ps_min_bytes
{ static constexpr const size_t strict = 1, rough = 256; }; - template<> struct ps_min_bytes { static constexpr const size_t strict = 1, rough = 128; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 8; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 8; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 4; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 4; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 2; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 2; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 1; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 1; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 8; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 1; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 2; }; + template<> struct ps_min_bytes
{ static constexpr const size_t strict = 1; }; + template<> struct ps_min_bytes { static constexpr const size_t strict = 1; }; struct throwable_buffer_reader { @@ -85,6 +81,7 @@ namespace epee void read(array_entry &ae); template size_t min_bytes() const; + void set_limits(size_t objects, size_t fields, size_t strings); private: struct recursuion_limitation_guard { @@ -108,6 +105,10 @@ namespace epee size_t m_objects; size_t m_fields; size_t m_strings; + + size_t max_objects; + size_t max_fields; + size_t max_strings; }; inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz) @@ -122,6 +123,9 @@ namespace epee m_objects = 0; m_fields = 0; m_strings = 0; + max_objects = std::numeric_limits::max(); + max_fields = std::numeric_limits::max(); + max_strings = std::numeric_limits::max(); } inline void throwable_buffer_reader::read(void* target, size_t count) @@ -172,12 +176,12 @@ namespace epee CHECK_AND_ASSERT_THROW_MES(size <= m_count / ps_min_bytes::strict, "Size sanity check failed"); if (std::is_same()) { - CHECK_AND_ASSERT_THROW_MES(size <= EPEE_PORTABLE_STORAGE_OBJECT_LIMIT_INTERNAL - m_objects, "Too many objects"); + CHECK_AND_ASSERT_THROW_MES(size <= max_objects - m_objects, "Too many objects"); m_objects += size; } else if (std::is_same()) { - CHECK_AND_ASSERT_THROW_MES(size <= EPEE_PORTABLE_STORAGE_STRING_LIMIT_INTERNAL - m_strings, "Too many strings"); + CHECK_AND_ASSERT_THROW_MES(size <= max_strings - m_strings, "Too many strings"); m_strings += size; } @@ -246,7 +250,7 @@ namespace epee inline storage_entry throwable_buffer_reader::read_se() { RECURSION_LIMITATION(); - CHECK_AND_ASSERT_THROW_MES(m_strings + 1 <= EPEE_PORTABLE_STORAGE_STRING_LIMIT_INTERNAL, "Too many strings"); + CHECK_AND_ASSERT_THROW_MES(m_strings + 1 <= max_strings, "Too many strings"); m_strings += 1; return storage_entry(read()); } @@ -256,7 +260,7 @@ namespace epee inline storage_entry throwable_buffer_reader::read_se
() { RECURSION_LIMITATION(); - CHECK_AND_ASSERT_THROW_MES(m_objects < EPEE_PORTABLE_STORAGE_OBJECT_LIMIT_INTERNAL, "Too many objects"); + CHECK_AND_ASSERT_THROW_MES(m_objects < max_objects, "Too many objects"); ++m_objects; section s;//use extra variable due to vs bug, line "storage_entry se(section()); " can't be compiled in visual studio storage_entry se(std::move(s)); @@ -309,7 +313,7 @@ namespace epee RECURSION_LIMITATION(); sec.m_entries.clear(); size_t count = read_varint(); - CHECK_AND_ASSERT_THROW_MES(count <= EPEE_PORTABLE_STORAGE_OBJECT_FIELD_LIMIT_INTERNAL - m_fields, "Too many object fields"); + CHECK_AND_ASSERT_THROW_MES(count <= max_fields - m_fields, "Too many object fields"); m_fields += count; while(count--) { @@ -339,5 +343,12 @@ namespace epee RECURSION_LIMITATION(); CHECK_AND_ASSERT_THROW_MES(false, "Reading array entry is not supported"); } + inline + void throwable_buffer_reader::set_limits(size_t objects, size_t fields, size_t strings) + { + max_objects = objects; + max_fields = fields; + max_strings = strings; + } } } diff --git a/contrib/epee/include/storages/portable_storage_template_helper.h b/contrib/epee/include/storages/portable_storage_template_helper.h index 13c870d44..de6acfed8 100644 --- a/contrib/epee/include/storages/portable_storage_template_helper.h +++ b/contrib/epee/include/storages/portable_storage_template_helper.h @@ -84,10 +84,10 @@ namespace epee } //----------------------------------------------------------------------------------------------------------- template - bool load_t_from_binary(t_struct& out, const epee::span binary_buff) + bool load_t_from_binary(t_struct& out, const epee::span binary_buff, const epee::serialization::portable_storage::limits_t *limits = NULL) { portable_storage ps; - bool rs = ps.load_from_binary(binary_buff); + bool rs = ps.load_from_binary(binary_buff, limits); if(!rs) return false;