I was trying to invent a toy zip-bomb while doing an exercise at Exercism and noticed an integer overflow in std.Io.Writer interface:
test "Io.Writer does not integer overflow" {
var w: std.Io.Writer.Discarding = .init(&.{});
_ = try w.writer.writeSplat(&.{"A", "B"}, std.math.maxInt(usize));
}
It crashes:
$ zig test example.zig
thread 380898 panic: integer overflow
zig-x86_64-linux-0.16.0/lib/std/Io/Writer.zig:162:11: 0x1042243 in countSplat (std.zig)
total += data[data.len - 1].len * splat;
^
zig-x86_64-linux-0.16.0/lib/std/Io/Writer.zig:184:29: 0x10413c7 in writeSplat (std.zig)
const count = countSplat(data, splat);
^
example.zig:19:32: 0x124f2e7 in test_0 (example.zig)
_ = try w.writer.writeSplat(&.{"A", "B"}, std.math.maxInt(usize));
Is it a bug in standard library or am I using it wrong? I did not expect anything to actually crash.
i’d argue you’re using it wrong, although i could see arguments against this. if you cannot address the total number of bites you want to write, you should not be writing that many bytes.
The exercise is to write a Run-Length Encoding compressor and decompressor. My compressor implements Io.Writer interface and decompressor implements Io.Reader interface. Then I chain them to test if they decompress and compress back to the original:
The compressed input is a zip bomb that would decompress into maxInt(usize) bytes. But the interfaces interact through splatByteAll() method and do not need to allocate millions of terabytes. I was testing my implementation with different edge case inputs to catch all integer overflows in my code. Then I discovered an overflow in the standard library.
I am not a security expert. I do not know if there is a way to throw a malicious compressed file at some program and trigger a vulnerability.