Skip to content

Commit 1f08359

Browse files
committed
fix: enforce max_total_file_pixels in GIF decoder
Check cumulative decoded pixels (frame_count * w * h) against ExecutionSecurity::max_total_file_pixels after each frame advance. Applies both during frame-skipping (SelectFrame) and normal sequential decoding. Default limit is 400 megapixels.
1 parent a28f90a commit 1f08359

File tree

1 file changed

+24
-0
lines changed
  • imageflow_core/src/codecs/gif

1 file changed

+24
-0
lines changed

imageflow_core/src/codecs/gif/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ pub struct GifDecoder {
2626
next_frame: Option<Frame<'static>>,
2727
target_frame: Option<i32>,
2828
current_frame: i32,
29+
max_total_file_pixels: Option<u64>,
30+
pixels_per_frame: u64,
2931
}
3032

3133
impl GifDecoder {
@@ -83,6 +85,7 @@ impl GifDecoder {
8385
}
8486

8587
let screen = Screen::new(&reader);
88+
let pixels_per_frame = w as u64 * h as u64;
8689

8790
Ok(GifDecoder {
8891
reader,
@@ -92,9 +95,28 @@ impl GifDecoder {
9295
next_frame: None,
9396
target_frame: None,
9497
current_frame: 0,
98+
max_total_file_pixels: c.security.max_total_file_pixels,
99+
pixels_per_frame,
95100
})
96101
}
97102

103+
fn check_total_pixels(&self) -> Result<()> {
104+
if let Some(max) = self.max_total_file_pixels {
105+
let total = self.current_frame as u64 * self.pixels_per_frame;
106+
if total > max {
107+
return Err(nerror!(
108+
ErrorKind::SizeLimitExceeded,
109+
"GIF total decoded pixels ({} frames x {} pixels = {}) exceeds max_total_file_pixels {}",
110+
self.current_frame,
111+
self.pixels_per_frame,
112+
total,
113+
max
114+
));
115+
}
116+
}
117+
Ok(())
118+
}
119+
98120
fn read_next_frame_info(&mut self) -> Result<()> {
99121
self.last_frame = self.next_frame.take();
100122
// Currently clones local palette.
@@ -221,6 +243,7 @@ impl Decoder for GifDecoder {
221243
.map_err(|e| nerror!(ErrorKind::GifDecodingError, "{:?}", e))?;
222244

223245
self.current_frame += 1;
246+
self.check_total_pixels()?;
224247
self.read_next_frame_info().map_err(|e| e.at(here!()))?;
225248
}
226249
}
@@ -261,6 +284,7 @@ impl Decoder for GifDecoder {
261284
}
262285

263286
self.current_frame += 1;
287+
self.check_total_pixels()?;
264288

265289
// If we have a target frame, don't pre-fetch next frame (signals single-frame output)
266290
if self.target_frame.is_none() {

0 commit comments

Comments
 (0)