Skip to content

Fix ArgumentOutOfRangeException in Deflate64 - #128071

Merged
rzikm merged 2 commits into
mainfrom
fix/deflate64-fuzzer-crash
May 12, 2026
Merged

Fix ArgumentOutOfRangeException in Deflate64#128071
rzikm merged 2 commits into
mainfrom
fix/deflate64-fuzzer-crash

Conversation

@rzikm

@rzikm rzikm commented May 12, 2026

Copy link
Copy Markdown
Member

Found by Deflate64Fuzzer.

rzikm and others added 2 commits May 12, 2026 13:26
The InflaterManaged.DecodeBlock loop guard reeBytes > 65536 was tight
enough to ensure room for one more max-length Deflate match (258 bytes)
but not for a max-length Deflate64 match (65538 bytes, length code 285
with 16 extra bits). When a crafted/corrupted Deflate64 stream produced
a length-285 code with 65538 bytes of remaining freeBytes, OutputWindow
write tripped a Debug.Assert (No Enough space) and in Release silently
overran the window via modular arithmetic on WindowMask.

Introduce a named constant MaxMatchLength = 65538 and tighten the loop
guard to reeBytes >= MaxMatchLength. Also fix a swapped length/distance
comment in OutputWindow.cs so it matches reality.

Add a regression test using the fuzzer-discovered crash input from
src/libraries/Fuzzing/DotnetFuzzing/deployment/Deflate64Fuzzer/.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 12, 2026 11:28
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @karelz, @dotnet/area-system-io-compression
See info in area-owners.md if you want to be subscribed.

@github-actions

Copy link
Copy Markdown
Contributor

Caution

Security scanning requires review for Code Review

Details

The threat detection results could not be parsed. The workflow output should be reviewed before merging.

Review the workflow run logs for details.

🤖 Copilot Code Review — PR #128071

Note

This review was generated by GitHub Copilot.

Holistic Assessment

Motivation: The PR fixes a real off-by-one bug in the Deflate64 decompression loop guard. The maximum match length is 65538 (base 3 + 65535 extra bits), but the old condition freeBytes > 65536 allowed entering the loop with only 65537 free bytes, which is insufficient. This was found by fuzzing, confirming the bug is triggerable.

Approach: The fix correctly introduces a named constant MaxMatchLength = 65538 and changes the loop guard to freeBytes >= MaxMatchLength. This is the right fix at the right layer — ensuring the invariant (sufficient buffer space before decoding) is correctly maintained.

Summary: ✅ LGTM. The fix is correct, minimal, well-commented, and includes a regression test. The off-by-one analysis is sound: max length = 3 + 65535 = 65538, and the loop now correctly requires at least that many free bytes before decoding.


Detailed Findings

✅ Correctness — Off-by-one fix is correct

The old guard freeBytes > 65536 permitted entry with freeBytes = 65537. Length code 285 in Deflate64 has 16 extra bits with base length 3, yielding a max match of 65538 bytes. Writing 65538 bytes into 65537 bytes of space would overflow. The new guard freeBytes >= 65538 correctly prevents this.

✅ Comment correction in OutputWindow.cs

The old comment incorrectly stated "up to a 65536 length as well as up to a 65538 distance." The fix swaps these: max length is 65538 (3 + 65535), max distance is 65536 (2^16). This matches the Deflate64 spec.

✅ Test coverage

The regression test exercises both sync and async paths using a fuzzer-discovered input that triggers the exact overflow scenario. Using reflection to construct DeflateManagedStream directly is reasonable since the internal type is not publicly constructable, and the test validates the fix without requiring a full zip archive wrapper.

💡 Test uses reflection on internals

The test accesses DeflateManagedStream and ZipCompressionMethod via reflection. This is brittle if those types are renamed or restructured, but is an established pattern in this test file (see similar tests nearby) and is acceptable for testing internal decompression logic.

Generated by Code Review for issue #128071 · ● 1.8M ·

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

This PR tightens the Deflate64 managed inflater’s output-window space check to prevent an ArgumentOutOfRangeException when a malformed Deflate64 stream produces a maximum-length match, and adds a regression test reproducing the fuzzer input.

Changes:

  • Add a MaxMatchLength constant (65538) and use it to gate decoding on available OutputWindow space in InflaterManaged.DecodeBlock.
  • Correct Deflate64 max length/distance commentary in OutputWindow.
  • Add a regression test that feeds the fuzzer-produced Deflate64 payload through the managed Deflate64 decompressor and asserts InvalidDataException for both sync and async copy paths.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/libraries/System.IO.Compression/tests/ZipArchive/zip_InvalidParametersAndStrangeFiles.cs Adds a regression test ensuring a crafted Deflate64 stream fails with InvalidDataException (not ArgumentOutOfRangeException) in both sync/async paths.
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/OutputWindow.cs Updates the Deflate64 max length/distance comment to reflect the correct bounds.
src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/InflaterManaged.cs Introduces MaxMatchLength and uses it to avoid output-window overwrite when decoding Deflate64 length/distance pairs.

@iremyux iremyux 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.

LGTM

@rzikm

rzikm commented May 12, 2026

Copy link
Copy Markdown
Member Author

/ba-g maccatalyst failure is unrelated

@rzikm
rzikm merged commit 975134a into main May 12, 2026
88 of 94 checks passed
@rzikm
rzikm deleted the fix/deflate64-fuzzer-crash branch May 12, 2026 18:24
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants