From 2d4d0d352f815d0d99dd8cf8d4ce554e33fc446c Mon Sep 17 00:00:00 2001 From: arhag Date: Thu, 28 Feb 2019 13:26:50 -0500 Subject: [PATCH] initial work on #6437 --- libraries/chain/CMakeLists.txt | 1 + libraries/chain/controller.cpp | 8 +- libraries/chain/genesis_intrinsics.cpp | 231 ++++++++++++++++++ .../eosio/chain/genesis_intrinsics.hpp | 14 ++ .../eosio/chain/global_property_object.hpp | 35 ++- libraries/chain/include/eosio/chain/types.hpp | 4 +- .../include/eosio/chain/wasm_interface.hpp | 68 ++++-- libraries/chain/wasm_interface.cpp | 4 +- libraries/fc | 2 +- 9 files changed, 334 insertions(+), 33 deletions(-) create mode 100644 libraries/chain/genesis_intrinsics.cpp create mode 100644 libraries/chain/include/eosio/chain/genesis_intrinsics.hpp diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 52b4181a030..c2a28f9aaa8 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -49,6 +49,7 @@ add_library( eosio_chain transaction_metadata.cpp protocol_feature_activation.cpp protocol_feature_manager.cpp + genesis_intrinsics.cpp ${HEADERS} ) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 41d8c156a1f..e68ad4c2a8a 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -792,12 +793,15 @@ struct controller_impl { const auto& tapos_block_summary = db.get(1); db.modify( tapos_block_summary, [&]( auto& bs ) { - bs.block_id = head->id; + bs.block_id = head->id; }); conf.genesis.initial_configuration.validate(); db.create([&](auto& gpo ){ - gpo.configuration = conf.genesis.initial_configuration; + gpo.configuration = conf.genesis.initial_configuration; + for( const auto& i : genesis_intrinsics ) { + gpo.add_intrinsic_to_whitelist( i ); + } }); db.create([](auto&){}); diff --git a/libraries/chain/genesis_intrinsics.cpp b/libraries/chain/genesis_intrinsics.cpp new file mode 100644 index 00000000000..a40010f7586 --- /dev/null +++ b/libraries/chain/genesis_intrinsics.cpp @@ -0,0 +1,231 @@ +/** + * @file + * @copyright defined in eos/LICENSE + */ + +#include + +namespace eosio { namespace chain { + +const std::vector genesis_intrinsics = { + "__ashrti3", + "__lshlti3", + "__lshrti3", + "__ashlti3", + "__divti3", + "__udivti3", + "__modti3", + "__umodti3", + "__multi3", + "__addtf3", + "__subtf3", + "__multf3", + "__divtf3", + "__eqtf2", + "__netf2", + "__getf2", + "__gttf2", + "__lttf2", + "__letf2", + "__cmptf2", + "__unordtf2", + "__negtf2", + "__floatsitf", + "__floatunsitf", + "__floatditf", + "__floatunditf", + "__floattidf", + "__floatuntidf", + "__floatsidf", + "__extendsftf2", + "__extenddftf2", + "__fixtfti", + "__fixtfdi", + "__fixtfsi", + "__fixunstfti", + "__fixunstfdi", + "__fixunstfsi", + "__fixsfti", + "__fixdfti", + "__fixunssfti", + "__fixunsdfti", + "__trunctfdf2", + "__trunctfsf2", + "is_feature_active", + "activate_feature", + "get_resource_limits", + "set_resource_limits", + "set_proposed_producers", + "get_blockchain_parameters_packed", + "set_blockchain_parameters_packed", + "is_privileged", + "set_privileged", + "get_active_producers", + "db_idx64_store", + "db_idx64_remove", + "db_idx64_update", + "db_idx64_find_primary", + "db_idx64_find_secondary", + "db_idx64_lowerbound", + "db_idx64_upperbound", + "db_idx64_end", + "db_idx64_next", + "db_idx64_previous", + "db_idx128_store", + "db_idx128_remove", + "db_idx128_update", + "db_idx128_find_primary", + "db_idx128_find_secondary", + "db_idx128_lowerbound", + "db_idx128_upperbound", + "db_idx128_end", + "db_idx128_next", + "db_idx128_previous", + "db_idx256_store", + "db_idx256_remove", + "db_idx256_update", + "db_idx256_find_primary", + "db_idx256_find_secondary", + "db_idx256_lowerbound", + "db_idx256_upperbound", + "db_idx256_end", + "db_idx256_next", + "db_idx256_previous", + "db_idx_double_store", + "db_idx_double_remove", + "db_idx_double_update", + "db_idx_double_find_primary", + "db_idx_double_find_secondary", + "db_idx_double_lowerbound", + "db_idx_double_upperbound", + "db_idx_double_end", + "db_idx_double_next", + "db_idx_double_previous", + "db_idx_long_double_store", + "db_idx_long_double_remove", + "db_idx_long_double_update", + "db_idx_long_double_find_primary", + "db_idx_long_double_find_secondary", + "db_idx_long_double_lowerbound", + "db_idx_long_double_upperbound", + "db_idx_long_double_end", + "db_idx_long_double_next", + "db_idx_long_double_previous", + "db_idx64_store", + "db_idx64_remove", + "db_idx64_update", + "db_idx64_find_primary", + "db_idx64_find_secondary", + "db_idx64_lowerbound", + "db_idx64_upperbound", + "db_idx64_end", + "db_idx64_next", + "db_idx64_previous", + "db_idx128_store", + "db_idx128_remove", + "db_idx128_update", + "db_idx128_find_primary", + "db_idx128_find_secondary", + "db_idx128_lowerbound", + "db_idx128_upperbound", + "db_idx128_end", + "db_idx128_next", + "db_idx128_previous", + "db_idx256_store", + "db_idx256_remove", + "db_idx256_update", + "db_idx256_find_primary", + "db_idx256_find_secondary", + "db_idx256_lowerbound", + "db_idx256_upperbound", + "db_idx256_end", + "db_idx256_next", + "db_idx256_previous", + "db_idx_double_store", + "db_idx_double_remove", + "db_idx_double_update", + "db_idx_double_find_primary", + "db_idx_double_find_secondary", + "db_idx_double_lowerbound", + "db_idx_double_upperbound", + "db_idx_double_end", + "db_idx_double_next", + "db_idx_double_previous", + "db_idx_long_double_store", + "db_idx_long_double_remove", + "db_idx_long_double_update", + "db_idx_long_double_find_primary", + "db_idx_long_double_find_secondary", + "db_idx_long_double_lowerbound", + "db_idx_long_double_upperbound", + "db_idx_long_double_end", + "db_idx_long_double_next", + "db_idx_long_double_previous", + "db_store_i64", + "db_update_i64", + "db_remove_i64", + "db_get_i64", + "db_next_i64", + "db_previous_i64", + "db_find_i64", + "db_lowerbound_i64", + "db_upperbound_i64", + "db_end_i64", + "assert_recover_key", + "recover_key", + "assert_sha256", + "assert_sha1", + "assert_sha512", + "assert_ripemd160", + "sha1", + "sha256", + "sha512", + "ripemd160", + "check_transaction_authorization", + "check_permission_authorization", + "get_permission_last_used", + "get_account_creation_time", + "current_time", + "publication_time", + "abort", + "eosio_assert", + "eosio_assert_message", + "eosio_assert_code", + "eosio_exit", + "read_action_data", + "action_data_size", + "current_receiver", + "require_recipient", + "require_auth", + "require_auth2", + "has_auth", + "is_account", + "prints", + "prints_l", + "printi", + "printui", + "printi128", + "printui128", + "printsf", + "printdf", + "printqf", + "printn", + "printhex", + "read_transaction", + "transaction_size", + "expiration", + "tapos_block_prefix", + "tapos_block_num", + "get_action", + "send_inline", + "send_context_free_inline", + "send_deferred", + "cancel_deferred", + "get_context_free_data", + "memcpy", + "memmove", + "memcmp", + "memset" +}; + +} } // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/genesis_intrinsics.hpp b/libraries/chain/include/eosio/chain/genesis_intrinsics.hpp new file mode 100644 index 00000000000..bd736d6a285 --- /dev/null +++ b/libraries/chain/include/eosio/chain/genesis_intrinsics.hpp @@ -0,0 +1,14 @@ + +/** + * @file + * @copyright defined in eos/LICENSE + */ +#pragma once + +#include + +namespace eosio { namespace chain { + +extern const std::vector genesis_intrinsics; + +} } // namespace eosio::chain diff --git a/libraries/chain/include/eosio/chain/global_property_object.hpp b/libraries/chain/include/eosio/chain/global_property_object.hpp index e513045c0b2..0f9579b48a7 100644 --- a/libraries/chain/include/eosio/chain/global_property_object.hpp +++ b/libraries/chain/include/eosio/chain/global_property_object.hpp @@ -26,13 +26,33 @@ namespace eosio { namespace chain { */ class global_property_object : public chainbase::object { - OBJECT_CTOR(global_property_object, (proposed_schedule)(preactivated_protocol_features)) + OBJECT_CTOR(global_property_object, (proposed_schedule)(preactivated_protocol_features)(whitelisted_intrinsics)) - id_type id; - optional proposed_schedule_block_num; - shared_producer_schedule_type proposed_schedule; - chain_config configuration; - shared_vector preactivated_protocol_features; + public: + + inline void add_intrinsic_to_whitelist( const char* name ) { + uint64_t h = static_cast( std::hash{}( std::string(name) ) ); + whitelisted_intrinsics.emplace( std::piecewise_construct, + std::forward_as_tuple( h ), + std::forward_as_tuple( name, whitelisted_intrinsics.get_allocator() ) + ); + } + + inline void add_intrinsic_to_whitelist( const std::string& name ) { + uint64_t h = static_cast( std::hash{}( name ) ); + whitelisted_intrinsics.emplace( std::piecewise_construct, + std::forward_as_tuple( h ), + std::forward_as_tuple( name.c_str(), name.size(), + whitelisted_intrinsics.get_allocator() ) + ); + } + + id_type id; + optional proposed_schedule_block_num; + shared_producer_schedule_type proposed_schedule; + chain_config configuration; + shared_vector preactivated_protocol_features; + shared_flat_multimap whitelisted_intrinsics; }; @@ -83,5 +103,6 @@ FC_REFLECT(eosio::chain::dynamic_global_property_object, ) FC_REFLECT(eosio::chain::global_property_object, - (proposed_schedule_block_num)(proposed_schedule)(configuration)(preactivated_protocol_features) + (proposed_schedule_block_num)(proposed_schedule)(configuration) + (preactivated_protocol_features)(whitelisted_intrinsics) ) diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index e3608cbad87..5ce7bf87550 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -8,7 +8,7 @@ #include -#include +#include #include #include #include @@ -95,6 +95,8 @@ namespace eosio { namespace chain { using shared_vector = boost::interprocess::vector>; template using shared_set = boost::interprocess::set, allocator>; + template + using shared_flat_multimap = boost::interprocess::flat_multimap< K, V, std::less, allocator< std::pair > >; /** * For bugs in boost interprocess we moved our blob data to shared_string diff --git a/libraries/chain/include/eosio/chain/wasm_interface.hpp b/libraries/chain/include/eosio/chain/wasm_interface.hpp index 7e6991996af..38c6b82c063 100644 --- a/libraries/chain/include/eosio/chain/wasm_interface.hpp +++ b/libraries/chain/include/eosio/chain/wasm_interface.hpp @@ -17,31 +17,57 @@ namespace eosio { namespace chain { namespace webassembly { namespace common { class intrinsics_accessor; - struct root_resolver : Runtime::Resolver { - //when validating is true; only allow "env" imports. Otherwise allow any imports. This resolver is used - //in two cases: once by the generic validating code where we only want "env" to pass; and then second in the - //wavm runtime where we need to allow linkage to injected functions - root_resolver(bool validating = false) : validating(validating) {} - bool validating; + class root_resolver : public Runtime::Resolver { + public: + // The non-default constructor puts root_resolver in a mode where it does validation, i.e. only allows "env" imports. + // This mode is used by the generic validating code that runs during setcode, where we only want "env" to pass. + // The default constructor is used when no validation is required such as when the wavm runtime needs to + // allow linkage to the intrinsics and the injected functions. + + root_resolver() {} + + root_resolver( const shared_flat_multimap& whitelisted_intrinsics ) + :whitelisted_intrinsics(&whitelisted_intrinsics) + {} bool resolve(const string& mod_name, const string& export_name, IR::ObjectType type, - Runtime::ObjectInstance*& out) override { - try { - //protect access to "private" injected functions; so for now just simply allow "env" since injected functions - // are in a different module - if(validating && mod_name != "env") - EOS_ASSERT( false, wasm_exception, "importing from module that is not 'env': ${module}.${export}", ("module",mod_name)("export",export_name) ); - - // Try to resolve an intrinsic first. - if(Runtime::IntrinsicResolver::singleton.resolve(mod_name,export_name,type, out)) { - return true; - } - - EOS_ASSERT( false, wasm_exception, "${module}.${export} unresolveable", ("module",mod_name)("export",export_name) ); - return false; - } FC_CAPTURE_AND_RETHROW( (mod_name)(export_name) ) } + Runtime::ObjectInstance*& out) override + { try { + bool fail = false; + + if( whitelisted_intrinsics != nullptr ) { + // Protect access to "private" injected functions; so for now just simply allow "env" since injected + // functions are in a different module. + EOS_ASSERT( mod_name == "env", wasm_exception, + "importing from module that is not 'env': ${module}.${export}", + ("module",mod_name)("export",export_name) ); + + // Only consider imports that are in the whitelisted set of intrinsics: + uint64_t hash = static_cast( std::hash{}( export_name ) ); + auto itr = whitelisted_intrinsics->lower_bound( hash ); + fail = true; + for( const auto end = whitelisted_intrinsics->end(); itr != end && itr->first == hash; ++itr ) { + if( itr->second.compare( 0, itr->second.size(), export_name.c_str(), export_name.size() ) == 0 ) { + fail = false; + break; + } + } + } + + // Try to resolve an intrinsic first. + if( !fail && Runtime::IntrinsicResolver::singleton.resolve( mod_name, export_name, type, out ) ) { + return true; + } + + EOS_THROW( wasm_exception, "${module}.${export} unresolveable", + ("module",mod_name)("export",export_name) ); + return false; + } FC_CAPTURE_AND_RETHROW( (mod_name)(export_name) ) } + + protected: + const shared_flat_multimap* whitelisted_intrinsics = nullptr; }; } } diff --git a/libraries/chain/wasm_interface.cpp b/libraries/chain/wasm_interface.cpp index 74af3b88ee5..9fcec326724 100644 --- a/libraries/chain/wasm_interface.cpp +++ b/libraries/chain/wasm_interface.cpp @@ -46,7 +46,9 @@ namespace eosio { namespace chain { wasm_validations::wasm_binary_validation validator(control, module); validator.validate(); - root_resolver resolver(true); + const auto& gpo = control.db().get(); + + root_resolver resolver( gpo.whitelisted_intrinsics ); LinkResult link_result = linkModule(module, resolver); //there are a couple opportunties for improvement here-- diff --git a/libraries/fc b/libraries/fc index 12956c33041..972200d002d 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 12956c330413e69bd998cd0657c8a82ef3e8a106 +Subproject commit 972200d002d7ca2eba52095168745ff5f3a20912