| author | |
| committer | |
| log | 60b0b2129664d6e97822c8ce815518c6a48f9203 |
| tree | 451da90a263939d8aa45e9e6f0dedf7cdaf276fe |
| parent | 59de7e3a5725f0c4eeb64bc464db85e019af7446 |
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.2 files changed, 18 insertions(+), 1 deletions(-)
lib/std/compress/zstd.zig+6| ... | @@ -121,6 +121,12 @@ test Decompress { | ... | @@ -121,6 +121,12 @@ test Decompress { |
| 121 | try testExpectDecompress(uncompressed, compressed19); | 121 | try testExpectDecompress(uncompressed, compressed19); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 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 | |||
| 124 | test "zero sized raw block" { | 130 | test "zero sized raw block" { |
| 125 | const input_raw = | 131 | const input_raw = |
| 126 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number | 132 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number |
lib/std/compress/zstd/Decompress.zig+12-1| ... | @@ -158,7 +158,18 @@ fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { | ... | @@ -158,7 +158,18 @@ fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { |
| 158 | 158 | ||
| 159 | switch (d.state) { | 159 | switch (d.state) { |
| 160 | .new_frame => { | 160 | .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 | }; | ||
| 162 | const magic = try in.takeEnumNonexhaustive(Frame.Magic, .little); | 173 | const magic = try in.takeEnumNonexhaustive(Frame.Magic, .little); |
| 163 | initFrame(d, w.buffer.len, magic) catch |err| { | 174 | initFrame(d, w.buffer.len, magic) catch |err| { |
| 164 | d.err = err; | 175 | d.err = err; |