-
Notifications
You must be signed in to change notification settings - Fork 624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Large CPU and memory consumption on decoding a crafted GIF file #1052
Comments
|
Or just enough to be possible with 2^32 * 4 bytes ( |
For more on memory limits see #938 |
In fact, the code from #876 does implement a memory limit. I alluded to this in that other thread, but perhaps our new Reader API should have: /// Set the limit on total memory use. Attempting to read a file which would take more
/// space than this will fail with ImageError::InsufficientMemory. Defaults to 128MB, set to
/// `usize::MAX` to disable.
Reader::with_memory_limit(bytes: usize);
/// Set the limit on image size. Defaults to 16,384 x 16,384.
Reader::with_size_limit(width: u32, height: u32); |
Good catch, I had for some reason thought the limit was |
It's worth noting that the 2_000_000_000 bytes check is not actually there in the library. The code in #876 that does the check is just a fuzzing harness and is not present in the crate itself. |
I've updated the reproducing code to the latest version of These files blow past the explicitly set size and allocation limits to use up over 7GB memory in Code used: extern crate image;
use image::AnimationDecoder;
use image::io::Limits;
use std::fs::File;
use std::io::Read;
use std::env;
fn main() {
let filename = env::args().skip(1).next().expect("No file given");
println!("Decoding {:?}", filename);
let mut file = File::open(filename).unwrap();
let mut contents: Vec<u8> = Vec::new();
// Returns amount of bytes read and append the result to the buffer
let _num_read = file.read_to_end(&mut contents).unwrap();
gif_decode(&contents);
}
fn gif_decode(data: &[u8]) {
let mut limits = Limits::default();
limits.max_image_height = Some(16384); // 16384 * 16384 * 4 bytes per pixel = 1 GiB
limits.max_image_width = Some(16384);
limits.max_alloc = Some(1024 * 1024 * 1024); // 1 GiB
if let Ok(decoder) = image::codecs::gif::GifDecoder::with_limits(data, limits) {
let mut frames = decoder.into_frames();
while let Some(Ok(_)) = frames.next() {
// we don't use the frames for anything
}
}
} Notable differences from the previous code:
If I did the math right, both size and memory limiting are ineffective for these files - they both constrain memory usage to 1GiB, but I am seeing up to 7GiB memory usage in practice. |
If you call Really, we should deprecate |
Using These files still blow right past the allocation limit, but I'm not sure if that's even supported for |
It might be useful to at least do a crude check against the memory limit: |
Oh, there is native support for a memory limit in the It's just not wired up to |
Hmm, I think the But you can have a GIF image that decodes into up to |
I've opened a pull request for the Once that's merged and shipped, I can pass through the memory limit set in |
I just checked the However, the general convention in the image crate is that decoders should not count output buffers towards the allocation limit because the API of |
It is great that If I take the above code and uncomment the limits on the dimensions, it creates a very large output buffer and consumes 7GiB again. I suspect that check is not performed in |
The |
Tested on latest git commit as of this writing, ac93e75
Actual behavior
Decoding a crafted file mere 469 bytes in size takes over 7 gigabytes of memory. And not just virtual memory - it does get actually used and backed by physical memory.
This sample does not pose a problem as is, but it's possible that by applying the same technique it's possible to create very small files that OOM the system.
Expected
imagemagick rejects these files immediately. For the exact reason for each file see https://ncry.pt/p/6bPn#OPffqnjbN7RwGKJMwA0BQl3wuNlynKoUxw2dXZx9UKY
Reproduction steps
Same reproduction code as in #876
I'm attaching all samples classified as hangs by AFL so that you have the most complete info. The file
id:000002,src:000000+000052,op:splice,rep:128
is the most egregious in terms of time and memory consumption.image_gif_timeouts.zip
The text was updated successfully, but these errors were encountered: