Closed code423n4 closed 1 year ago
miladpiri marked the issue as sponsor disputed
I have verified through the blame that TX are not free anymore.
However the tx were free during the contest, although the comment does suggest that that was going to change: https://github.com/matter-labs/era-contracts/blame/272f11c1f7e141c6c89be3224d7a52dbbc747c0a/ethereum/contracts/zksync/facets/Mailbox.sol#L143
At the time of submission I believe the finding was valid, I'll ask for feedback by a couple more judges but at this time am leaving the report open
GalloDaSballo marked the issue as selected for report
The finding is mitigated as the current Era code charges fees, however the Warden couldn't have known that since the Era code was changed 2 weeks ago while the contest ended 3 weeks ago
Thanks @GalloDaSballo At the time of contest, it was assumed (as the comment states) that all the L1 -> L2 transactions were free (so any finding related to free tx that results in DoS would be invalid, because we explicitly state that).
This finding states that an attacker can register factory deps for free. While, we already mentioned that our tx are assumed to be free in the comment. So, what is the added value here?
So, I do not see this a valid finding.
This finding states that an attacker can register factory deps for free. While, we already mentioned that our tx are assumed to be free in the comment. So, what is the added value here?
Thank you for the clarification @miladpiri , will double check
GalloDaSballo marked the issue as unsatisfactory: Out of scope
I understand that the finding pertains to Bootloader so have closed as OOS
I believe that the statement concerning DOS being disclosed does make the finding OOS in that end
That said, even with paying txs, it does seem to be like this allows DOSsing by buying all available gas in a block, I must acknowledged that this could be viewed as "normal" behaviour as ultimately at the sequencer level there's no difference between someone buying txs to use the chain or to doss it.
I recommend the warden to further elaborate on the possible attack and follow up with the Sponsor or me
Lines of code
https://github.com/code-423n4/2023-03-zksync/blob/main/bootloader/bootloader.yul#L912
Vulnerability details
Impact
The bootloader's execution of L1->L2 transactions allows an attacker to register factory dependencies without paying any gas fees on L2.
Currently, L1->L2 transactions are already free. Even if they are not, it's not clear whether the gas costs you save on L2 make up for the costs of the transaction on L1. Nevertheless, I thought that this might be unexpected behavior in the bootloader since there's no documentation on it.
Proof of Concept
First, some knowledge of the bootloader's gas operations I've collected through discussions with the sponsor (Vlad & Barichek):
nearCall
allows you to call functions with a strict gas limit where the operation panics in case it runs out of gas. Described in detail here.nearCall
to limit each transaction's gas usage to the amount the user actually paid for.The one place where
nearCall
isn't used is inl1TxPreparation()
, part ofprocessL1Tx()
:There, the bootloader executes
markFactoryDepsForTx()
where the KnownCodesStorage contract is called to register all the factory dependencies of the current transaction. None of that is done with anearCall
. So, there's no limit set on the amount of gas that can be used.l1TxPreparation()
is part ofprocessL1Tx()
:In essence, the function:
gasLimitForTx > gasUsedOnPreparation
. Otherwise, it skips that.gasLimit * gasPrice
)As I said earlier, there's no limit on the gas
l1TxPreparation()
is allowed to spend. As long as the bootloader doesn't run out of gas (keep in mind there are other txs inside the block), the function won't panic or revert. So the user submits an L1->L2 transaction with the maximum amount of allowed factory dependencies (32) and a gas limit so low that after the call tol1TxPreparation()
, there's no gas left for the execution so that step is skipped. The last thing the bootloader does is to pay the operator (gasLimit * gasPrice), determine that there's no refund, and finally mark the tx as unsuccessful.Tools Used
none
Recommended Mitigation Steps
After
l1TxPreparation()
, add a check so that it didn't consume more gas than the user provided. Or, usenearCall
.