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

Commit

Permalink
Merge pull request #10273 from EOSIO/release-2.1.x-security-fixes
Browse files Browse the repository at this point in the history
Consolidated Security Updates for 2.0.12 - 2.1.x
  • Loading branch information
nickjjzhao authored Apr 20, 2021
2 parents 8bb7bd4 + 4aa0679 commit df34a98
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 51 deletions.
3 changes: 2 additions & 1 deletion libraries/chain/include/eosio/chain/transaction_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ namespace eosio { namespace chain {
void record_transaction( const transaction_id_type& id, fc::time_point_sec expire );

void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const;
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, bool estimate )const;
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const;
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit )const;

void disallow_transaction_extensions( const char* error_msg )const;

Expand Down
51 changes: 41 additions & 10 deletions libraries/chain/transaction_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ namespace eosio { namespace chain {

if( !explicit_billed_cpu_time ) {
// Fail early if amount of the previous speculative execution is within 10% of remaining account cpu available
int64_t validate_account_cpu_limit = account_cpu_limit - subjective_cpu_bill_us;
int64_t validate_account_cpu_limit = account_cpu_limit - subjective_cpu_bill_us + leeway.count(); // Add leeway to allow powerup
if( validate_account_cpu_limit > 0 )
validate_account_cpu_limit -= EOS_PERCENT( validate_account_cpu_limit, 10 * config::percent_1 );
if( validate_account_cpu_limit < 0 ) validate_account_cpu_limit = 0;
validate_account_cpu_usage( billed_cpu_time_us, validate_account_cpu_limit, true );
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit );
}

eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes) so check_net_usage can be efficient
Expand Down Expand Up @@ -456,34 +456,65 @@ namespace eosio { namespace chain {
);
}

validate_account_cpu_usage( billed_us, account_cpu_limit, false );
validate_account_cpu_usage( billed_us, account_cpu_limit );
}
}

void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, bool estimate )const {
void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const {
if( (billed_us > 0) && !control.skip_trx_checks() ) {
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());

if( !cpu_limited_by_account && (billing_timer_exception_code == block_cpu_usage_exceeded::code_value) ) {
EOS_ASSERT( billed_us <= objective_duration_limit.count(),
block_cpu_usage_exceeded,
"${desc} CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)",
("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", objective_duration_limit.count() )
"billed CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)",
("billed", billed_us)( "billable", objective_duration_limit.count() )
);
} else {
if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
EOS_ASSERT( billed_us <= account_cpu_limit,
greylist_cpu_usage_exceeded,
"${desc} CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)",
("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", account_cpu_limit )
"billed CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)",
("billed", billed_us)( "billable", account_cpu_limit )
);
} else {
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
EOS_ASSERT( billed_us <= cpu_limit,
tx_cpu_usage_exceeded,
"${desc} CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)",
("desc", (estimate ? "estimated" : "billed"))("billed", billed_us)( "billable", cpu_limit )
"billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)",
("billed", billed_us)( "billable", cpu_limit )
);
}
}
}
}

void transaction_context::validate_account_cpu_usage_estimate( int64_t prev_billed_us, int64_t account_cpu_limit )const {
// prev_billed_us can be 0, but so can account_cpu_limit
if( (prev_billed_us >= 0) && !control.skip_trx_checks() ) {
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());

if( !cpu_limited_by_account && (billing_timer_exception_code == block_cpu_usage_exceeded::code_value) ) {
EOS_ASSERT( prev_billed_us < objective_duration_limit.count(),
block_cpu_usage_exceeded,
"estimated CPU time (${billed} us) is not less than the billable CPU time left in the block (${billable} us)",
("billed", prev_billed_us)( "billable", objective_duration_limit.count() )
);
} else {
if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
EOS_ASSERT( prev_billed_us < account_cpu_limit,
greylist_cpu_usage_exceeded,
"estimated CPU time (${billed} us) is not less than the maximum greylisted billable CPU time for the transaction (${billable} us)",
("billed", prev_billed_us)( "billable", account_cpu_limit )
);
} else {
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
EOS_ASSERT( prev_billed_us < cpu_limit,
tx_cpu_usage_exceeded,
"estimated CPU time (${billed} us) is not less than the maximum billable CPU time for the transaction (${billable} us)",
("billed", prev_billed_us)( "billable", cpu_limit )
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class subjective_billing {
trx_cache_index _trx_cache_index;
account_subjective_bill_cache _account_subjective_bill_cache;
block_subjective_bill_cache _block_subjective_bill_cache;
std::set<chain::account_name> _disabled_accounts;

private:
uint32_t time_ordinal_for( const fc::time_point& t ) const {
Expand Down Expand Up @@ -115,12 +116,13 @@ class subjective_billing {
public:
void disable() { _disabled = true; }
bool is_disabled() const { return _disabled; }
void disable_account( chain::account_name a ) { _disabled_accounts.emplace( a ); }

/// @param in_pending_block pass true if pt's bill time is accounted for in the pending block
void subjective_bill( const transaction_id_type& id, const fc::time_point& expire, const account_name& first_auth,
const fc::microseconds& elapsed, bool in_pending_block )
{
if( !_disabled ) {
if( !_disabled && !_disabled_accounts.count( first_auth ) ) {
uint32_t bill = std::max<int64_t>( 0, elapsed.count() );
auto p = _trx_cache_index.emplace(
trx_cache_entry{id,
Expand All @@ -138,15 +140,15 @@ class subjective_billing {

void subjective_bill_failure( const account_name& first_auth, const fc::microseconds& elapsed, const fc::time_point& now )
{
if( !_disabled ) {
if( !_disabled && !_disabled_accounts.count( first_auth ) ) {
uint32_t bill = std::max<int64_t>( 0, elapsed.count() );
const auto time_ordinal = time_ordinal_for(now);
_account_subjective_bill_cache[first_auth].expired_accumulator.add(bill, time_ordinal, expired_accumulator_average_window);
}
}

uint32_t get_subjective_bill( const account_name& first_auth, const fc::time_point& now ) const {
if( _disabled ) return 0;
if( _disabled || _disabled_accounts.count( first_auth ) ) return 0;
const auto time_ordinal = time_ordinal_for(now);
const subjective_billing_info* sub_bill_info = nullptr;
auto aitr = _account_subjective_bill_cache.find( first_auth );
Expand Down
Loading

0 comments on commit df34a98

Please sign in to comment.