Lucene search

K
code423n4Code4renaCODE423N4:2023-05-MAIA-FINDINGS-ISSUES-769
HistoryJul 05, 2023 - 12:00 a.m.

_payFallbackGas is not being paid in case selector is 0x07 or 0x08

2023-07-0500:00:00
Code4rena
github.com
4
_payfallbackgas
selectors
protocol
anyfallback
execution budget
update
code update

Lines of code

Vulnerability details

Impact

_payFallbackGas gas is not being paid for selectors 0x07 and 0x08 which causes a loss for protocol’s execution gas budget. In case Execution budget is not enough then anyFallback will fail.

Proof of Concept

In _payFallbackGas() gas should always be paid in case selector (flag) is sent as 0x07 or 0x08 by calldata in anyFallback() L1227-L1307

    function anyFallback(bytes calldata data)
        external
        virtual
        requiresExecutor
        returns (bool success, bytes memory result)
    {
        //Get Initial Gas Checkpoint
        uint256 initialGas = gasleft();


        //Save Flag
        bytes1 flag = data[0];


        //Save memory for Deposit Nonce
        uint32 _depositNonce;


        /// DEPOSIT FLAG: 0, 1, 2
        if ((flag == 0x00) || (flag == 0x01) || (flag == 0x02)) {
            //Check nonce calldata slice.
            _depositNonce = uint32(bytes4(data[PARAMS_START:PARAMS_TKN_START]));


            //Make tokens available to depositor.
            _clearDeposit(_depositNonce);


            emit LogCalloutFail(flag, data, rootChainId);


            //Deduct gas costs from deposit and replenish this bridge agent's execution budget.
            _payFallbackGas(_depositNonce, initialGas);


            return (true, "");


            /// DEPOSIT FLAG: 3
        } else if (flag == 0x03) {
            _depositNonce = uint32(bytes4(data[PARAMS_START + PARAMS_START:PARAMS_TKN_START + PARAMS_START]));


            //Make tokens available to depositor.
            _clearDeposit(_depositNonce);


            emit LogCalloutFail(flag, data, rootChainId);


            //Deduct gas costs from deposit and replenish this bridge agent's execution budget.
            _payFallbackGas(_depositNonce, initialGas);


            return (true, "");


            /// DEPOSIT FLAG: 4, 5
        } else if ((flag == 0x04) || (flag == 0x05)) {
            //Save nonce
            _depositNonce = uint32(bytes4(data[PARAMS_START_SIGNED:PARAMS_START_SIGNED + PARAMS_TKN_START]));


            //Make tokens available to depositor.
            _clearDeposit(_depositNonce);


            emit LogCalloutFail(flag, data, rootChainId);


            //Deduct gas costs from deposit and replenish this bridge agent's execution budget.
            _payFallbackGas for (_depositNonce, initialGas);


            return (true, "");


            /// DEPOSIT FLAG: 6
        } else if (flag == 0x06) {
            //Save nonce
            _depositNonce = uint32(
                bytes4(data[PARAMS_START_SIGNED + PARAMS_START:PARAMS_START_SIGNED + PARAMS_TKN_START + PARAMS_START])
            );


            //Make tokens available to depositor.
            _clearDeposit(_depositNonce);


            emit LogCalloutFail(flag, data, rootChainId);


            //Deduct gas costs from deposit and replenish this bridge agent's execution budget.
            _payFallbackGas(_depositNonce, initialGas);


            return (true, "");


            //Unrecognized Function Selector
        } else {
            return (false, "unknown selector");
        }
    }

The code above shows how no consideration to 0x07 and 0x08 selectors while 0x07 is retrySettlement() and 0x08 is retrieveDeposit() both are calling _sendRetrieveOrRetry() which is performing _createGasDeposit() and _performCall() that means a request to the Root Omni-chain. L418-L439

    function retrySettlement(uint32 _settlementNonce, uint128 _gasToBoostSettlement)
        external
        payable
        lock
        requiresFallbackGas
    {
        //Encode Data for cross-chain call.
        bytes memory packedData = abi.encodePacked(
            bytes1(0x07), depositNonce++, _settlementNonce, msg.value.toUint128(), _gasToBoostSettlement
        );
        //Update State and Perform Call
        _sendRetrieveOrRetry(packedData);
    }


    /// @inheritdoc IBranchBridgeAgent
    function retrieveDeposit(uint32 _depositNonce) external payable lock requiresFallbackGas {
        //Encode Data for cross-chain call.
        bytes memory packedData = abi.encodePacked(bytes1(0x08), _depositNonce, msg.value.toUint128(), uint128(0));


        //Update State and Perform Call
        _sendRetrieveOrRetry(packedData);
    }

Basically the User will not pay gas for anyFallback() when it is triggered. This happens when he tried to send a request by calling retrySettlement() or retrieveDeposit() and the request fails. It will cause a loss for protocol’s execution gas budget.

Tools Used

Manual Review

Recommended Mitigation Steps

Consider call _payFallbackGas() for 0x07 and 0x08 flags in anyFallback() function

Assessed type

Other


The text was updated successfully, but these errors were encountered:

All reactions