Raise instead of hanging on a truncated frame in Zstd.decompress#143
Open
Watson1978 wants to merge 1 commit into
Open
Raise instead of hanging on a truncated frame in Zstd.decompress#143Watson1978 wants to merge 1 commit into
Watson1978 wants to merge 1 commit into
Conversation
decode_one_frame looped until ZSTD_decompressStream returned 0. For a
truncated/incomplete frame libzstd keeps returning a non-zero "need more
input" hint while consuming and producing nothing, so the loop spun
forever. Because ZSTD_decompressStream is called directly (GVL held),
this froze the whole VM at 100% CPU and ignored SIGTERM.
A header-only frame reproduces it:
Zstd.decompress("\x28\xB5\x2F\xFD") # hung forever
Detect the no-progress case (no output produced and no input consumed
with a non-zero return) and raise, matching the streaming decompressor
which already stops when the input is exhausted. Add a regression spec.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Zstd.decompresscould hang forever on a truncated / incomplete frame.decode_one_frameloops untilZSTD_decompressStreamreturns0. For atruncated frame, libzstd keeps returning a non-zero "need more input" hint
while consuming and producing nothing, so the loop never terminates.
Because
ZSTD_decompressStreamis called directly (with the GVL held),this freezes the whole Ruby VM at 100% CPU and does not even respond to
SIGTERM.A header-only frame reproduces it:
This is reachable from any input source that feeds attacker-controlled
compressed bytes to
Zstd.decompress(e.g. a compressed network payload).Fix
Detect the no-progress case — no output produced and no input consumed
with a non-zero return — and raise, instead of looping. This mirrors
Zstd::StreamingDecompress#decompress, which already stops once the inputis exhausted (and returns gracefully on the same input).
Tests
Added a regression spec asserting that truncated frames (bare magic and
several truncation lengths) raise instead of hanging. Full suite passes
(
67 examples, 0 failures). Valid single/concatenated frames areunaffected.
🤖 Generated with Claude Code