Skip to content

read: bound zstd-decompressed size to the declared size#951

Open
scadastrangelove wants to merge 1 commit into
gimli-rs:mainfrom
scadastrangelove:fix/zstd-decompress-size-cap
Open

read: bound zstd-decompressed size to the declared size#951
scadastrangelove wants to merge 1 commit into
gimli-rs:mainfrom
scadastrangelove:fix/zstd-decompress-size-cap

Conversation

@scadastrangelove

Copy link
Copy Markdown

Fixes #950.

The Zstandard branch of CompressedData::decompress grows decompressed past the try_reserve_exact(size) reservation that the Zlib branch respects (decompress_vec stays within its reserved capacity, read_to_end does not). So a section declaring a small ch_size can allocate the full decoded size of a large-expanding zstd stream before the trailing size != decompressed.len() check rejects it.

This bounds the zstd read to size (plus one byte, so the existing size check still rejects an over-long stream), so the allocation can no longer exceed the declared uncompressed size.

Verified against main:

Discovered by the rust-in-peace security pipeline.

CompressedData::decompress reserves try_reserve_exact(size) for the
header-declared uncompressed size, but the Zstandard branch's read_to_end
grows the buffer to the actual decoded length, ignoring that reservation
(the Zlib branch stays bounded by its reserved capacity via decompress_vec).
A section declaring a small ch_size but carrying a stream that expands to
gigabytes therefore allocates the full decoded size before the trailing
size != decompressed.len() check can reject it.

Bound the zstd read to size (+1 so the existing size check still rejects an
over-long stream), so the allocation can no longer exceed the declared size.

Discovered by the rust-in-peace security pipeline
(https://github.com/scadastrangelove/rust-in-peace/).
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.

Zstandard-compressed section decodes past the declared size (unbounded allocation / OOM)

1 participant