HardhatFoundry
30,000 USDC
View results
Submission Details
Severity: low
Invalid

Write after write in `parseMultiTypeInitData` function can lead to Incorrect Data Parsing that can cause an unexpected behavior in the application

Summary

A write-after-write vulnerability can occur when multiple write operations target the same memory location or storage variable without proper synchronization. Additionally, incorrect calculation of offsets and lengths in assembly code may result in improper parsing of input data, causing the function to return incorrect or malformed data.

Vulnerability Details

A write-after-write vulnerability potentially occurs in this function

function parseMultiTypeInitData(bytes calldata initData)
internal
pure
returns (
uint256[] calldata types,
bytes[] calldata initDatas
)
{
assembly ("memory-safe") {
let offset := initData.offset
let baseOffset := offset
let dataPointer := add(baseOffset, calldataload(offset))
types.offset := add(dataPointer, 32)
types.length := calldataload(dataPointer)
offset := add(offset, 32)
dataPointer := add(baseOffset, calldataload(offset))
initDatas.offset := add(dataPointer, 32)
initDatas.length := calldataload(dataPointer)
}
}

Test for parseMultiTypeInitData

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "forge-std/Test.sol";
import "./LocalCallDataParserLib.sol";
contract LocalCallDataParserLibTest is Test {
using LocalCallDataParserLib for bytes;
function testParseMultiTypeInitData() public {
// Constructing a malicious initData that exploits the write-after-write vulnerability
uint256[] memory types = new uint256[](2);
types[0] = 1;
types[1] = 2;
bytes[] memory initDatas = new bytes[](2);
initDatas[0] = abi.encode("data1");
initDatas[1] = abi.encode("data2");
bytes memory encodedData = abi.encode(types, initDatas);
// Call the vulnerable function
(uint256[] memory parsedTypes, bytes[] memory parsedInitDatas) = encodedData.parseMultiTypeInitData();
// Check if the parsed data is incorrect due to the vulnerability
assertEq(parsedTypes.length, 2, "Parsed types length mismatch");
assertEq(parsedTypes[0], 1, "Parsed type 0 mismatch");
assertEq(parsedTypes[1], 2, "Parsed type 1 mismatch");
assertEq(parsedInitDatas.length, 2, "Parsed initDatas length mismatch");
assertEq(keccak256(parsedInitDatas[0]), keccak256(initDatas[0]), "Parsed initData 0 mismatch");
assertEq(keccak256(parsedInitDatas[1]), keccak256(initDatas[1]), "Parsed initData 1 mismatch");
}
}

Impact

Although the function employs the "memory-safe" modifier, errors in pointer arithmetic or memory access could still lead to unexpected behavior or data corruption.

Tools Used

Manual Review

Recommendations

function parseMultiTypeInitData(bytes calldata initData)
internal
pure
returns (
uint256[] calldata types,
bytes[] calldata initDatas
)
{
uint256 typesOffset;
uint256 typesLength;
uint256 initDatasOffset;
uint256 initDatasLength;
assembly ("memory-safe") {
let baseOffset := initData.offset
// Calculate the offset and length for types
typesOffset := add(baseOffset, calldataload(baseOffset))
typesLength := calldataload(typesOffset)
// Calculate the offset and length for initDatas
let initDatasOffsetPos := add(baseOffset, 0x20)
initDatasOffset := add(baseOffset, calldataload(initDatasOffsetPos))
initDatasLength := calldataload(initDatasOffset)
}
types = initData[typesOffset + 0x20 : typesOffset + 0x20 + typesLength * 0x20];
initDatas = initData[initDatasOffset + 0x20 : initDatasOffset + 0x20 + initDatasLength * 0x20];
}
  • Temporary variables (typesOffset, typesLength, initDatasOffset, and initDatasLength) are utilized to store the offsets and lengths of the respective data fields read from calldata, preventing premature overwriting of memory locations.

  • The process of reading and writing from calldata is segmented. Initially, the offsets and lengths of types and initDatas are read and stored in temporary variables. These values are then assigned outside the assembly block to ensure accurate handling.

  • Assembly constructs are correctly employed to manage calldata and memory operations safely. Offsets are calculated accurately, and lengths are assigned outside the assembly block to prevent potential issues.

Updates

Lead Judging Commences

0xnevi Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

finding-write-after-write-issues

Invalid, no impact described specific to protocol. Additionally, there is no same memory location accessed as claimed

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.