QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: low
Invalid

Out-of-Bounds Write in `_quantAMMUnpack128Array` Function

Summary

The _quantAMMUnpack128Array function is designed to unpack a series of 256-bit integers into a target array of 128-bit integers. While the logic for handling typical cases appears correct, there exists a critical vulnerability when the sourceArray length and targetArrayLength parameters are mismatched. Specifically, the function does not adequately prevent out-of-bounds access during unpacking, which could lead to runtime exceptions or undefined behavior.

Vulnerability Details

The _quantAMMUnpack128Array function attempts to unpack 256-bit integers into a targetArray of 128-bit integers. Each 256-bit integer in sourceArray contributes two 128-bit values. The loop structure increments the targetIndex by 2 in each iteration. If targetArrayLength is not carefully constrained, the function will attempt to access an out-of-bounds index in the targetArray.

function _quantAMMUnpack128Array(
int256[] memory _sourceArray,
uint _targetArrayLength
) internal pure returns (int256[] memory targetArray) {
require(_sourceArray.length * 2 >= _targetArrayLength, "SRC!=TGT");
targetArray = new int256[](_targetArrayLength);
uint targetIndex;
uint sourceArrayLengthMinusOne = _sourceArray.length - 1;
bool divisibleByTwo = _targetArrayLength % 2 == 0;
for (uint i; i < _sourceArray.length; ) {
targetArray[targetIndex] = _sourceArray[i] >> 128;
unchecked {
++targetIndex;
}
if ((!divisibleByTwo && i < sourceArrayLengthMinusOne) || divisibleByTwo) {
targetArray[targetIndex] = int256(int128(_sourceArray[i]));
}
unchecked {
++i;
++targetIndex;
}
}
if (!divisibleByTwo) {
targetArray[_targetArrayLength - 1] = int256(int128(_sourceArray[sourceArrayLengthMinusOne]));
}
}
}

Scenario
Input
sourceArray = [val1, val2, val3] (length = 3)
targetArrayLength = 4
Execution Steps
On the 3rd iteration (i = 2), the function tries to assign the high 128 bits of sourceArray[2] to targetArray[4].
Since targetArray only has 4 slots (indices 0 to 3), this causes an out-of-bounds error.
Root Cause
The loop termination condition (for (uint i; i < _sourceArray.length; )) ensures that every 256-bit value in sourceArray is unpacked, regardless of whether the targetArray is already fully populated.

Impact

  1. The function may attempt to write to an index outside the allocated memory for targetArray, resulting in a runtime error or undefined behavior.

  2. If this function is called in a smart contract, a DoS attack could be triggered by carefully crafted inputs that cause the function to revert or fail.

Tools Used

Manual Review

Recommendations

Modify the loop to ensure that targetIndex does not exceed _targetArrayLength. The new loop structure should focus on populating targetArray completely without assuming that all sourceArray values must be unpacked

function _quantAMMUnpack128Array(
int256[] memory _sourceArray,
uint _targetArrayLength
) internal pure returns (int256[] memory targetArray) {
require(_sourceArray.length * 2 >= _targetArrayLength, "SRC!=TGT");
targetArray = new int256[](_targetArrayLength);
uint targetIndex;
uint sourceArrayLengthMinusOne = _sourceArray.length - 1;
bool divisibleByTwo = _targetArrayLength % 2 == 0;
for (uint i; i < _sourceArray.length; ) {
targetArray[targetIndex] = _sourceArray[i] >> 128;
unchecked {
++targetIndex;
+ if (targetIndex < _targetArrayLength) {
+ targetArray[targetIndex] = int256(int128(_sourceArray[i]));
+ }
+ unchecked {
+ ++i;
+ ++targetIndex;
+ }
}
if ((!divisibleByTwo && i < sourceArrayLengthMinusOne) || divisibleByTwo) {
targetArray[targetIndex] = int256(int128(_sourceArray[i]));
}
unchecked {
++i;
++targetIndex;
}
}
if (!divisibleByTwo) {
targetArray[_targetArrayLength - 1] = int256(int128(_sourceArray[sourceArrayLengthMinusOne]));
}
}
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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

Give us feedback!