Summary
The functions mulWad(uint256 x, uint256 y)
and mulWadUp(uint256 x, uint256 y)
rewrite a free memory pointer.
Vulnerability Details
The mulWad(uint256 x, uint256 y)
and mulWadUp(uint256 x, uint256 y)
functions use memory slot 0x40
to write the error selector.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
if mul(y, gt(x, div(not(0), y))) {
-> mstore(0x40, 0xbac65e5b)
revert(0x1c, 0x04)
}
z := div(mul(x, y), WAD)
}
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
if mul(y, gt(x, or(div(not(0), y), x))) {
-> mstore(0x40, 0xbac65e5b)
revert(0x1c, 0x04)
}
if iszero(sub(div(add(z, x), y), 1)) { x := add(x, 1) }
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
This address is reserved by solidity to hold the first empty slot to which variables can be written.
Solidity docs
Impact
Writing to this slot may result in loss or unintentional modification of data.
Tools Used
Manual review.
Recommendations
According to the documentation
Scratch space can be used between statements (i.e. within inline assembly). The zero slot is used as initial value for dynamic memory arrays and should never be written to (the free memory pointer points to 0x80 initially).
we can use memory from 0x20 to 0x3f without updating free memory point.
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
- mstore(0x40, 0xbac65e5b) // `MathMasters__MulWadFailed()`.
+ mstore(0x20, 0xbac65e5b) // `MathMasters__MulWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, or(div(not(0), y), x))) {
- mstore(0x40, 0xbac65e5b) // `MathMasters__MulWadFailed()`.
+ mstore(0x20, 0xbac65e5b) // `MathMasters__MulWadFailed()`.
revert(0x1c, 0x04)
}
if iszero(sub(div(add(z, x), y), 1)) { x := add(x, 1) }
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}