Inner Call Out Of Gas Attack
Highlights a vulnerability related to gas allocation in contracts, specifically focusing on inner calls and the potential for successful attacks.
There is another problem related to how gas works in Ethereum. It's possible for a contract to be attacked when it calls other contracts using almost all of the available gas (63/64 of the total gas). This attack affects inner calls where the failure of the inner call doesn't cause the calling contract to stop.
This issue is somewhat similar to a Call Stack Depth Attack, but there are differences. For example, calls like <address>.send
won't fail because they still receive a minimum amount of gas called the gas stipend. The gas stipend is extra gas and is not affected by the 1/64 rule. So, these calls always have at least 2300 gas and won't fail due to running out of gas (unless the receiving contract intentionally reverts or uses more than 2300 gas).
The issue has some similarities to the call stack depth attack when it's used in low-level calls that catch failures of inner calls. These types of calls may become more popular with the introduction of the try/catch
feature in Solidity 0.6.
When a user calls the
test()
function, they can specify a gas limit for the transaction. If the gas limit is set too low (let's say 6,400,000), the inner call tocallNeeding6400000Gas()
won't receive enough gas.Let's say that in case of failure, there is some code in the
catch
block that consumes 50,000 gas.If the user makes a transaction with a gas limit of 6,400,000 gas and the inner call doesn't receive enough gas, it will fail with an "out of gas" exception.
As a result, the
catch
block will be executed, consuming 50,000 gas. Since we have approximately 100,000 gas available (6,400,000 / 64), the transaction will still complete successfully.
The issue here is that the caller, in this case, the Test
contract, won't be able to know whether the failure of the inner call was due to a lack of gas or if the inner call intentionally reverted.
Therefore, caution should be exercised when using a wildcard catch
block. It's important to be aware of this issue and carefully handle the logic inside the try/catch
block, especially if there are cases where the caller expects the inner call to intentionally revert.
Auction Example
Assuming the ERC20 token used in the code is secure and doesn't have any vulnerabilities, the code may appear safe at first glance. However, there is a potential issue with the try-catch block.
The problem arises because a new bidder can provide a specific amount of gas for the transaction. They can set it up in such a way that there isn't enough gas allocated for the second transfer call to succeed, but there is enough for the rest of the code. Since there are no significant operations after the try-catch
block, they won't require much gas, maybe just a few hundred units.
So, let's say the transferFrom
function requires around 20,000 gas (which is possible for an ERC20 token). If the gas provided for the transaction is such that 20,000 divided by 64 is greater than the remaining gas left for the bid call (let's say 300 gas), the transferFrom
call will throw an "out of gas" exception. However, the bid call might still have enough gas to complete successfully.
This example illustrates how similar the Inner Call Out of Gas Attack is to the Call Stack Depth Attack, which was aimed to be mitigated with EIP-150.
In summary, even though the code may seem safe at first, the specific gas allocation in the transaction can allow for a scenario where the inner transfer call fails due to insufficient gas, while the rest of the code completes successfully.
Last updated