Skip to content

fix: Fix OOM crash in SettingsSerializer readStream() VInt decoder.#707

Open
lggcs wants to merge 2 commits into
TokTok:masterfrom
lggcs:master
Open

fix: Fix OOM crash in SettingsSerializer readStream() VInt decoder.#707
lggcs wants to merge 2 commits into
TokTok:masterfrom
lggcs:master

Conversation

@lggcs
Copy link
Copy Markdown

@lggcs lggcs commented Apr 15, 2026

readStream() had no bounds check on the VInt shift count or the accumulated size value before calling QByteArray::resize(), allowing a crafted settings file to trigger an unbounded allocation (up to 2GB) and immediate OOM crash. The signed left-shift also produced undefined behavior when the shift exceeded 28 bits. Add the same overflow guard used by dataToVInt() (num2 > sizeof(int) * CHAR_BIT), stream error status checks, and a post-loop validity check on the decoded size before allocation.

Resolves #706


This change is Reviewable

readStream() had no bounds check on the VInt shift count or the accumulated size value before calling QByteArray::resize(), allowing a crafted settings file to trigger an unbounded allocation (up to 2GB) and immediate OOM crash. The signed left-shift also produced undefined behavior when the shift exceeded 28 bits. Add the same overflow guard used by dataToVInt() (num2 > sizeof(int) * CHAR_BIT), stream error status checks, and a post-loop validity check on the decoded size before allocation.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

Tip

Preview URL:

@github-actions github-actions Bot added the bug Bug fix for the user, not a fix to a build script label Apr 15, 2026
Copy link
Copy Markdown
Member

@iphydf iphydf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's an easy way to unit test this, please add a test. If not, file an issue and I'll follow up.

…tion

Covers the three guards added to readStream():

- OOM payload: VInt encoding 0x7FFFFFFF triggers the shift-count guard
  (num2 > sizeof(int)*CHAR_BIT), preventing QByteArray::resize(INT_MAX)
- Shift overflow: 5 continuation bytes push shifts past 32 bits,
  exercising the same guard for the UB case
- Truncated stream: premature EOF is caught by the QDataStream status
  check before each readRawData
- Zero-size VInt: the post-loop num <= 0 guard rejects empty values
- Valid settings: round-trips a key/value pair through the serializer
- isSerializedFormat: verifies QTOX magic detection
@lggcs lggcs deployed to netlify May 19, 2026 14:11 — with GitHub Actions Active
@lggcs
Copy link
Copy Markdown
Author

lggcs commented May 19, 2026

If there's an easy way to unit test this, please add a test. If not, file an issue and I'll follow up.

@iphydf comprehensive test case was committed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix for the user, not a fix to a build script

Development

Successfully merging this pull request may close these issues.

[Bug]: SettingsSerializer readStream() Unbounded Allocation and Integer Overflow

2 participants