mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-22 03:32:39 -05:00
Merge pull request #1566 from midasmatterhorn/fix/r4-inline-len-overflow
pdf: an inline image with absurd dimensions falls back to the EI scan
This commit is contained in:
3 files changed
+21
-2
No files matched your search
@@ -82,7 +82,10 @@ pub(crate) fn inline_len(file: &File, d: &Dict, res: Option<&Dict>) -> Option<us
|
||||
let mask = matches!(file.get(d, "ImageMask"), Some(Obj::Bool(true)));
|
||||
let bpc = if mask { 1 } else { file.get_num(d, "BitsPerComponent").unwrap_or(8.0) as usize };
|
||||
let n = if mask { 1 } else { file.get(d, "ColorSpace").map(|c| color_space(file, c, res).components()).unwrap_or(1) };
|
||||
Some((w * n * bpc).div_ceil(8) * h)
|
||||
// `Width`/`Height` come straight from the file and can be enormous: fall back to the
|
||||
// `EI` scan (the caller's `None` branch) instead of overflowing the arithmetic.
|
||||
let row = w.checked_mul(n)?.checked_mul(bpc)?.div_ceil(8);
|
||||
row.checked_mul(h)
|
||||
}
|
||||
|
||||
/// Decode an image's samples (all filters, including DCT). Returns (bytes, components from
|
||||
|
||||
@@ -515,7 +515,7 @@ impl<'a> Interp<'a> {
|
||||
&& (p + 2 == data.len() || crate::object::is_white(data[p + 2]))
|
||||
};
|
||||
let end = match crate::image::inline_len(self.file, &d, Some(res)) {
|
||||
Some(len) => (start + len).min(data.len()),
|
||||
Some(len) => start.saturating_add(len).min(data.len()),
|
||||
None => {
|
||||
let mut p = start;
|
||||
while p + 1 < data.len() && !is_ei(p) {
|
||||
|
||||
@@ -263,6 +263,22 @@ fn hostile_structures_return_errors_or_draw_nothing() {
|
||||
assert!(!doc.skipped.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inline_image_with_absurd_dimensions_falls_back_to_ei_scan() {
|
||||
// `/W 5000000000000000000` overflows the row math (`* bpc` alone exceeds usize::MAX):
|
||||
// `inline_len` must return `None` (scan for `EI`) instead of overflowing; the oversized
|
||||
// image itself is then refused by size.
|
||||
let bytes = page_pdf("q 10 0 0 10 0 0 cm BI /W 5000000000000000000 /H 100 /CS /G /BPC 8 ID \0 EI Q", "", vec![]);
|
||||
let doc = parse(&bytes).unwrap();
|
||||
let _ = render(&doc);
|
||||
assert!(!doc.skipped.is_empty());
|
||||
// A length just under `usize::MAX` passes the row math; past byte 4096 of the content the
|
||||
// caller's `start + len` would then overflow.
|
||||
let content = format!("{}q 10 0 0 10 0 0 cm BI /W 2305843009213693440 /H 8 /CS /G /BPC 8 ID | ||||