Skip to content

Commit 60b0b21

Browse files
committed
zstd.Decompress: Treat a partial magic number as a failure
Previously, the "allow EndOfStream" part of this logic was too permissive. If there are a few dangling bytes at the end of the stream, that should be treated as a bad magic number. The only case where EndOfStream is allowed is when the stream is truly at the end, with exactly zero bytes available.
1 parent 59de7e3 commit 60b0b21

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

lib/std/compress/zstd.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ test Decompress {
121121
try testExpectDecompress(uncompressed, compressed19);
122122
}
123123

124+
test "partial magic number" {
125+
const input_raw =
126+
"\x28\xb5\x2f"; // 3 bytes of the 4-byte zstandard frame magic number
127+
try testExpectDecompressError(error.BadMagic, input_raw);
128+
}
129+
124130
test "zero sized raw block" {
125131
const input_raw =
126132
"\x28\xb5\x2f\xfd" ++ // zstandard frame magic number

lib/std/compress/zstd/Decompress.zig

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,18 @@ fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
158158

159159
switch (d.state) {
160160
.new_frame => {
161-
// Allow error.EndOfStream only on the frame magic.
161+
// Only return EndOfStream when there are exactly 0 bytes remaining on the
162+
// frame magic. Any partial magic bytes should be considered a failure.
163+
in.fill(@sizeOf(Frame.Magic)) catch |err| switch (err) {
164+
error.EndOfStream => {
165+
if (in.bufferedLen() != 0) {
166+
d.err = error.BadMagic;
167+
return error.ReadFailed;
168+
}
169+
return err;
170+
},
171+
else => |e| return e,
172+
};
162173
const magic = try in.takeEnumNonexhaustive(Frame.Magic, .little);
163174
initFrame(d, w.buffer.len, magic) catch |err| {
164175
d.err = err;

0 commit comments

Comments
 (0)