Skip to content

Latest commit

 

History

History
69 lines (50 loc) · 2.53 KB

File metadata and controls

69 lines (50 loc) · 2.53 KB

Striped Amber Bird

Medium

InteractionControl.sol :: pauseAll() if any contract is already paused, will cause the transaction to revert, preventing it from functioning as intended.

Summary

pauseAll() is intended to pause all contracts; however, if an individual contract is already paused, the transaction will revert, preventing it from working as intended.

Root Cause

pauseAll() is implemented as follows.

function pauseAll() external onlyOwner {
    for (uint256 i = 0; i < controlledContractNames.length; ++i) {
      address addr = IContractAddressManager(contractAddressManager).getContractAddressForName(
        controlledContractNames[i]
      );
      _pauseContract(addr);
    }
  }

As shown, it iterates through all contracts to pause them. However, if any contract has already been individually paused with pauseContract(), the transaction will revert. This happens because _pauseContract() invokes pause() on the target contract, as defined in Pausable.sol.

function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

As shown, this requires that the contract be unpaused; otherwise, it reverts.

This is problematic in an emergency when you need to pause all contracts quickly. There’s no time to identify and unpause individual contracts, as every second is critical. This limitation hinders effective emergency response.

Internal pre-conditions

One of the protocol’s contracts is currently paused.

External pre-conditions

None.

Attack Path

None.

Impact

If a contract is already paused, calling pauseAll() will cause a revert, preventing it from working as intended. In an emergency, this can be critical, as every second counts.

PoC

The previous sections demonstrate this issue.

Mitigation

To resolve this, check if the contract is unpaused; if it is, proceed to pause the contract.

function pauseAll() external onlyOwner {
    for (uint256 i = 0; i < controlledContractNames.length; ++i) {
      address addr = IContractAddressManager(contractAddressManager).getContractAddressForName(
        controlledContractNames[i]
      );
+     if (!IPausable(addr).paused()) {
+        _pauseContract(addr);
+     }
    }
  }