ianic/flate

Integer overflow on 'lengths overflow' test case

squeek502 opened this issue · 0 comments

In attempting to get some fuzz testing going, flate hits an integer overflow on one of the test cases from Zig:

https://github.com/ziglang/zig/blob/3122fd0ba0eb4cdb17616658b462a255a37f1ad7/lib/std/compress/deflate/decompressor.zig#L1058-L1067

Reproduction:

const std = @import("std");
const flate = @import("flate");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer std.debug.assert(gpa.deinit() == .ok);
    const allocator = gpa.allocator();

    const data = "\xed\x1d$\xe9\xff\xff9\x0e";

    var fbs = std.io.fixedBufferStream(data);
    const reader = fbs.reader();
    var inflate = flate.raw.decompressor(reader);

    const inflated = inflate.reader().readAllAlloc(allocator, std.math.maxInt(usize)) catch {
        return;
    };
    defer allocator.free(inflated);
}

Stack trace:

thread 19052 panic: integer overflow
/home/ryan/Programming/zig/flate/src/inflate.zig:193:54: 0x1099d57 in dynamicCodeLength (decompress)
                        lens[pos + i] = lens[pos + i - 1];
                                                     ^
/home/ryan/Programming/zig/flate/src/inflate.zig:170:50: 0x109d14c in dynamicBlockHeader (decompress)
                pos += try self.dynamicCodeLength(sym.symbol, &dst_l, pos);
                                                 ^
/home/ryan/Programming/zig/flate/src/inflate.zig:248:74: 0x10a39d1 in step (decompress)
                    if (self.block_type == 2) try self.dynamicBlockHeader();
                                                                         ^
/home/ryan/Programming/zig/flate/src/inflate.zig:310:30: 0x1060ac2 in get (decompress)
                try self.step();
                             ^
/home/ryan/Programming/zig/flate/src/inflate.zig:322:37: 0x105c84a in read (decompress)
            const out = try self.get(buffer.len);
                                    ^
/home/ryan/Programming/zig/zig/lib/std/io.zig:331:26: 0x1057cdd in typeErasedReadFn (decompress)
            return readFn(ptr.*, buffer);
                         ^
/home/ryan/Programming/zig/zig/lib/std/io/Reader.zig:10:23: 0x10ad58b in read (decompress)
    return self.readFn(self.context, buffer);
                      ^
/home/ryan/Programming/zig/zig/lib/std/io/Reader.zig:29:34: 0x10ac3fc in readAtLeast (decompress)
        const amt = try self.read(buffer[index..]);
                                 ^
/home/ryan/Programming/zig/zig/lib/std/io/Reader.zig:17:23: 0x107bfa0 in readAll (decompress)
    return readAtLeast(self, buffer, buffer.len);
                      ^
/home/ryan/Programming/zig/zig/lib/std/io/Reader.zig:67:44: 0x1060cdd in readAllArrayListAligned__anon_4972 (decompress)
        const bytes_read = try self.readAll(dest_slice);
                                           ^
/home/ryan/Programming/zig/zig/lib/std/io/Reader.zig:52:40: 0x105cb8b in readAllArrayList (decompress)
    return self.readAllArrayListAligned(null, array_list, max_append_size);
                                       ^
/home/ryan/Programming/zig/zig/lib/std/io/Reader.zig:92:30: 0x1057ded in readAllAlloc (decompress)
    try self.readAllArrayList(&array_list, max_size);
                             ^
/home/ryan/Programming/zig/zig/lib/std/io.zig:167:54: 0x1057a5f in main (decompress)
            return @errorCast(self.any().readAllAlloc(allocator, max_size));
                                                     ^
/home/ryan/Programming/zig/zig/lib/std/start.zig:585:37: 0x10578c7 in posixCallMainAndExit (decompress)
            const result = root.main() catch |err| {
                                    ^
/home/ryan/Programming/zig/zig/lib/std/start.zig:253:5: 0x10573f1 in _start (decompress)
    asm volatile (switch (native_arch) {
    ^
???:?:?: 0x0 in ??? (???)
Aborted