The ExecutionHelper::_execute(address, uint256, bytes calldata)
function could lead to a free memory pointer pointing to an already written spot in memory, causing potential issues.
During the execution of the UserOperation, the function ExecutionHelper::_execute(address target, uint256 value, bytes calldata callData)
stores the callData
passed as an argument in the free memory slot. After the low-level call, the returned data size overwrites the first memory slot where the callData
was stored, and the second slot is overwritten by the returned data itself. At the end of the process, the free memory pointer is set to point to the slot after the returned data. However, if callData.length > returndatasize() + 0x20
, then the free memory pointer will point to a part of the callData
bytes, leading to potential misuse of memory.
Assume the free memory pointer at the beginning of the execution is equal to 0x80. We execute the ExecutionHelper::_execute(address target, uint256 value, bytes calldata callData)
function with callData = 0xffffff...fffff
(128 bytes long). Then, all slots from 0x80 to 0xc0 are written:
Suppose the low-level call to the target with the given callData
returns a uint256
, so returndatasize() = 0x20
. At the end of the execution, the free memory pointer will be pointing to 0x80 + 0x20 + returndatasize() = 0x80 + 0x20 + 0x20 = 0xc0
.
The impact of this vulnerability could lead to unexpected memory behavior, potentially causing data corruption or unintended consequences within the smart contract execution flow.
Manual review
To prevent this misuse of memory, the callData
should be removed from memory before any further operations:
This modification ensures that callData
is properly deleted from memory, preventing the free memory pointer from pointing to an already written spot in memory.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.