code4rena-2023-09-centrifuge-m03
[M-03] Cached DOMAIN_SEPARATOR is incorrect for tranche tokens potentially breaking permit integrations
Summary
ERC20 이름이 변경되더라도 미리 계산해 캐싱한 DOMAIN_SEPARATOR를 업데이트 하지 않는다. permit이 실패할 수 있다.
Keyword
erc2612, erc712, erc20, signature, wrong state, logic flaw
Vulnerability
새 트랜치 토큰이 배포되면 생성자에서 _DOMAIN_SEPARATOR를 계산하여 캐싱한다. domain seperator는 EIP712에 ERC20의 이름, 버전(EIP712 서명 버전), 체인 ID, 컨트랙트 주소를 해싱한 값이다.
ERC20의 이름(name 변수)은 생성자에서 초기화되지 않으므로 빈 문자열이 들어있다.
bytes32 private immutable _DOMAIN_SEPARATOR;
constructor(uint8 decimals_) {
...
deploymentChainId = block.chainid;
_DOMAIN_SEPARATOR = _calculateDomainSeparator(block.chainid);
}
function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {
return keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes(version)),
chainId,
address(this)
)
);
} 트랜치 토큰의 이름과 심볼은 이후 file 함수를 호출하여 설정된다. 이로 인해 _DOMAIN_SEPARATOR의 값은 올바르지 않게 된다. ERC20의 이름이 바뀌었기 때문에 해시값을 다시 구하는 게 맞다.
function newTrancheToken(
uint64 poolId,
bytes16 trancheId,
string memory name,
string memory symbol,
uint8 decimals,
address[] calldata trancheTokenWards,
address[] calldata restrictionManagerWards
) public auth returns (address) {
...
TrancheToken token = new TrancheToken{salt: salt}(decimals);
token.file("name", name);
...
}실제 ERC20 이름을 이용하여 서명한 유저는 정상적으로 permit할 수 없을 것이다.
또한 updateTrancheTokenMetadata를 이용해 트랜치 토큰의 이름과 심볼을 변경할 수도 있다. 이름을 변경한다면 동일하게 _DOMAIN_SEPARATOR 값이 틀어질 것이다.
function updateTrancheTokenMetadata(
uint64 poolId,
bytes16 trancheId,
string memory tokenName,
string memory tokenSymbol
) public onlyGateway {
TrancheTokenLike trancheToken = TrancheTokenLike(getTrancheToken(poolId, trancheId));
require(address(trancheToken) != address(0), "PoolManager/unknown-token");
trancheToken.file("name", tokenName);
trancheToken.file("symbol", tokenSymbol);
}Impact
DOMAIN_SEPARATOR가 실제와 맞지 않아 트랜치 토큰의 permit 함수가 실패할 수 있다.
Mitigation
캐시된 _DOMAIN_SEPARATOR를 계산하기 전에 이름을 초기화하거나, 이름이 변경되면 _DOMAIN_SEPARATOR를 재계산한다.
tags: bughunting, centrifuge, smart contract, solidity, erc2612, erc712, erc20, signature, wrong state, logic flaw, severity medium