Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consensus protocol upgrade to restrict authorization checking when sending actions to self #6705

Closed
arhag opened this issue Feb 6, 2019 · 2 comments

Comments

Projects
None yet
1 participant
@arhag
Copy link
Contributor

commented Feb 6, 2019

Background

EOSIO has a powerful permissions system that determines when authorizations (in the form of an account name and permission name pair) are allowed to be added to an action.

The general rules for action authorizations, which applies to all of the original actions in an input (or user-signed) transaction, are as follows:

  1. Minimum permission requirement

    Each authorization within an action corresponds to a minimum required permission. The minimum permission is looked up from part of the blockchain native state (modified using the eosio::linkauth and eosio::unlinkauth native actions) that maps the triplet (authorization actor, action code account, action name) to the permission name of the minimum required permission under the account of the authorization actor. By default, the mapping for any triplet is to the active permission of the authorization actor, unless modified using the eosio::linkauth action. The permission referred to by the authorization must either be the minimum required permission or an ancestor of it up the branch within the account's permission tree.

  2. Permission satisfaction requirement

    The declared authorization must also be satisfied by the credentials available within the current authorization context. These credentials may include public keys that correspond to valid signatures on the transaction, individual permissions (in the form of an account name and permission name pair) that are considered to be provided for authorization purposes within the current authorization context, and even a provided time delay which is relevant for delayed transactions. To satisfy the authorization, the authority of the permission corresponding to the authorization must be satisfiable just by the credentials available in the current authorization context.

These rules not only apply for all of the original actions in an input transaction, they also apply for many inline actions and actions in contract-generated deferred transactions. In that case however, the authorization context will be different.

For original actions in an input transaction, the authorization context includes the public keys corresponding to the signatures on the transaction as well a provided time delay set based on the delay_sec field in the input transaction.

For inline actions, the authorization context includes the eosio.code permission of the contract account that is sending the inline action and, if the contract is operating in the context a retired deferred transaction, it will also include a provided time delay equal to the difference between the current time and the time the deferred transaction was originally published.

For actions in a deferred transaction sent by a contract, the authorization context includes the eosio.code permission of the contract account that is sending the deferred transaction and a provided time delay set based on the delay_sec field in the generated transaction.

Since the initial version of EOSIO software, an alternative path existed to bypass the typical authorization checking described above for certain inline actions or contract-generated deferred transactions. If the inline action's code account is the same as the account of the contract sending the inline action, or if all the actions in a contract-generated deferred transaction have the same code account which is the account of the contract sending the deferred transaction, then the authorization bypass was utilized.

The motivation behind this bypass was that a contract could already do within the sending contract all the internal table changes that could be done during the execution of an inline action or a deferred transaction. So the bypass allowed the contract to avoid the strictness of the general authorization checks, enabling more flexible behavior in smart contracts.

However, this analysis missed the fact that the bypass opened up a privilege escalation vulnerability due to the fact that the authorizations of an action are also used by the native blockchain code to determine which accounts can be billed RAM by the contract. The authorizations of the original actions in a transaction (whether input or deferred) are also used by the native blockchain code to determine which accounts are to be billed for the CPU and network bandwidth of the transaction. This privilege escalation attack effectively meant that a contract exploiting this vulnerability could store data in its tables that charged the RAM costs for storing that data to any existing EOSIO account (without requiring that account to even be active in this process at all). However, the vulnerability could NOT be exploited to change the contract code or table data of other accounts, and there was no possibility of this exploit being used to steal tokens or other EOSIO digital assets (other than RAM and CPU/network bandwidth).

A subjective mitigation (released with v1.5.1 of EOSIO) has been available for over a month for live EOSIO blockchains to adopt which restricts the authorization rules when sending inline actions or deferred transaction such that this vulnerability cannot be exploited as long as all the active block producers of the network are running a version of nodeos including the patch for their block producing nodes.

The subjective mitigation effectively removes the bypass when sending deferred transactions meaning under this subjective mitigation the authorization for contract-generated deferred transactions is consistent with the general authorization rules described above which already applied to the original actions in an input transaction.

The subjective mitigation does not enforce as strict of a restriction for sending inline actions. The bypass rules have been restricted in the subjective mitigation to protect users' RAM and CPU/network bandwidth. But the authorization checks when sending an inline action are still more flexible than the general authorization rules that apply to original actions in an input transaction. This flexibility was purposely added to the subjective mitigation to reduce the number of existing well-meaning contracts deployed on live EOSIO blockchains that would break because they inadvertently relied on the unintentional flexibility of the bypass rules.

The subjective mitigation has been critical to quickly protecting users' RAM, but it is not a long-term solution. The long-term solution requires making the restrictions objective through a consensus protocol upgrade. Furthermore, for the sake of consistency, it is desirable for the authorization checks on inline actions to be as strict as the authorization checks on the original actions in an input transaction or the authorization checks on sending a deferred transaction now with the subjective mitigation in place. In other words, it is desirable for a consensus protocol upgrade to remove the bypass entirely.

This intention to further restrict the authorization checking behavior for sending inline actions has already been signaled through the deprecation notice in the v1.5.1 release of EOSIO. Since it will take some time before a consensus protocol upgrade to remove the bypass is activated, contract developers have some time to upgrade their contracts to not rely on the bypass.

Consensus upgrade feature

The goal of this consensus protocol upgrade feature is to remove the authorization checking bypass that applied when a contract sent an inline action to itself or when it sent a deferred transaction consisting of only actions to itself. With this change, the authorization checking behavior for actions becomes consistent regardless of whether the actions are the original actions in an input transaction, actions included in a contract-generated transaction, or inline actions sent by a contract.

A new consensus protocol upgrade feature will be added to trigger the changes described in this consensus upgrade proposal. The actual digest for the feature understood at the blockchain level is to be determined. For the purposes of this proposal the codename RESTRICT_ACTION_TO_SELF will be use to stand-in for whatever the feature identifier will actually end up being.

The actual code changes to implement this are straightforward after the necessary protocol feature foundations are in place.

In the apply_context::execute_inline function, the line

bool disallow_send_to_self_bypass = false;

should instead be set to true iff RESTRICT_ACTION_TO_SELF has been activated.

In the apply_context::schedule_deferred_transaction function, the line

bool disallow_send_to_self_bypass = false;

should instead be set to true iff RESTRICT_ACTION_TO_SELF has been activated.

@arhag arhag added the HARDFORK label Feb 6, 2019

@arhag

This comment has been minimized.

Copy link
Contributor Author

commented Feb 6, 2019

This issue depends on #6429. It will also be setup by default to be a protocol feature requiring pre-activation, thus it also depends on #6431.

@arhag

This comment has been minimized.

Copy link
Contributor Author

commented Apr 10, 2019

Resolved by #7088.

@arhag arhag closed this Apr 10, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.