fix(derivation): guard against blockCount underflow on malformed batches#953
Conversation
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
batch.LastBlockNumber and the reference block (decoded startBlock for the V0->V1+ transition or parent header's LastBlockNumber for V1+) are not constrained by the L1 Rollup contract, so a malformed batch with LastBlockNumber below the reference would underflow blockCount and lead to a makeslice panic downstream in the blob-only path. Reject such batches with a clear error before subtracting. Co-authored-by: Cursor <cursoragent@cursor.com>
49cfa0a to
aee8855
Compare
Summary
Re-apply the underflow guard in
BatchInfo.ParseBatch(originally landed as commit aae2213 on this branch and reverted by 82e7062 without replacement). Addresses audit feedback on PR #935.The bug
In
node/derivation/batch_info.go::ParseBatch, both block-count derivation paths subtract two attacker-controllableuint64values without bounds checking:batch.LastBlockNumberis read directly from L1 calldata; the L1 Rollup contract does not constrain its relationship to the parent batch. A malformed batch withLastBlockNumber < parentBatchBlock(orLastBlockNumber < startBlock.Numberin the V0→V1 path) underflowsblockCountto a near-2^64value.Downstream,
bcLen := blockCount * 60wraps modulo2^64. For specific attacker-chosenLastBlockNumbervalues,bcLenwraps to a small number, the boundary checkif uint64(len(batchBytes)) < bcLenpasses spuriously, and the subsequent loop (for i := 0; i < int(blockCount); i++) iterates againstrawBlockContexts[i*60 : i*60+60]and panics with a slice-out-of-range. Net effect: a single malformed L1 commit batch crashes every honest derivation node simultaneously.The fix
Reject the malformed batch with a clear error before the subtraction, in both paths:
batch.LastBlockNumber < startBlock.Numberbatch.LastBlockNumber < parentBatchBlockAsymmetry between the two guards is intentional — V0→V1 has a
+ 1so equality represents a valid 1-block batch; V1+ does not, so equality represents an empty (0-block) batch which does not panic and is therefore out of scope for this PR.10 lines, no behavioral change on well-formed batches.
Why this is being re-applied
Commit aae2213 originally landed this fix on
feat/multi_batchon 2026-05-11. Commit 82e7062 reverted it ~1h later with a one-line message and no replacement implementation; the underflow path has been live on the branch ever since. Audit review on PR #935 flagged the same panic vector independently, so the fix is going back in.Test plan
go build ./...innode/RPCRollupBatchwithLastBlockNumber < parent.LastBlockNumber()in unit context and confirmParseBatchreturns the new error rather than panicking. (Regression test deliberately not bundled in this PR — kept scope minimal at the request of the reviewer; tracked separately.)🤖 Generated with Claude Code