OOM in PNG decoding despite a memory limit and dimension limits being set
image OOMs when attempting to decode a crafted PNG file, discovered by fuzzer.
The fuzzer uses image::load_from_memory_with_format() which, according to the documentation, has a default memory limit of 512Mb. However, the decoding process actually allocates way more than that.
I have tried setting the limit explicitly, just in case, and got the same OOM:
let mut reader = image::io::Reader::new(Cursor::new(data));
reader.set_format(image::ImageFormat::Png);
reader.limits(image::io::Limits::default());
let _ = reader.decode();
This happens on commit 04052e64c9a94606efc8bd3d87d5f3e0f566774e
Reproduction steps
cargo +nightly fuzz run --release fuzzer_script_png path/to/file.png
The file to trigger it: oom-cf5aeccc25f220c487c913b20c285a860e302ffc.png
Even setting width and height limits to cap the output at ~130Mb doesn't help. The following code still OOMs:
let mut reader = image::io::Reader::new(std::io::Cursor::new(data));
reader.set_format(image::ImageFormat::Png);
let mut limits = image::io::Limits::default();
// add limits to stop the fuzzer from OOMing
limits.max_image_width = Some(4096);
limits.max_image_height = Some(4096);
reader.limits(limits);
let _ = reader.decode();
on this input: oom-cf5aeccc25f220c487c913b20c285a860e302ffc
FWIW I could not trigger similar failures in JPEG or TIFF.
There's a simple explanation for this issue... PngDecoder ignores any user limits and always creates an underlying decoder that uses an unbounded amount of memory: https://github.com/image-rs/image/blob/c24aecb954b0c9ae96ebdacd023140e323de2d75/src/codecs/png.rs#L120-L123
Unfortunately this is a bit annoying to fix because right now the png crate does potentially large allocations in the constructor, while the ImageDecoder trait allows you to set limits after the object has been created.
This was fixed in https://github.com/image-rs/image/pull/1812 for load_from_memory_with_format.
Remaining work is being tracked in https://github.com/image-rs/image/issues/2084