EOSIO / eos

An open source smart contract platform
https://developers.eos.io/manuals/eos
MIT License
11.27k stars 3.6k forks source link

How to avoid abuse of RAM by evil contract account? #4824

Closed vjoke closed 6 years ago

vjoke commented 6 years ago

Basically when an action is executed, we can add notifier by calling require_recipient. It's useful for linking actions from different contracts to work as a whole. But it also introduces new security problems. If the recipient itself is a contract, then the recipient's action handler can consume RAM on behalf of the original action. This may not be the expected result of original action. Following snippet shows that require_authorization only checks the authorization against the current action. How to solve this problem?

void apply_context::update_db_usage( const account_name& payer, int64_t delta ) {
   if( delta > 0 ) {
      if( !(privileged || payer == account_name(receiver)) ) {
         require_authorization( payer );
      }
   }
   trx_context.add_ram_usage(payer, delta);
}

void apply_context::require_authorization( const account_name& account ) {
   for( uint32_t i=0; i < act.authorization.size(); i++ ) {
     if( act.authorization[i].actor == account ) {
        used_authorizations[i] = true;
        return;
     }
   }
   EOS_ASSERT( false, missing_auth_exception, "missing authority of ${account}", ("account",account));
}
jgiszczak commented 6 years ago

Contracts delegating action processing to other contracts have a trust relationship with the other contracts. To prevent unexpected RAM consumption, the best way is to control all of the relevant accounts and contracts. A less attractive but possibly effective way is to only delegate to verified open source contracts that have been frozen by dropping ownership permissions.

There have been discussions about how to provide relative certainty that you can delegate to an arbitrary contract and still be assured there will be no RAM consumption. Code has not yet been written and there is no schedule. Watch future release notes.

smlu commented 6 years ago

I believe inline actions should have a way to verify or limit how much resources has been consumed during the executed action. This can be done either by explicitly limiting the resources of inline action before execution or be able to access transaction context where you would be able to calculate the difference in resource consumption before and after the inline action took place. I think this should be also applied to the deferred transaction. The third option that I see is to introduce a special permission that has to be given to each and every cc action (actions executed via require_recipient) in advance for the cc action to do anything relevant in the name of action's actor.

The last solution adds a bit more overhead to the developer's workflow so I believe first two options should be considered.