Closed code423n4 closed 1 year ago
GalloDaSballo marked the issue as primary issue
We clearly stated that freezability is a very dangerous place, but we understand that. It sound pretty much the same as "accidentally transfer ownership to different address".
From the doc:
Note, that it is a very dangerous thing since the diamond proxy can freeze the upgrade system and then the diamond will be frozen forever.
However, I agree that mitigation step is interesting, probably can be a QA issue!
miladpiri marked the issue as disagree with severity
miladpiri marked the issue as sponsor acknowledged
Per the sponsor comment, because the finding is out of scope I can only award the Refactoring suggestion, with QA Severity
R
Lines of code
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L137 https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L161 https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L200-L223 https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/DiamondCut.sol#L83 https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/DiamondCut.sol#L98 https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/DiamondProxy.sol#L30
Vulnerability details
Vulnerability Details
The
DiamondCutFacet
is a special facet contract for managing the freezing, unfreezing, and upgrading of other facet contracts.We discovered a critical issue regarding the diamond freeze feature, which allows a governor to freeze the
Diamond
contract. If theDiamondCutFacet
was set to be a freezable facet by mistake, theDiamond
contract would be frozen unrecoverably, affecting all platform's assets and users' assets on both L1 and L2 networks.The root cause of this issue resides in the function
_addOneFunction
of theDiamond
contract (code snippet 1). We found that the_addOneFunction
function allows a governor to register theDiamondCutFacet
contract as a freezable facet by mistake.In other words, the
_addOneFunction
function lacks a proper verification process when theDiamondCutFacet
contract is registered.Two diamond cut actions that can cause this issue include
Add
andReplace
. Specifically, theAdd
action would trigger the_addFunctions
function (L119 - 139 in code snippet 2), whereas theReplace
action would trigger the_replaceFunctions
function (L143 - 163).We found that both functions would invoke the
_addOneFunction
function in L137 and L161 to trigger the issue.Code snippet 3 below presents the functions
emergencyFreezeDiamond
(L78 - 88) andunfreezeDiamond
(L91 - 101).The
emergencyFreezeDiamond
function allows a governor to pause all freezable facets' functions instantly (L83). If theDiamondCutFacet
contract was set to be a freezable facet, its functions would also be frozen.From our investigation, if the
DiamondCutFacet
contract is frozen, a governor would have no way to unfreeze the contract because the execution of theunfreezeDiamond
function to unfreeze theDiamond
contract (L98) would not be reachable any longer.To elaborate on the case when the
DiamondCutFacet
contract is frozen, theDiamondProxy
'sfallback
function would reject the execution of theDiamondCutFacet
'sunfreezeDiamond
function in L30 in the code snippet 4 below.Therefore, this issue could impact all platform's assets and users' assets on both L1 and L2 networks.
Impact
We discovered a critical issue regarding the diamond freeze feature, which allows a governor to freeze the
Diamond
contract. If theDiamondCutFacet
was set to be a freezable facet by mistake, theDiamond
contract would be frozen unrecoverably, affecting all platform's assets and users' assets on both L1 and L2 networks.Proof of Concept
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L137
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L161
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/libraries/Diamond.sol#L200-L223
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/DiamondCut.sol#L83
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/facets/DiamondCut.sol#L98
https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/zksync/DiamondProxy.sol#L30
Tools Used
VSCode (Manual Review)
Recommended Mitigation Steps
We recommend implementing a proper facet verification mechanism by ensuring that the
DiamondCutFacet
contract cannot be set as a freezable facet as follows.Code snippet 5 shows the
DiamondCutFacet
contract. We implemented the pure functionisDiamondCutFacet
(L138 - 140) that would returntrue
of typebool
. This function would be used in the verification process, which will be explained later.In the code snippet 6 below, we defined the
isDiamondCutFacet
function (L37) in theIDiamondCut
interface.The
_addOneFunction
function was updated to implement the proposed facet verification mechanism as presented in L216 - 237 in the code snippet 7 below.In case a new facet is registered to the system, the
_addOneFunction
function would verify that the new facet must not be the freezableDiamondCutFacet
contract.To verify the new facet, specifically, the
_addOneFunction
function would make astaticcall
to theisDiamondCutFacet
function of the target facet (L219 - 220).If the target facet is the
DiamondCutFacet
contract, theisDiamondCutFacet
function would return the valuetrue
making a transaction to be reverted in L223.Otherwise, the verification process would be succeeded regardless of the call result. In other words, we would imply that the target facet would not be the
DiamondCutFacet
contract since the target facet does not implement the legitimateisDiamondCutFacet
function.Code snippet 8 below provides the
DiamondCutFacetVerificationHelper
library required by the updated_addOneFunction
function.The
DiamondCutFacetVerificationHelper.functionStaticCall()
function (L8 - 10) would be adopted by the_addOneFunction
function in L219 - 220 in the code snippet 7 above.Meanwhile, the
DiamondCutFacetVerificationHelper.decodeBool()
function (L12 - 14) would be adopted by the_addOneFunction
function in L222 in the above code snippet 7.