zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 7a7d6a02a58f78d19769829df74f911448ebc3d7 (tree)
parent acfdad858138de029abcb1c9bf20df0e58738eb3
Author: dweiller <4678790+dweiller@users.noreply.github.com>
Date:   Mon, 31 Mar 2025 14:33:33 +1100

std.compress.zstd: fix OOB access in literal decode

When decoding the literals section of a compressed block, the length of
the regenerated size of the literals must be checked against the buffer
literals are decoded into.

Diffstat:
Mlib/std/compress/zstandard.zig | 19+++++++++++++++++++
Mlib/std/compress/zstandard/decode/block.zig | 1+
2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/lib/std/compress/zstandard.zig b/lib/std/compress/zstandard.zig @@ -289,3 +289,22 @@ test "zero sized block" { try expectEqualDecodedStreaming("", input_raw); try expectEqualDecodedStreaming("", input_rle); } + +test "declared raw literals size too large" { + const input_raw = + "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number + "\x00\x00" ++ // frame header: everything unset, window descriptor zero + "\x95\x00\x00" ++ // block header with: last_block set, block_type compressed, block_size 18 + "\xbc\xf3\xae" ++ // literals section header with: type raw, size_format 3, regenerated_size 716603 + "\xa5\x9f\xe3"; // some bytes of literal content - the content is shorter than regenerated_size + + // Note that the regenerated_size in the above input is larger than block maximum size, so the + // block can't be valid as it is a raw literals block. + + var fbs = std.io.fixedBufferStream(input_raw); + var window: [1024]u8 = undefined; + var stream = decompressor(fbs.reader(), .{ .window_buffer = &window }); + + var buf: [1024]u8 = undefined; + try std.testing.expectError(error.MalformedBlock, stream.read(&buf)); +} diff --git a/lib/std/compress/zstandard/decode/block.zig b/lib/std/compress/zstandard/decode/block.zig @@ -989,6 +989,7 @@ pub fn decodeLiteralsSection( const header = try decodeLiteralsHeader(source); switch (header.block_type) { .raw => { + if (buffer.len < header.regenerated_size) return error.LiteralsBufferTooSmall; try source.readNoEof(buffer[0..header.regenerated_size]); return LiteralsSection{ .header = header,