Closed code423n4 closed 2 years ago
Recursion is necessary to handle, for example, ERC1155 message structure, see: https://github.com/skalenetwork/ima-c4-audit/blob/11d6a6ae5bf16af552edd75183791375e501915f/contracts/Messages.sol#L186-L189
This is a complex struct of struct within struct. ABI of the struct will have shifts in the data, and one will need to pass the shift to get the MessageType. For this reason, recursion is implemented. This can cause an infinite recursion if one adds an index of MessageType that is % 32
. But this is not possible, since message types are additive and for each 32 block an EMPTY message type will be added.
At the very least, an in-line doc comment describing this recursion requirement and MessageType may help clarify to external contributors. Suggest 0 (Non-critical)
I believe that the warden finding has validity, however the impact is minimized by the fact that the worst case scenario is a revert (no state changes), additionally, per the sponsor comment, recursion is necessary to unpack some of the data.
I believe that there may be edge cases where this finding can cause problems, however in lack of a POC, I agree with the sponsor with a non-critical severity
Lines of code
https://github.com/skalenetwork/ima-c4-audit/blob/main/contracts/Messages.sol#L195-L202
Vulnerability details
Impact
The function
getMessageType()
may cause infinite recursion.Consider the situation where
data
is 0x0000...00 (for 32 bytes). We will have the situation wherefirstWord = abi.decode(0x00...00, (uint256))
=>firstWord = 0
Thus, we hit the conditional statement
if (firstWord % 32 == 0) {
since0 % 32 == 0
So we will execute
return getMessageType(data[firstWord:]);
where
data[firstWord:] = data[0:] = data
and thus we have just callgetMessageType(data)
exactly as we did originally. After which the steps above will repeat and there will be another layer of recursion.The impact of this vulnerability is that the function will eventually run out of memory and revert.
Proof of Concept
Recommended Mitigation Steps
Consider checking if
firstWord == 0
in which case theMessageType
isEMPTY
.An alternative solution would be to revert if
firstWord == 0
to save gas for the caller.