Closed github-actions[bot] closed 1 year ago
Comment from Optimism
Description: Incorrect withdrawal finalization due to EIP-150 logic
Reason: Duplicate of #096
Action: See comment on #096
Escalate for 250 USDC
I think this report addresses both issues mentioned in #96 and #109. Although the primary focus is on the problem related to the incompatibility with the EIP-150
logic, the report also clearly describes the issue of gas consumption that occurs between the corresponding require
check and call
:
In this example, the
require
statement was done exactly before the external call because logic between them also can consume some gas and lead to an incorrect amount of gas passed to the call.
The report also provides an example of how this bug can be harmful even to a user who takes into account such additional gas expenses and sets the gas limit accordingly:
Especially it is so in the cases when such logic will be changed during the upgrade of the
OptimismPortal
contract, as some projects launched on optimism may rely on the fact that it is using some constant amount of gas.
Therefore, I kindly request that you consider accepting this report as one that addresses both problems, although it may only partially cover the second one.
Escalate for 250 USDC
I think this report addresses both issues mentioned in #96 and #109. Although the primary focus is on the problem related to the incompatibility with the
EIP-150
logic, the report also clearly describes the issue of gas consumption that occurs between the correspondingrequire
check andcall
:In this example, the
require
statement was done exactly before the external call because logic between them also can consume some gas and lead to an incorrect amount of gas passed to the call.The report also provides an example of how this bug can be harmful even to a user who takes into account such additional gas expenses and sets the gas limit accordingly:
Especially it is so in the cases when such logic will be changed during the upgrade of the
OptimismPortal
contract, as some projects launched on optimism may rely on the fact that it is using some constant amount of gas.Therefore, I kindly request that you consider accepting this report as one that addresses both problems, although it may only partially cover the second one.
You've created a valid escalation for 250 USDC!
To remove the escalation from consideration: Delete your comment. To change the amount you've staked on this escalation: Edit your comment (do not create a new comment).
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
Escalation rejected, although it touches the same parts of the code that 109 does, it's not clear that it is describing the same bug
Escalation rejected, although it touches the same parts of the code that 109 does, it's not clear that it is describing the same bug
This issue's escalations have been rejected!
Watsons who escalated this issue will have their escalation amount deducted from their next payout.
Barichek
medium
Incorrect withdrawal finalization due to EIP-150 logic
Summary
It is possible to pass incorrect gas to the withdrawal transaction execution and force fail it with no possibility of a second attempt of execution (although in fact, the transaction with the specified amount of gas will not revert).
Vulnerability Detail
The
finalizeWithdrawalTransaction
function ofOptimismPortal
makes an external call to the withdrawal target contract and passes the required amount of gas in the following manner:According to the EIP-150
call
can consume at most63/64
of parent calls' gas. That means that in casegasleft() * 63 / 64
in the moment of making the call using theSafeCall
library is smaller thangasleft() - FINALIZE_GAS_BUFFER
the amount of gas that will be passed to the external call can be incorrect. This can lead to failing the withdrawal call and marking such withdrawal tx as processed (with no possibility of reexecution).To better understand the scenario please check the
PoC
subsection. There is used a simplified version of theOptimismPortal
contract (but with no modifications that have any significant effect on the described problem). As the target of the withdrawal call there used aCustomBridge
contract, which is also simplified -- instead of processing real logic it just burns some amount of gas that can be practically used during a such call (specifically in the PoC it burnsGAS_TO_BE_USED_FOR_WITHDRAWALS = 3000000
gas). For the simplification and visibility of the withdrawal call result, there is usedstateMarker
public variable.The
PoC
contract shows how exactly the described scenario can happen (here it is the description of the logic of thePoC
contract constructor):TO_USE_AS_SAFE_GAS_LIMIT
gasLimit
reverts (which is checked in therequire(customBridge.stateMarker() == 0);
statement);finalizeWithdrawalTransaction
function withdrawal transaction was marked as processed (which is enforced in therequire(optimismPortalSimplified.finalizedWithdrawals(Hashing.hashWithdrawal(tx)));
statement);processCrossChainTransaction
function on the target contract should not fail (which is enforced by checking thestateMarker
variable value after the "naive" call of this function with mentioned gas limit).Please note, that for the call through the
OptimismPortalSimplified
contract, there is usedgasLimit
value with the additional overheadADDITIONAL_OVERHEAD_TO_COVER_EXTRA_EXPENSES = 3000
, so this is not just a "small error in gas calculations due to additional logic". Also, you can check the debug trace to make sure of it.PoC
Impact
Possibility of passing incorrect gas to the withdrawal transaction execution and forcing fail of it with no possibility of a second attempt of execution (although in fact, the transaction with the specified amount of gas will not revert by nature). To perform such a transaction, the attacker does not need any additional access. Also, due to the specifics of
eth_estimateGas
logic, the user himself can execute the transaction, since the minimum amount of gas can be used at which the transaction is not reverted.Code Snippet
Tool used
Manual Review, Remix IDE
Recommendation
Change the gas management logic to be compatible with EIP-150. You can use the following:
In this example, the
require
statement was done exactly before the external call because logic between them also can consume some gas and lead to an incorrect amount of gas passed to the call. Especially it is so in the cases when such logic will be changed during the upgrade of theOptimismPortal
contract, as some projects launched on optimism may rely on the fact that it is using some constant amount of gas.Duplicate of #96