Skip to content

Harden block parsing against malformed backend responses#5

Merged
ValarDragon merged 1 commit into
masterfrom
harden/backend-input-panics
Jun 12, 2026
Merged

Harden block parsing against malformed backend responses#5
ValarDragon merged 1 commit into
masterfrom
harden/backend-input-panics

Conversation

@ValarDragon

Copy link
Copy Markdown

Fixes the panic/crash vectors found while auditing the block-fetch codepaths for the zcash#565 backport (#3). All are pre-existing on master, independent of #3, and reachable from both the block ingestor and client-driven GetBlock/GetBlockRange cache misses whenever the backend (or a MITM — the RPC connection is plain HTTP) serves inconsistent or malformed responses.

Fixes

  1. getBlockFromRPC txid-list indexing panic — the verbose reply's txid list was indexed once per parsed transaction; a raw block with more transactions than the verbose reply listed panicked. Now returns an error. (This is the panic class we hit while writing the parallel-ingestor tests: testdata block 380643 has 2 transactions.)
  2. Block.GetHeight() unguarded indexingParseFromSlice accepts a block with zero transactions, and a first transaction with no transparent inputs parses fine (the parser doesn't verify it's a coinbase); vtx[0].transparentInputs[0] panicked on either. Now returns -1, which existing callers already handle.
  3. hash32.FromSlice/ReverseSlice doc/behavior mismatch — documented as zero-padding short input, but the slice→array conversion panics on len < 32. Now matches the docs. All current callers pass exactly 32 bytes, so this is a latent footgun fix, not a behavior change.
  4. Log.Fatal on malformed verbose getblock JSON — a non-JSON-shaped (but successful) response killed the whole process; now returns an error so callers retry/report.
  5. Memory amplificationParseFromSlice pre-allocated the tx slice from the untrusted tx_count varint (cap 0x02000000 → ~268MB per crafted block, × concurrent fetchers); the capacity hint is now bounded by the remaining data length.

Testing

Regression tests for 1, 2, 4 (TestGetBlockFromRPCBadBackendReplies, TestGetHeightMalformedBlocks) and 3 (TestFromSlice, TestReverseSliceShort). All verified to panic (1–3) or exit (4) when run against master's unguarded code, and pass with the guards. Full suite passes under -race.

No conflicts with #3: same files in places, but disjoint hunks; the two PRs merge cleanly in either order.

These fixes are also candidates for upstreaming to zcash/lightwalletd.

🤖 Generated with Claude Code

A buggy or malicious backend (the RPC connection is plain HTTP) could
previously crash lightwalletd via several panic paths, reachable from
the block ingestor and from client-driven GetBlock/GetBlockRange cache
misses:

- getBlockFromRPC indexed the verbose getblock reply's txid list once
  per parsed transaction; a raw block with more transactions than the
  verbose reply listed panicked with index out of range.
- Block.GetHeight() indexed vtx[0].transparentInputs[0] unguarded, but
  ParseFromSlice accepts a block with zero transactions, and a first
  transaction with no transparent inputs parses fine (the parser does
  not verify it is a coinbase).
- hash32.FromSlice and ReverseSlice documented zero-padding short
  input but used a slice-to-array conversion, which panics on input
  shorter than 32 bytes. (All current callers pass 32 bytes; this was
  a latent footgun contradicting its documentation.)

Also:
- A malformed (non-JSON-shaped) verbose getblock response killed the
  whole process via Log.Fatal; return an error instead so the caller
  can retry or report it.
- ParseFromSlice pre-allocated the transaction slice from the
  untrusted tx_count varint (up to 0x02000000), allowing ~268MB
  allocations per crafted block; cap the capacity hint by the
  remaining data length.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ValarDragon ValarDragon merged commit db27b61 into master Jun 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant