Skip to content

Consume skippable framed chunks iteratively in ensureBuffer - #736

Open
iliasabk wants to merge 1 commit into
xerial:mainfrom
iliasabk:fix/framed-skippable-chunk-recursion
Open

iliasabk wants to merge 1 commit into
xerial:mainfrom
iliasabk:fix/framed-skippable-chunk-recursion

Conversation

@iliasabk

Copy link
Copy Markdown

Issue

Fixes #731 — uncontrolled recursion (CWE-674, CVSS 5.3) in SnappyFramedInputStream.ensureBuffer(), reported by August829 with a PoC.

Root cause

getFrameMetaData() accepts zero-length reserved-skippable chunks (0x800xfe, minLength = 0), and the SKIP branch of ensureBuffer() handled each one by calling return ensureBuffer(). Every chunk — only 4 bytes on the wire — therefore consumed one call-stack frame, so a crafted stream of ~78 KB was enough to terminate the decompressing thread with StackOverflowError.

Fix

The SKIP handling now consumes runs of skippable chunks in a while loop instead of recursing, so stack depth stays constant no matter how many chunks precede the next data frame. Behaviour for all other frame actions is unchanged; the loop exits with the first non-SKIP FrameMetaData and the existing data path runs as before.

Tests

Two regression tests in SnappyFramedStreamTest:

  • testSkippableChunkRun — 100,000 zero-length skippable chunks followed by a checksummed uncompressed data chunk: the data is returned intact (fails pre-fix with StackOverflowError at SnappyFramedInputStream.java:531).
  • testSkippableChunkRunToEof — a stream that is nothing but skippable chunks ends in -1 instead of StackOverflowError.

./sbt "testOnly org.xerial.snappy.SnappyFramedStreamTest": 19/19 pass; the two new tests fail against the unmodified code, confirming they reproduce the reported bug. Full ./sbt test: identical result set as unmodified upstream — the only failures are the 11 pre-existing isTooLarge*ArrayInputLength cases in SnappyTest that hit OutOfMemoryError on small test heaps before reaching Snappy code.

Each reserved-skippable chunk made ensureBuffer() recurse into itself,
so a crafted stream added one call-stack frame per ~4 input bytes and
terminated reads with StackOverflowError. Skipping iteratively keeps
the stack depth constant regardless of how many chunks precede the
next data frame.

Fixes xerial#731

Signed-off-by: Ilias Aberkane <iliasaberkane2908@gmail.com>
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.

snappy-java through 1.1.10.8 Uncontrolled Recursion via SnappyFramedInputStream skippable chunks

1 participant