Inaccurate use of the gasleft() estimation #107
Labels
bug
Something isn't working
disagree with severity
Sponsor confirms validity, but disagrees with warden’s risk assessment (sponsor explain in comments)
downgraded by judge
Judge downgraded the risk level of this issue
grade-b
judge review requested
Judge should review this issue
primary issue
Highest quality submission among a set of duplicates
QA (Quality Assurance)
Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Lines of code
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L200
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L224
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L279
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L291
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L371
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/SmartAccount.sol#L372
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L49
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L55
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L169
https://github.com/code-423n4/2023-01-biconomy/blob/53c8c3823175aeb26dee5529eeefa81240a406ba/scw-contracts/contracts/smart-contract-wallet/aa-4337/core/EntryPoint.sol#L186
Vulnerability details
Impact
The gasleft() check is used extensively in the codebase.
however the actual amount of gas left during the call is less than that (mainly due to the 1/64 rule, see below)
Reference for the 1/64 rule - EIP-150.
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
Also check out evm.codes
https://www.evm.codes/?fork=merge
We have to formulate the impact of using gasleft() case by case starting from the execTransaction in SmartAccount
If the code above, the actual amount of gas left is less than gasleft(),
then the code below pass but the transaction can still run out of gas.
When handling the gas price refund, gasleft() is also used:
the actual amount of gas left is less than gasleft(), the impact is that the receiver is not able to get the full gas refund payment.
gasleft() is also used when estimaing the gas cost in SmartWallet
the actual amount of gas left is less than gasleft(), this leads to inaccurate estimation of the gas needed to in order to complete the transaction.
The gasleft() is also used extensively in EntryPoint.sol
the actual amount of gas left is less than gasleft(), transaction can run out of gas unexpectedly.
Proof of Concept
Besides using a few units of gas between the check and the actual call, there's also a rule that only 63/64 of the remaining gas would be dedicated to an (external) function call. Since there are 2 external function calls done (nonRevertingBridgeCall() and the actual call to the bridge) ~2/64 of the gas isn't sent to the bridge call and can be used after the bridge call runs out of gas.
The following PoC shows that if the amount of gas left before the call is at least 1 million then the execution can continue after the bridge call fails
(note: there is no bridge in the context of the smart wallet, this POC just shows that the using gasleft() is not a accurate way to estimate the gas left)
Output of POC:
Tools Used
Foundry, hardhat, and manual review.
Recommended Mitigation Steps
Modify the required amount of gas left to gasLimit + any amount of gas spent before reaching the call(), then multiply it by 32/30 to mitigate the 1/64 rule (+ some margin of safety maybe).
Or In fact I think the gas estimation can be done in off-chain manner.
The text was updated successfully, but these errors were encountered: