TransactionValidator checks intrinsic costs against wrong value #1108
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
M-01
primary issue
Highest quality submission among a set of duplicates
satisfactory
satisfies C4 submission criteria; eligible for awards
selected for report
This submission will be included/highlighted in the audit report
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/code-423n4/2023-10-zksync/blob/1fb4649b612fac7b4ee613df6f6b7d921ddd6b0d/code/contracts/ethereum/contracts/zksync/libraries/TransactionValidator.sol#L41
Vulnerability details
Impact
An incorrect check allows an L1->L2 transaction to be sent that does not cover the sum of overhead and intrinsic costs for the operator.
Proof of Concept
The gasLimit required for a transaction consists of (see docs):
The function
TransactionValidator.getMinimalPriorityTransactionGasLimit
calculates the intrinsic costs that will be incurred for the processing of a transaction on L2. The calculated value is checked inTransactionValidator.validateL1ToL2Transaction
like this:The issue is that
_transaction.gasLimit
is the total gasLimit including the overhead for the operator. The overhead costs are already checked before that inTransactionValidator.getTransactionBodyGasLimit
The value returned by this function is the
actualGasLimit
(see formula above) that will be available for the processing of the transaction and which should be used to check if the intrinsic costs are covered.In the current implementation the
totalGasLimit
is checked twice if its greater than overhead and intrinsic costs (separately, not the sum). The bootloader does things correctly by subtracting the overhead from the totalGasLimit first and then checking if the rest covers the intrinsic costs (also called "preparation" costs):That means users will not be able to execute transactions for cheap. However, since L1->L2 transaction have to be processed (due to the way the priority queue works), it would be possible to grief the operator by submitting transactions that only cover$\text{max(overhead, intrinsicCosts)}$ . Those transactions would not have enough gas to be executed on L2, but the overhead and intrinsic costs would still be incurred.
Tools Used
Manual Review
Recommended Mitigation Steps
In
TransactionValidator.validateL1ToL2Transaction
change the check like this:l2GasForTxBody
is what remains after subtracting the overhead from the totalGasLimit.Assessed type
Other
The text was updated successfully, but these errors were encountered: