Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Nonprivileged inline action subjective limit #9262

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bc4308a
Add subjective limit to inline transaction size for nonprivileged
jgiszczak Jun 22, 2020
7656593
Move new inline limit from global property to plugin option.
jgiszczak Jun 29, 2020
37e38a7
Address review comments.
jgiszczak Jun 30, 2020
546fffe
Remove new test file and adjust existing inline action test.
jgiszczak Jul 1, 2020
2db6cce
Revert spurious whitespace changes in genesis_state.hpp.
jgiszczak Jul 1, 2020
d8ffb58
Revert structure name change in state history abi.
jgiszczak Jul 2, 2020
96032bb
Avoid breaking consensus while checking nonprivileged inline size
jgiszczak Jul 2, 2020
4364f49
Eliminate redundant condition check.
jgiszczak Jul 2, 2020
2963e9b
Added plumbing to be able to set max_inline_action_size to be able to…
brianjohnson5972 Jul 6, 2020
c557584
Use the new plumbing to not use default values for default_max_inline…
brianjohnson5972 Jul 6, 2020
bb6c5cf
Apply subjective limit on inline actions even skipping auth checks
jgiszczak Jul 6, 2020
411048a
Apply subjective limit to context free actions as well.
jgiszczak Jul 7, 2020
d7570f7
Added plumbing to set max_nonprivileged_inline_action_size.
brianjohnson5972 Jul 8, 2020
1c8ffc3
Added send_action_4k action.
brianjohnson5972 Jul 8, 2020
19bb2a0
Added tests for subjective and objective limits.
brianjohnson5972 Jul 8, 2020
54d69e7
Added comments
brianjohnson5972 Jul 8, 2020
cad1691
Added send_deferred_transaction_4k_action action to contract.
brianjohnson5972 Jul 8, 2020
a1b5baa
Added verification that nonprivileged action size limit is enforced s…
brianjohnson5972 Jul 8, 2020
c3f8dd5
Used BOOST_CHECK_EXCEPTION.
brianjohnson5972 Jul 8, 2020
320850d
Revert eventually spurious whitespace changes to chain_config.hpp
jgiszczak Jul 8, 2020
c00dafb
Merge branch 'nonprivileged-inline-action-subjective-limit' of github…
jgiszczak Jul 8, 2020
403d6d2
Remove and correct some comments.
jgiszczak Jul 8, 2020
bacaa7a
Remove one more invalid comment and clarify tester param name
jgiszczak Jul 8, 2020
05a61a0
Made variable name appropriate.
brianjohnson5972 Jul 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions libraries/chain/abi_serializer.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/chain_config.hpp>
#include <eosio/chain/transaction.hpp>
#include <eosio/chain/asset.hpp>
#include <eosio/chain/exceptions.hpp>
#include <fc/io/raw.hpp>
Expand Down
10 changes: 7 additions & 3 deletions libraries/chain/apply_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,12 @@ void apply_context::require_recipient( account_name recipient ) {
* implicitly authorized by the current receiver (running code). This method has significant
* security considerations and several options have been considered:
*
* 1. priviledged accounts (those marked as such by block producers) can authorize any action
* 1. privileged accounts (those marked as such by block producers) can authorize any action
* 2. all other actions are only authorized by 'receiver' which means the following:
* a. the user must set permissions on their account to allow the 'receiver' to act on their behalf
*
* Discarded Implemenation: at one point we allowed any account that authorized the current transaction
* to implicitly authorize an inline transaction. This approach would allow privelege escalation and
* Discarded Implementation: at one point we allowed any account that authorized the current transaction
* to implicitly authorize an inline transaction. This approach would allow privilege escalation and
* make it unsafe for users to interact with certain contracts. We opted instead to have applications
* ask the user for permission to take certain actions rather than making it implicit. This way users
* can better understand the security risk.
Expand Down Expand Up @@ -290,6 +290,10 @@ void apply_context::execute_inline( action&& a ) {

// No need to check authorization if replaying irreversible blocks or contract is privileged
if( !control.skip_auth_check() && !privileged ) {
const auto& chain_config = control.get_global_properties().configuration;
EOS_ASSERT( a.data.size() < std::min(chain_config.max_inline_action_size, control.get_max_nonprivileged_inline_action_size()),
inline_action_too_big_nonprivileged,
"inline action too big for nonprivileged account ${account}", ("account", a.account));
heifner marked this conversation as resolved.
Show resolved Hide resolved
try {
control.get_authorization_manager()
.check_authorization( {a},
Expand Down
8 changes: 7 additions & 1 deletion libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,7 +1188,8 @@ struct controller_impl {
|| (code == contract_blacklist_exception::code_value)
|| (code == action_blacklist_exception::code_value)
|| (code == key_blacklist_exception::code_value)
|| (code == sig_variable_size_limit_exception::code_value);
|| (code == sig_variable_size_limit_exception::code_value)
|| (code == inline_action_too_big_nonprivileged::code_value);
}

bool scheduled_failure_is_subjective( const fc::exception& e ) const {
Expand Down Expand Up @@ -2432,6 +2433,11 @@ const protocol_feature_manager& controller::get_protocol_feature_manager()const
return my->protocol_features;
}

uint32_t controller::get_max_nonprivileged_inline_action_size()const
{
return my->conf.max_nonprivileged_inline_action_size;
}

controller::controller( const controller::config& cfg, const chain_id_type& chain_id )
:my( new controller_impl( cfg, *this, protocol_feature_set{}, chain_id ) )
{
Expand Down
33 changes: 16 additions & 17 deletions libraries/chain/include/eosio/chain/chain_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ namespace eosio { namespace chain {
* values specified by the producers.
*/
struct chain_config {
uint64_t max_block_net_usage; ///< the maxiumum net usage in instructions for a block
uint32_t target_block_net_usage_pct; ///< the target percent (1% == 100, 100%= 10,000) of maximum net usage; exceeding this triggers congestion handling
uint32_t max_transaction_net_usage; ///< the maximum objectively measured net usage that the chain will allow regardless of account limits
uint32_t base_per_transaction_net_usage; ///< the base amount of net usage billed for a transaction to cover incidentals
uint64_t max_block_net_usage; ///< the maxiumum net usage in instructions for a block
uint32_t target_block_net_usage_pct; ///< the target percent (1% == 100, 100%= 10,000) of maximum net usage; exceeding this triggers congestion handling
uint32_t max_transaction_net_usage; ///< the maximum objectively measured net usage that the chain will allow regardless of account limits
uint32_t base_per_transaction_net_usage; ///< the base amount of net usage billed for a transaction to cover incidentals
uint32_t net_usage_leeway;
uint32_t context_free_discount_net_usage_num; ///< the numerator for the discount on net usage of context-free data
uint32_t context_free_discount_net_usage_den; ///< the denominator for the discount on net usage of context-free data
uint32_t context_free_discount_net_usage_num; ///< the numerator for the discount on net usage of context-free data
uint32_t context_free_discount_net_usage_den; ///< the denominator for the discount on net usage of context-free data

uint32_t max_block_cpu_usage; ///< the maxiumum billable cpu usage (in microseconds) for a block
uint32_t target_block_cpu_usage_pct; ///< the target percent (1% == 100, 100%= 10,000) of maximum cpu usage; exceeding this triggers congestion handling
uint32_t max_transaction_cpu_usage; ///< the maximum billable cpu usage (in microseconds) that the chain will allow regardless of account limits
uint32_t min_transaction_cpu_usage; ///< the minimum billable cpu usage (in microseconds) that the chain requires
uint32_t max_block_cpu_usage; ///< the maxiumum billable cpu usage (in microseconds) for a block
uint32_t target_block_cpu_usage_pct; ///< the target percent (1% == 100, 100%= 10,000) of maximum cpu usage; exceeding this triggers congestion handling
uint32_t max_transaction_cpu_usage; ///< the maximum billable cpu usage (in microseconds) that the chain will allow regardless of account limits
uint32_t min_transaction_cpu_usage; ///< the minimum billable cpu usage (in microseconds) that the chain requires

uint32_t max_transaction_lifetime; ///< the maximum number of seconds that an input transaction's expiration can be ahead of the time of the block in which it is first included
uint32_t deferred_trx_expiration_window; ///< the number of seconds after the time a deferred transaction can first execute until it expires
uint32_t max_transaction_delay; ///< the maximum number of seconds that can be imposed as a delay requirement by authorization checks
uint32_t max_inline_action_size; ///< maximum allowed size (in bytes) of an inline action
uint16_t max_inline_action_depth; ///< recursion depth limit on sending inline actions
uint16_t max_authority_depth; ///< recursion depth limit for checking if an authority is satisfied
uint32_t max_transaction_lifetime; ///< the maximum number of seconds that an input transaction's expiration can be ahead of the time of the block in which it is first included
uint32_t deferred_trx_expiration_window; ///< the number of seconds after the time a deferred transaction can first execute until it expires
uint32_t max_transaction_delay; ///< the maximum number of seconds that can be imposed as a delay requirement by authorization checks
uint32_t max_inline_action_size; ///< maximum allowed size (in bytes) of an inline action
uint16_t max_inline_action_depth; ///< recursion depth limit on sending inline actions
uint16_t max_authority_depth; ///< recursion depth limit for checking if an authority is satisfied
heifner marked this conversation as resolved.
Show resolved Hide resolved

void validate()const;

Expand Down Expand Up @@ -113,5 +113,4 @@ FC_REFLECT(eosio::chain::chain_config,

(max_transaction_lifetime)(deferred_trx_expiration_window)(max_transaction_delay)
(max_inline_action_size)(max_inline_action_depth)(max_authority_depth)

)
35 changes: 18 additions & 17 deletions libraries/chain/include/eosio/chain/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ static const uint32_t maximum_elastic_resource_multiplier = 1000;
const static uint32_t rate_limiting_precision = 1000*1000;


const static uint32_t default_max_block_net_usage = 1024 * 1024; /// at 500ms blocks and 200byte trx, this enables ~10,000 TPS burst
const static uint32_t default_max_block_net_usage = 1024 * 1024; /// at 500ms blocks and 200byte trx, this enables ~10,000 TPS burst
const static uint32_t default_target_block_net_usage_pct = 10 * percent_1; /// we target 1000 TPS
const static uint32_t default_max_transaction_net_usage = default_max_block_net_usage / 2;
const static uint32_t default_base_per_transaction_net_usage = 12; // 12 bytes (11 bytes for worst case of transaction_receipt_header + 1 byte for static_variant tag)
Expand All @@ -66,22 +66,23 @@ const static uint32_t default_context_free_discount_net_usage_num = 20; // TO
const static uint32_t default_context_free_discount_net_usage_den = 100;
const static uint32_t transaction_id_net_usage = 32; // 32 bytes for the size of a transaction id

const static uint32_t default_max_block_cpu_usage = 200'000; /// max block cpu usage in microseconds
const static uint32_t default_target_block_cpu_usage_pct = 10 * percent_1;
const static uint32_t default_max_transaction_cpu_usage = 3*default_max_block_cpu_usage/4; /// max trx cpu usage in microseconds
const static uint32_t default_min_transaction_cpu_usage = 100; /// min trx cpu usage in microseconds (10000 TPS equiv)
const static uint32_t default_subjective_cpu_leeway_us = 31000; /// default subjective cpu leeway in microseconds

const static uint32_t default_max_trx_lifetime = 60*60; // 1 hour
const static uint32_t default_deferred_trx_expiration_window = 10*60; // 10 minutes
const static uint32_t default_max_trx_delay = 45*24*3600; // 45 days
const static uint32_t default_max_inline_action_size = 4 * 1024; // 4 KB
const static uint16_t default_max_inline_action_depth = 4;
const static uint16_t default_max_auth_depth = 6;
const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery
const static uint32_t default_block_cpu_effort_pct = 80 * percent_1; // percentage of block time used for producing block
const static uint16_t default_controller_thread_pool_size = 2;
const static uint32_t default_max_variable_signature_length = 16384u;
const static uint32_t default_max_block_cpu_usage = 200'000; /// max block cpu usage in microseconds
const static uint32_t default_target_block_cpu_usage_pct = 10 * percent_1;
const static uint32_t default_max_transaction_cpu_usage = 3*default_max_block_cpu_usage/4; /// max trx cpu usage in microseconds
const static uint32_t default_min_transaction_cpu_usage = 100; /// min trx cpu usage in microseconds (10000 TPS equiv)
const static uint32_t default_subjective_cpu_leeway_us = 31000; /// default subjective cpu leeway in microseconds

const static uint32_t default_max_trx_lifetime = 60*60; // 1 hour
const static uint32_t default_deferred_trx_expiration_window = 10*60; // 10 minutes
const static uint32_t default_max_trx_delay = 45*24*3600; // 45 days
const static uint32_t default_max_inline_action_size = 512 * 1024; // 512 KB
const static uint16_t default_max_inline_action_depth = 4;
const static uint16_t default_max_auth_depth = 6;
const static uint32_t default_sig_cpu_bill_pct = 50 * percent_1; // billable percentage of signature recovery
const static uint32_t default_block_cpu_effort_pct = 80 * percent_1; // percentage of block time used for producing block
const static uint16_t default_controller_thread_pool_size = 2;
const static uint32_t default_max_variable_signature_length = 16384u;
const static uint32_t default_max_nonprivileged_inline_action_size = 4 * 1024; // 4 KB
brianjohnson5972 marked this conversation as resolved.
Show resolved Hide resolved

const static uint32_t min_net_usage_delta_between_base_and_max_for_trx = 10*1024;
// Should be large enough to allow recovery from badly set blockchain parameters without a hard fork
Expand Down
2 changes: 0 additions & 2 deletions libraries/chain/include/eosio/chain/contract_types.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#pragma once

#include <eosio/chain/authority.hpp>
#include <eosio/chain/chain_config.hpp>
#include <eosio/chain/config.hpp>
#include <eosio/chain/types.hpp>

namespace eosio { namespace chain {
Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace eosio { namespace chain {
uint64_t reversible_guard_size = chain::config::default_reversible_guard_size;
uint32_t sig_cpu_bill_pct = chain::config::default_sig_cpu_bill_pct;
uint16_t thread_pool_size = chain::config::default_controller_thread_pool_size;
uint32_t max_nonprivileged_inline_action_size = chain::config::default_max_nonprivileged_inline_action_size;
bool read_only = false;
bool force_all_checks = false;
bool disable_replay_opts = false;
Expand Down Expand Up @@ -181,6 +182,7 @@ namespace eosio { namespace chain {
const authorization_manager& get_authorization_manager()const;
authorization_manager& get_mutable_authorization_manager();
const protocol_feature_manager& get_protocol_feature_manager()const;
uint32_t get_max_nonprivileged_inline_action_size()const;

const flat_set<account_name>& get_actor_whitelist() const;
const flat_set<account_name>& get_actor_blacklist() const;
Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/include/eosio/chain/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ namespace eosio { namespace chain {
3050010, "Action attempts to increase RAM usage of account without authorization" )
FC_DECLARE_DERIVED_EXCEPTION( restricted_error_code_exception, action_validate_exception,
3050011, "eosio_assert_code assertion failure uses restricted error code value" )
FC_DECLARE_DERIVED_EXCEPTION( inline_action_too_big_nonprivileged, action_validate_exception,
3050012, "Inline action exceeds maximum size limit for a non-privileged account" )

FC_DECLARE_DERIVED_EXCEPTION( database_exception, chain_exception,
3060000, "Database exception" )
Expand Down
4 changes: 4 additions & 0 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ void chain_plugin::set_program_options(options_description& cli, options_descrip
("eos-vm-oc-enable", bpo::bool_switch(), "Enable EOS VM OC tier-up runtime")
#endif
("enable-account-queries", bpo::value<bool>()->default_value(false), "enable queries to find accounts by various metadata.")
("max-nonprivileged-inline-action-size", bpo::value<uint32_t>()->default_value(config::default_max_nonprivileged_inline_action_size), "maximum allowed size (in bytes) of an inline action for a nonprivileged account")
;

// TODO: rate limiting
Expand Down Expand Up @@ -755,6 +756,9 @@ void chain_plugin::plugin_initialize(const variables_map& options) {
if( options.count( "reversible-blocks-db-guard-size-mb" ))
my->chain_config->reversible_guard_size = options.at( "reversible-blocks-db-guard-size-mb" ).as<uint64_t>() * 1024 * 1024;

if( options.count( "max-nonprivileged-inline-action-size" ))
my->chain_config->max_nonprivileged_inline_action_size = options.at( "max-nonprivileged-inline-action-size" ).as<uint32_t>();

if( options.count( "chain-threads" )) {
my->chain_config->thread_pool_size = options.at( "chain-threads" ).as<uint16_t>();
EOS_ASSERT( my->chain_config->thread_pool_size > 0, plugin_config_exception,
Expand Down
4 changes: 2 additions & 2 deletions unittests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,9 +1063,9 @@ BOOST_FIXTURE_TEST_CASE(transaction_tests, TESTER) { try {
CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_empty", {});

// test send_action_large
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), inline_action_too_big,
BOOST_CHECK_EXCEPTION(CALL_TEST_FUNCTION(*this, "test_transaction", "send_action_large", {}), inline_action_too_big_nonprivileged,
[](const fc::exception& e) {
return expect_assert_message(e, "inline action too big");
return expect_assert_message(e, "inline action too big for nonprivileged account");
}
);

Expand Down
2 changes: 1 addition & 1 deletion unittests/eosio_system_tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ class eosio_system_tester : public TESTER {
("max_transaction_lifetime", 3600 + n)
("deferred_trx_expiration_window", 600 + n)
("max_transaction_delay", 10*86400+n)
("max_inline_action_size", 4096 + n)
("max_inline_action_size", 512*1024 + n)
("max_inline_action_depth", 4 + n)
("max_authority_depth", 6 + n)
("max_ram_size", (n % 10 + 1) * 1024 * 1024)
Expand Down
1 change: 0 additions & 1 deletion unittests/misc_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <eosio/chain/asset.hpp>
#include <eosio/chain/authority.hpp>
#include <eosio/chain/authority_checker.hpp>
#include <eosio/chain/chain_config.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/thread_utils.hpp>
#include <eosio/testing/tester.hpp>
Expand Down