Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: low
Valid

Error selector will never be returned with current conditions

Summary

Revert statements using incorrect memory slot

Vulnerability Details

The function mulWadUp wants to return an error selector loaded into memory at position 0x40. The issue arises when the revert op code uses the memory offset 0x1c and 0x04 for the size in the return data, as this actually will load empty bytes when the function reverts (empty error message), as you can see in the PoC below:

function test2MulWad() public {
uint x = type(uint248).max;
uint y = 1000;
uint z = MathMasters.mulWad(x,y);
console2.log("z", z);
}
Running 1 test for test/MathMasters.t.sol:MathMastersTest
[FAIL. Reason: ] test2MulWad() (gas: 285)
Traces:
[285] MathMastersTest::test2MulWad()
└─ ←
Test result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 18.79ms

Additionally, there is an optimizer bug introduced in solidity 0.8.13, that can cause memory writes in inline assembly blocks to be incorrectly removed under certain conditions. The Yul optimizer considers all memory writes in the outermost Yul block that are never read from as unused and removes them. Both mulWad and mulWadUp write to the 0x40 memory pointer, but as this offset is never read, it removes the mstore(0x40, 0xbac65e5b) completely.

The README clearly states: We expect any solidity project using version ^0.8.3 or above should be able to use our codebase. If not, that should be considered a vulnerability as well. The Solidity developers have confirmed this bug (which was introduced in Solidity 0.8.13) and fixed it in Solidity version 0.8.15. This means, that any project compiling with 0.8.13 and 0.8.14 will never revert with the desired error selector.

contract C {
function f() external {
assembly {
mstore(0, 0x42) // This write will be kept, since the return below reads from the memory.
mstore(32, 0x21) // This will be removed, but that is valid since the memory is never read again.
return(0, 32)
}
}
}

Impact

Medium. Off chain services will not be able to detect what the error is, so it will need to use tools like tenderly to check the line of code that failed.

Tools Used

Recommendations

If the idea is to keep using the 0x40 free memory pointer slot to store the error selector, then the revert opcode should be:

revert(0x5c, 0x04)
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Wrong error storage

Support

FAQs

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