authorgravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-09-27 14:06:14-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 14:05:17-04:00
log1e805df81d51a338eefaff0535e5f1cca9e22028
tree5fa960d64889a9b741be90720417c3d5957ff265
parent754ea118bc7192b75c337ae95ad54dbe619dea56

deflate.zig: fix bits_left overflow at EndOfStream and @intCast truncation with empty Huffman table


1 files changed, 26 insertions(+), 6 deletions(-)

lib/std/compress/deflate.zig+26-6
......@@ -58,8 +58,10 @@ const Huffman = struct {
5858 }
5959
6060 // All zero.
61 if (self.count[0] == code_length.len)
61 if (self.count[0] == code_length.len) {
62 self.min_code_len = 0;
6263 return;
64 }
6365
6466 var left: isize = 1;
6567 for (self.count[1..]) |val| {
......@@ -280,7 +282,7 @@ pub fn InflateStream(comptime ReaderType: type) type {
280282 return self.bits & mask;
281283 }
282284 fn readBits(self: *Self, bits: usize) !u32 {
283 const val = self.peekBits(bits);
285 const val = try self.peekBits(bits);
284286 self.discardBits(bits);
285287 return val;
286288 }
......@@ -487,6 +489,8 @@ pub fn InflateStream(comptime ReaderType: type) type {
487489 // We can't read PREFIX_LUT_BITS as we don't want to read past the
488490 // deflate stream end, use an incremental approach instead.
489491 var code_len = h.min_code_len;
492 if (code_len == 0)
493 return error.OutOfCodes;
490494 while (true) {
491495 _ = try self.peekBits(code_len);
492496 // Small optimization win, use as many bits as possible in the
......@@ -658,11 +662,27 @@ test "lengths overflow" {
658662 // f dy hlit hdist hclen 16 17 18 0 (18) x138 (18) x138 (18) x39 (16) x6
659663 // 1 10 11101 11101 0000 010 010 010 010 (11) 1111111 (11) 1111111 (11) 0011100 (01) 11
660664 const stream = [_]u8{ 0b11101101, 0b00011101, 0b00100100, 0b11101001, 0b11111111, 0b11111111, 0b00111001, 0b00001110 };
665 try std.testing.expectError(error.InvalidLength, testInflate(stream[0..]));
666}
667
668test "empty distance alphabet" {
669 // dynamic block with empty distance alphabet is valid if end of data symbol is used immediately
670 // f dy hlit hdist hclen 16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15 (18) x128 (18) x128 (1) ( 0) (256)
671 // 1 10 00000 00000 1111 000 000 010 010 000 000 000 000 000 000 000 000 000 000 000 000 000 001 000 (11) 1110101 (11) 1110101 (0) (10) (0)
672 const stream = [_]u8{ 0b00000101, 0b11100000, 0b00000001, 0b00001001, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00010000, 0b01011100, 0b10111111, 0b00101110 };
673 try testInflate(stream[0..]);
674}
661675
662 const reader = std.io.fixedBufferStream(&stream).reader();
676test "inflateStream fuzzing" {
677 // see https://github.com/ziglang/zig/issues/9842
678 try std.testing.expectError(error.EndOfStream, testInflate("\x950000"));
679 try std.testing.expectError(error.OutOfCodes, testInflate("\x950\x00\x0000000"));
680}
681
682fn testInflate(data: []const u8) !void {
663683 var window: [0x8000]u8 = undefined;
684 const reader = std.io.fixedBufferStream(data).reader();
664685 var inflate = inflateStream(reader, &window);
665
666 var buf: [1]u8 = undefined;
667 try std.testing.expectError(error.InvalidLength, inflate.read(&buf));
686 var inflated = try inflate.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize));
687 defer std.testing.allocator.free(inflated);
668688}