Skip to content

Reject oversized four-byte literal length in snappy decoder - #801

Draft
kali834x wants to merge 2 commits into
apache:masterfrom
kali834x:snappy-literal-length-narrowing
Draft

Reject oversized four-byte literal length in snappy decoder#801
kali834x wants to merge 2 commits into
apache:masterfrom
kali834x:snappy-literal-length-narrowing

Conversation

@kali834x

Copy link
Copy Markdown
Contributor

snappycompressorinputstream.readliterallength reads the four-byte literal length with byteutils.fromlittleendian and casts it straight to int, so a length field of 0xffffffff narrows to -1 and, after the +1 the method adds, becomes a zero-length literal. fill only guards against a negative literal size, so the zero-length literal slips through, consumes no input and emits no output, and read() then recurses into itself once per element until a crafted run of them overflows the stack with a stackoverflowerror that escapes the declared ioexception. reading the four-byte value as an unsigned long and rejecting anything that can't fit a positive int before narrowing keeps the check at the point of the conversion; the two- and three-byte forms can't overflow so they're untouched. reachable directly and through framedsnappycompressorinputstream, which decodes each chunk with this class.

  • Read the contribution guidelines for this project.
  • Read the ASF Generative Tooling Guidance if you use Artificial Intelligence (AI).
  • I used AI to create any part of, or all of, this pull request. Which AI tool was used to create this pull request, and to what extent did it contribute?
  • Run a successful build using the default Maven goal with mvn; that's mvn on the command line by itself.
  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request should have a meaningful subject line and body.

@garydgregory garydgregory changed the title reject oversized four-byte literal length in snappy decoder Reject oversized four-byte literal length in snappy decoder Aug 11, 2026
@garydgregory
garydgregory requested a lite review from Copilot August 11, 2026 22:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Hardens the raw Snappy decoder against a crafted 4-byte literal-length field that previously could narrow to a zero-length literal and trigger unbounded recursion (stack overflow), by validating the 4-byte length before narrowing.

Changes:

  • Read 4-byte literal-length values as a long and reject values that would overflow a positive int once the Snappy +1 adjustment is applied.
  • Add a regression test that exercises the 0xFFFFFFFF 4-byte literal-length case and asserts a CompressorException mentioning “literal length”.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/main/java/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java Adds an overflow/oversize guard for 4-byte literal lengths before converting to int.
src/test/java/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStreamTest.java New test covering the oversized 4-byte literal-length edge case to prevent regression.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@garydgregory
garydgregory marked this pull request as draft August 12, 2026 12:23
@garydgregory

Copy link
Copy Markdown
Member

Switched to draft. There are many callers of the API that downcast the result to an int and therefore this issue needs a general solution, which coincidentally, I happen to be working on.

@kali834x

Copy link
Copy Markdown
Contributor Author

Makes sense, a fix at the ByteUtils level covers all the call sites at once. Happy to rebase this onto your change once it lands, or close it if it's fully covered there.

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.

3 participants