Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add checks to ERC7579Utils.decodeBatch #5353

Merged
merged 28 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions contracts/account/utils/draft-ERC4337Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,33 @@ library ERC4337Utils {
return result;
}

/// @dev Variant of {hash} that supports user operations in memory.
function hashMemory(
PackedUserOperation memory self,
address entrypoint,
uint256 chainid
) internal pure returns (bytes32) {
bytes32 result = keccak256(
abi.encode(
keccak256(
abi.encode(
self.sender,
self.nonce,
keccak256(self.initCode),
keccak256(self.callData),
self.accountGasLimits,
self.preVerificationGas,
self.gasFees,
keccak256(self.paymasterAndData)
)
),
entrypoint,
chainid
)
);
return result;
}

/// @dev Returns `factory` from the {PackedUserOperation}, or address(0) if the initCode is empty or not properly formatted.
function factory(PackedUserOperation calldata self) internal pure returns (address) {
return self.initCode.length < 20 ? address(0) : address(bytes20(self.initCode[0:20]));
Expand Down
53 changes: 49 additions & 4 deletions contracts/account/utils/draft-ERC7579Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ library ERC7579Utils {
/// @dev The module type is not supported.
error ERC7579UnsupportedModuleType(uint256 moduleTypeId);

/// @dev Input calldata not properly formatted and possibly malicious.
error ERC7579DecodingError();

/// @dev Executes a single call.
function execSingle(
ExecType execType,
Expand Down Expand Up @@ -169,13 +172,55 @@ library ERC7579Utils {
}

/// @dev Decodes a batch of executions. See {encodeBatch}.
///
/// Note: This function runs some checks and will throw a {ERC7579DecodingError} if the input is not properly formatted.
Amxx marked this conversation as resolved.
Show resolved Hide resolved
function decodeBatch(bytes calldata executionCalldata) internal pure returns (Execution[] calldata executionBatch) {
frangio marked this conversation as resolved.
Show resolved Hide resolved
bool failure = false;

// Extract the ERC7579 Executions array
//
// We need to check that the calldataload are within bounds, and that the resulting array is within the input
// buffer. We don't need to check the individual array elements as this is done (by solidity) when they are
// accessed.
assembly ("memory-safe") {
let ptr := add(executionCalldata.offset, calldataload(executionCalldata.offset))
// Extract the ERC7579 Executions
executionBatch.offset := add(ptr, 32)
executionBatch.length := calldataload(ptr)
// Pointer to the end of the calldata buffer
let end := add(executionCalldata.offset, executionCalldata.length)

// Check the buffer at least one element (the offset to the array)
if slt(executionCalldata.length, 32) {
Amxx marked this conversation as resolved.
Show resolved Hide resolved
failure := 1
}
{
// Fetch offset to the array
let offset := calldataload(executionCalldata.offset)

// Check offset is within bound
if gt(offset, 0xffffffffffffffff) {
failure := 1
}
{
// Pointer to the start of the array data
let ptr := add(executionCalldata.offset, offset)

// Check pointer is within bound
if gt(add(ptr, 32), end) {
failure := 1
}
{
executionBatch.offset := add(ptr, 32)
executionBatch.length := calldataload(ptr)

// Check that the length is within bounds
failure := or(
gt(executionBatch.length, 0xffffffffffffffff),
gt(add(executionBatch.offset, mul(executionBatch.length, 32)), end)
)
}
}
}
}

if (failure) revert ERC7579DecodingError();
}

/// @dev Executes a `call` to the target with the provided {ExecType}.
Expand Down
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ out = 'out'
libs = ['node_modules', 'lib']
test = 'test'
cache_path = 'cache_forge'
fs_permissions = [{ access = "read", path = "./test/bin" }]

[fuzz]
runs = 5000
Expand Down
Loading
Loading