fix(snapshot): bump FetchSnapshotConfig read cap from 1 MiB to 64 MiB#3
Merged
tonicmuroq merged 1 commit intomainfrom May 6, 2026
Merged
fix(snapshot): bump FetchSnapshotConfig read cap from 1 MiB to 64 MiB#3tonicmuroq merged 1 commit intomainfrom
tonicmuroq merged 1 commit intomainfrom
Conversation
The previous cap was set with the comment "config blob is tiny", but
the SnapshotConfig embeds a per-file SparseMap for every file in the
snapshot. A 4 GiB Windows VM whose guest has many small live
allocations (e.g. an Electron app with a Firebase WebSocket signed in)
produces sparse maps in the high-hundred-KB range per fragmented file,
and the config blob easily exceeds 1 MiB once memory-ranges and
overlay.qcow2 are both accounted for. Observed live: 580 KB +
612 KB + base fields = 1.37 MB total config blob.
Wake-side symptom was
pull hibernation snapshot ...:
stream snapshot:
fetch snapshot config:
parse snapshot config: unexpected end of JSON input
— `io.ReadAll(io.LimitReader(body, 1<<20))` truncated the JSON exactly
at 1 MiB, leaving an unterminated structure.
Bump the cap to 64 MiB (still defends against pathological / malicious
manifests) and add a descriptor.Size pre-check so we reject oversize
blobs before reading. Add a streaming overflow guard for the case
where the descriptor lies about Size.
Tests:
- TestFetchSnapshotConfigOverOneMiB: builds a real ~1.4 MB
SnapshotConfig with two fragmented sparse maps and asserts parse
succeeds (would have failed under the old 1 MiB cap).
- TestFetchSnapshotConfigRejectsOversizeDescriptor: rejects a
descriptor advertising > 64 MiB up front.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dc0745d to
0315e8a
Compare
tonicmuroq
added a commit
to cocoonstack/vk-cocoon
that referenced
this pull request
May 6, 2026
Picks up cocoonstack/epoch#3, which raises the snapshot-config blob read cap from 1 MiB to 64 MiB. Wake-side parse failed with "unexpected end of JSON input" when the SnapshotConfig — including per-file SparseMap fields for memory-ranges and overlay.qcow2 — grew past 1 MiB, which a 4 GiB Windows guest with a Firebase-active agent hits routinely. No vk-cocoon source changes; just the go.mod / go.sum bump and a rebuild. Existing tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tonicmuroq
added a commit
to cocoonstack/vk-cocoon
that referenced
this pull request
May 6, 2026
Picks up cocoonstack/epoch#3, which raises the snapshot-config blob read cap from 1 MiB to 64 MiB. Wake-side parse failed with "unexpected end of JSON input" when the SnapshotConfig — including per-file SparseMap fields for memory-ranges and overlay.qcow2 — grew past 1 MiB, which a 4 GiB Windows guest with a Firebase-active agent hits routinely. No vk-cocoon source changes; just the go.mod / go.sum bump and a rebuild. Existing tests pass.
tonicmuroq
added a commit
to cocoonstack/vk-cocoon
that referenced
this pull request
May 6, 2026
Picks up cocoonstack/epoch#3, which raises the snapshot-config blob read cap from 1 MiB to 64 MiB. Wake-side parse failed with "unexpected end of JSON input" when the SnapshotConfig — including per-file SparseMap fields for memory-ranges and overlay.qcow2 — grew past 1 MiB, which a 4 GiB Windows guest with a Firebase-active agent hits routinely. No vk-cocoon source changes; just the go.mod / go.sum bump and a rebuild. Existing tests pass.
CMGS
pushed a commit
to cocoonstack/vk-cocoon
that referenced
this pull request
May 6, 2026
Picks up cocoonstack/epoch#3, which raises the snapshot-config blob read cap from 1 MiB to 64 MiB. Wake-side parse failed with "unexpected end of JSON input" when the SnapshotConfig — including per-file SparseMap fields for memory-ranges and overlay.qcow2 — grew past 1 MiB, which a 4 GiB Windows guest with a Firebase-active agent hits routinely. No vk-cocoon source changes; just the go.mod / go.sum bump and a rebuild. Existing tests pass.
CMGS
pushed a commit
to cocoonstack/vk-cocoon
that referenced
this pull request
May 6, 2026
Picks up cocoonstack/epoch#3, which raises the snapshot-config blob read cap from 1 MiB to 64 MiB. Wake-side parse failed with "unexpected end of JSON input" when the SnapshotConfig — including per-file SparseMap fields for memory-ranges and overlay.qcow2 — grew past 1 MiB, which a 4 GiB Windows guest with a Firebase-active agent hits routinely. No vk-cocoon source changes; just the go.mod / go.sum bump and a rebuild. Existing tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2.
Summary
pull.go:159reads the snapshot config blob viaio.ReadAll(io.LimitReader(body, 1<<20))with the comment "config blob is tiny", but the SnapshotConfig embeds per-file SparseMap fields. A 4 GiB Windows guest running an Electron app with a live Firebase WebSocket signed in produces sparse maps in the high-hundred-KB range per fragmented file, and the config blob easily exceeds 1 MiB oncememory-rangesandoverlay.qcow2are both accounted for.Observed live:
files["memory-ranges"].sparseMapfiles["overlay.qcow2"].sparseMapSymptom on the wake side:
io.LimitReaderreturns EOF after 1,048,576 bytes;io.ReadAllswallows the EOF; the caller hands the truncated buffer tojson.Unmarshal, which fails on the unterminated structure.Fix
desc.Sizeso we reject oversize blobs before any byte is read.Size.The reader path is the only thing that changes; pushers and on-disk format are untouched.
Relationship to cocoonstack/cocoon#23
Independent of #23. #23 addressed the writer-side tar PAX cap (a single file's sparse map > 1 MiB couldn't be encoded). This is the reader-side config cap (aggregate sparse maps + config metadata > 1 MiB couldn't be parsed). Both bugs share the same triggering condition (live Firebase agent → fragmented memory) but live in different layers.
Test plan
TestFetchSnapshotConfigOverOneMiB— builds a real ~1.4 MB SnapshotConfig with two fragmented sparse maps and asserts parse succeeds. Would have failed under the old 1 MiB cap with "unexpected end of JSON input".TestFetchSnapshotConfigRejectsOversizeDescriptor— descriptor advertising > 64 MiB is rejected before any read.go test ./snapshot/— all existing tests still pass alongside the new ones.🤖 Generated with Claude Code