core/types: guard (*Header).GetValidatorBytes against short Extra#2222
core/types: guard (*Header).GetValidatorBytes against short Extra#2222kajaaz wants to merge 3 commits into
Conversation
(*Header).GetValidatorBytes panics with 'slice bounds out of range' when len(h.Extra) < ExtraVanityLength+ExtraSealLength on pre-Cancun chain configs. The post-Cancun branch and companion helpers already guard this path; hoist the check to the top so both branches are safe. Add TestGetValidatorBytesShortExtra as regression test. Discovered with Zorya (concolic execution). Fixes 0xPolygon#2221
There was a problem hiding this comment.
Pull request overview
Hardens the exported (*Header).GetValidatorBytes helper in core/types to avoid a slice-bounds panic on malformed headers (short Extra) in the pre-Cancun path, and adds a regression test to ensure short inputs return nil instead of panicking.
Changes:
- Hoists the
len(Extra) >= ExtraVanityLength+ExtraSealLengthguard to cover both pre- and post-Cancun branches inGetValidatorBytes. - Documents the new
nilreturn behavior for shortExtraon this API. - Adds a regression test covering multiple short
Extralengths across both Cancun/non-Cancun configs plus a happy-path assertion.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| core/types/block.go | Moves the Extra length guard ahead of the Cancun fork to prevent pre-Cancun slice panics and return nil safely. |
| core/types/block_test.go | Adds a regression test ensuring short Extra never panics and returns nil, plus a pre-Cancun happy-path check. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
core/types/block_test.go:966
- Rather than hard-coding a specific set of short lengths, consider deriving them relative to ExtraVanityLength+ExtraSealLength (e.g., 0, 1, threshold-1) so the regression test remains valid if the constants ever change.
shortLens := []int{0, 1, 32, 64, 65, 80, 96}
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
|
@claude review once. |
|
Claude finished @pratikspatil024's task in 1m 30s —— View job Review of PR #2222
Verdict: Approve — the fix is correct and minimal.
|
There was a problem hiding this comment.
LGTM — small defensive guard that matches the pattern of the companion helpers, with a regression test.
Extended reasoning...
Overview
The PR hoists an existing length check to the top of (*Header).GetValidatorBytes in core/types/block.go so that both the pre-Cancun and post-Cancun branches return nil instead of panicking when len(h.Extra) < ExtraVanityLength + ExtraSealLength. A regression test (TestGetValidatorBytesShortExtra) covers a range of short Extra lengths for both branches plus a pre-Cancun happy-path assertion. Two files changed; the diff is ~15 LOC of production code.
Security risks
None introduced. The change is strictly safer: it converts a previously panicking code path into a silent nil return, eliminating a DoS vector for any out-of-tree consumer that might call this exported helper on unvalidated headers. All in-tree callers (consensus/bor/bor.go:472, bor.go:640, bor.go:660, consensus/bor/snapshot.go:156) either feed the result to valset.ParseValidators (handles nil) or take len() of it — none rely on the prior panic behavior. The removed log.Error on the post-Cancun short-Extra path now matches GetBaseFeeParams / DecodeBlockExtraData behavior, which is consistent.
Level of scrutiny
Low. This is a defensive bugfix that follows an existing established pattern within the same file. The semantics for valid headers are unchanged, the behavior change for invalid headers is provably safer, and the function's callers all tolerate nil output. The regression test directly demonstrates that the prior panic is gone.
Other factors
The Copilot reviewer raised four cosmetic suggestions (log noise, test comment drift, hardcoded < 97 threshold, post-Cancun happy-path coverage) — all have been marked resolved on the PR. SonarCloud quality gate passed. The bug hunting system found no bugs. The author (pratikspatil024) explicitly requested a review.



Description
(*Header).GetValidatorBytesincore/types/block.gopanics withruntime error: slice bounds out of rangewhen called on a header whoseExtrafield is shorter thanExtraVanityLength + ExtraSealLength(< 97 bytes) and the chain configuration is pre-Cancun. The pre-Cancun branch performs the sliceh.Extra[ExtraVanityLength : len(h.Extra)-ExtraSealLength]with no length guard, while the post-Cancun branch and the three companion helpers (GetBaseFeeParams,DecodeBlockExtraData,(*Block).GetTxDependency) all already guard this path. The comment atconsensus/bor/bor.go:670acknowledges the function relies on upstream validation, but because the function is exported, any out-of-tree consumer (indexer, light client, block explorer, MEV tooling) that calls it on unvalidated headers will panic on attacker-controllable input.This PR hoists the existing length check to the top of
GetValidatorBytesso it covers both the pre-Cancun and post-Cancun branches uniformly. Behaviour for valid headers is unchanged.Discovered with Zorya, a concolic-execution engine for Go binaries. Zorya produced a Z3 witness
extra.len = 1after 65.7 s; confirmed to reproduce natively asslice bounds out of range [:-64]. See issue #2221 for the full write-up, SAT witness, and reproduction steps.Fixes #2221
Changes
Breaking changes
None. The only behavioural change is that
GetValidatorBytesnow returnsnilinstead of panicking whenlen(h.Extra) < ExtraVanityLength + ExtraSealLengthon a pre-Cancun config. All in-tree call sites already guard against this condition viavalidateHeaderExtraField, so they are unaffected.Nodes audience
All nodes that import
core/types. No flag or configuration change required.Checklist
Cross repository changes
Testing
Manual tests
develop, appendedTestGetValidatorBytesShortExtraVerbosetocore/types/block_test.go(pre-fix). All 7 short-Extra lengths panicked as expected (slice bounds out of range [:-65]through[32:31]). Test passed, confirming the bug is present on unpatched code.block.go. Re-rango test -v -run TestGetValidatorBytesShortExtra ./core/types/. Test passed: no panics, all short-Extra cases returnednil, happy-path case returned correct 40 validator bytes.go test ./core/types/, all existing tests pass.