From bb726bfde3f0d9bd6773365b8981f3b31eb8609c Mon Sep 17 00:00:00 2001 From: Matt Witherspoon <32485495+spoonincode@users.noreply.github.com> Date: Mon, 4 Dec 2023 16:28:49 -0500 Subject: [PATCH] security updates --- .../eosio/chain/contract_table_objects.hpp | 31 +++++++++++ .../include/eosio/chain/database_utils.hpp | 51 +++++++++++++++++++ .../eosio/state_history/serialization.hpp | 15 +++++- .../include/eosio/state_history/types.hpp | 8 ++- 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contract_table_objects.hpp index baf549a2b1..51c06d6812 100644 --- a/libraries/chain/include/eosio/chain/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contract_table_objects.hpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -282,6 +284,35 @@ namespace config { } // namespace config +namespace detail { + template<> + struct snapshot_row_traits { + using value_type = key_value_object; + using snapshot_type = snapshot_key_value_object; + + static snapshot_key_value_object to_snapshot_row(const key_value_object& value, const chainbase::database&) { + snapshot_key_value_object ret; + + ret.primary_key = value.primary_key; + ret.payer = value.payer; + if(value.value.size()) { + ret.value.resize(value.value.size()); + memcpy(ret.value.data(), value.value.data(), value.value.size()); + } + return ret; + }; + + static void from_snapshot_row(snapshot_key_value_object&& row, key_value_object& value, chainbase::database&) { + value.primary_key = row.primary_key; + value.payer = row.payer; + if(row.value.size()) + value.value.resize_and_fill(row.value.size(), [&](char* data, std::size_t size) { + memcpy(data, row.value.data(), size); + }); + } + }; +} + } } // namespace eosio::chain CHAINBASE_SET_INDEX_TYPE(eosio::chain::table_id_object, eosio::chain::table_id_multi_index) diff --git a/libraries/chain/include/eosio/chain/database_utils.hpp b/libraries/chain/include/eosio/chain/database_utils.hpp index b67d57e042..ef0a4802ff 100644 --- a/libraries/chain/include/eosio/chain/database_utils.hpp +++ b/libraries/chain/include/eosio/chain/database_utils.hpp @@ -91,6 +91,42 @@ namespace eosio { namespace chain { fc::raw::unpack(ds, static_cast(b)); return ds; } + +namespace detail { + struct snapshot_key_value_object { + template + friend Stream& operator>>(Stream& ds, snapshot_key_value_object& o) { + fc::raw::unpack(ds, o.primary_key); + fc::raw::unpack(ds, o.payer); + + fc::unsigned_int sz; + fc::raw::unpack(ds, sz); + if(sz) { + o.value.resize(sz); + ds.read(o.value.data(), sz); + } + + return ds; + } + + template + friend Stream& operator<<(Stream& ds, const snapshot_key_value_object& o) { + fc::raw::pack(ds, o.primary_key); + fc::raw::pack(ds, o.payer); + + fc::raw::pack(ds, fc::unsigned_int(o.value.size())); + if(o.value.size()) + ds.write(o.value.data(), o.value.size()); + + return ds; + } + + uint64_t primary_key; + account_name payer; + std::vector value; + }; +} + } } namespace fc { @@ -197,6 +233,21 @@ namespace fc { from_variant(v, _v); sv = eosio::chain::shared_vector(_v.begin(), _v.end(), sv.get_allocator()); } + + inline + void to_variant(const eosio::chain::detail::snapshot_key_value_object& a, fc::variant& v) { + v = fc::mutable_variant_object("primary_key", a.primary_key) + ("payer", a.payer) + ("value", base64_encode(a.value.data(), a.value.size())); + } + + inline + void from_variant(const fc::variant& v, eosio::chain::detail::snapshot_key_value_object& a) { + from_variant(v["primary_key"], a.primary_key); + from_variant(v["payer"], a.payer); + const std::string s = base64_decode(v["value"].as_string()); + a.value = std::vector(s.begin(), s.end()); + } } namespace chainbase { diff --git a/libraries/state_history/include/eosio/state_history/serialization.hpp b/libraries/state_history/include/eosio/state_history/serialization.hpp index 7e3cfc9ead..bb6151b78a 100644 --- a/libraries/state_history/include/eosio/state_history/serialization.hpp +++ b/libraries/state_history/include/eosio/state_history/serialization.hpp @@ -85,6 +85,13 @@ datastream& operator<<(datastream& ds, const eosio::state_history::big_v return ds; } +template +datastream& operator<<(datastream& ds, const eosio::state_history::row_pair& rp) { + fc::raw::pack(ds, rp.first); + history_pack_big_bytes(ds, rp.second); + return ds; +} + template inline void history_pack_varuint64(datastream& ds, uint64_t val) { do { @@ -102,6 +109,12 @@ void history_pack_big_bytes(datastream& ds, const eosio::chain::bytes& v) { ds.write(&v.front(), v.size()); } +template +void history_pack_big_bytes(datastream& ds, const eosio::chain::shared_blob& b) { + fc::raw::pack(ds, unsigned_int((uint32_t)b.size())); + ds.write(b.data(), b.size()); +} + template void history_pack_big_bytes(datastream& ds, const std::optional& v) { fc::raw::pack(ds, v.has_value()); @@ -182,7 +195,7 @@ operator<<(datastream& fc::raw::pack(ds, as_type(obj.context.table.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.primary_key)); fc::raw::pack(ds, as_type(obj.obj.payer.to_uint64_t())); - fc::raw::pack(ds, as_type(obj.obj.value)); + history_pack_big_bytes(ds, obj.obj.value); return ds; } diff --git a/libraries/state_history/include/eosio/state_history/types.hpp b/libraries/state_history/include/eosio/state_history/types.hpp index 7da5494636..a94bab4e68 100644 --- a/libraries/state_history/include/eosio/state_history/types.hpp +++ b/libraries/state_history/include/eosio/state_history/types.hpp @@ -17,6 +17,12 @@ struct big_vector_wrapper { T obj; }; +struct row_pair { + row_pair(const bool f, const bytes& s) : first(f), second(s){} + bool first = false; + bytes second; +}; + struct partial_transaction { fc::time_point_sec expiration = {}; uint16_t ref_block_num = {}; @@ -66,7 +72,7 @@ struct augmented_transaction_trace { struct table_delta { fc::unsigned_int struct_version = 0; std::string name{}; - state_history::big_vector_wrapper>> rows{}; + state_history::big_vector_wrapper> rows{}; }; struct block_position {