image icon indicating copy to clipboard operation
image copied to clipboard

OOM in PNG decoding despite a memory limit and dimension limits being set

Open Shnatsel opened this issue 3 years ago • 3 comments

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

Shnatsel avatar Jul 04 '22 18:07 Shnatsel

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

Shnatsel avatar Jul 04 '22 18:07 Shnatsel

FWIW I could not trigger similar failures in JPEG or TIFF.

Shnatsel avatar Jul 04 '22 20:07 Shnatsel

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.

fintelia avatar Aug 10 '22 00:08 fintelia

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

fintelia avatar Jan 16 '24 03:01 fintelia