Submitted by berndartmueller
https://github.com/initia-labs/minievm/blob/744563dc6a642f054b4543db008df22664e4c125/x/evm/keeper/context.go#L300-L303
https://github.com/initia-labs/minievm/blob/744563dc6a642f054b4543db008df22664e4c125/x/evm/keeper/context.go#L405-L407
Both the EVMCallWithTracer() and EVMCreateWithTracer() functions check the special case where gasRemaining == 0 && err != nil && err != vm.ErrOutOfGas, which can happen in scenarios like:
In this situation, it returns early with an error, without adding the used EVM gas to the gas meter. Consequently, the EVM call was gas-free.
This if not a particular big problem for regular Cosmos SDK EVM calls, as the user already paid for the full gas (limit) upfront. The issue it causes is that the block gas meter will be incorrectly updated, it will not reflect the actual gas used by the EVM call; the impact of this is limited.
However, it is specifically problematic in the context of EVM calls that have been dispatched via the CosmosPrecompile precompile. Such calls are executed by dispatchMessage(), which does not charge the gas upfront. Therefore, no gas is charged at all of such dispatched EVM calls, which allows DoS attacks by repeating such calls.
The following PoC demonstrates a stack overflow error in the Counter contract during a dispatched (nested) EVM call. It shows that in this case, no gas is charged for the nested call.
Calling recursive() will dispatch another EVM call to Counter.nested() (that is allowed to fail so that the error is not propagated), which then first consumes a lot of gas by calling consumeGas(1_000_000), followed by triggering a stack overflow by calling triggerStackOverflow().
In this case, gasRemaining will be 0, and err != vm.ErrOutOfGas, resulting in no gas being charged for the nested call, leaving the overall gas used below 100,000.
First, update the Counter contract:
Then, copy and paste the following test case to x/evm/keeper/context_test.go:
Compile the Solidity contracts with make contracts-gen and run the test case.
Consider consuming the gas before returning the error in lines 302 and 407 to always charge gas regardless of the error.
beer-1 (Initia) confirmed and commented:
Initia mitigated:
Status: Mitigation confirmed. Full details in reports from 0xAlix2, berndartmueller and Franfran.
