PDF: write with craft-libs' krilla, which bounds decoded PNGs (#1240)

* PDF: write with craft-libs' krilla, which bounds decoded PNGs

* PDF: pin craft-libs' krilla at 9f75d3dc
This commit is contained in:
aiongg
2026-10-23 22:46:21 -04:00
committed by GitHub
parent 8167f13a6a
commit c668e21759
3 changed files with 33 additions and 2 deletions
Generated
+1 -2
View File
@@ -2613,8 +2613,7 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]] [[package]]
name = "krilla" name = "krilla"
version = "0.8.2" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/storytold/craft-libs?rev=9f75d3dc19b4b514c4f3d4847ed1ec1b0e86b4ef#9f75d3dc19b4b514c4f3d4847ed1ec1b0e86b4ef"
checksum = "27da593198b20eeba65caeb73c2bbeec3e53ab08fa549898312ce81c4fce5e33"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bumpalo", "bumpalo",
+5
View File
@@ -128,3 +128,8 @@ codegen-units = 1
debug = false debug = false
strip = true strip = true
panic = "abort" panic = "abort"
# craft-libs' vendored krilla 0.8.2: decoded PNGs are capped at 1 GiB and reserved fallibly, and a
# panic while drawing unwinds without aborting.
[patch.crates-io]
krilla = { git = "https://github.com/storytold/craft-libs", rev = "9f75d3dc19b4b514c4f3d4847ed1ec1b0e86b4ef" }
+27
View File
@@ -271,3 +271,30 @@ fn sample_files() {
std::fs::write(format!("{stem}-{}.pdf", i + 1), export_pdf(&d, &[*f], &PdfOptions::default()).unwrap()).unwrap(); std::fs::write(format!("{stem}-{}.pdf", i + 1), export_pdf(&d, &[*f], &PdfOptions::default()).unwrap()).unwrap();
} }
} }
/// A tiny PNG whose header claims 30,000 × 30,000 RGBA (3.6 GB decoded) is refused when it is read,
/// before anything is decoded: the PDF writer is craft-libs' patched krilla.
#[test]
fn a_png_that_decodes_too_large_is_refused() {
fn chunk(out: &mut Vec<u8>, kind: &[u8; 4], data: &[u8]) {
out.extend_from_slice(&u32::try_from(data.len()).unwrap().to_be_bytes());
let mut crc = flate2::Crc::new();
crc.update(kind);
crc.update(data);
out.extend_from_slice(kind);
out.extend_from_slice(data);
out.extend_from_slice(&crc.sum().to_be_bytes());
}
let mut ihdr = Vec::new();
ihdr.extend_from_slice(&30_000u32.to_be_bytes());
ihdr.extend_from_slice(&30_000u32.to_be_bytes());
ihdr.extend_from_slice(&[8, 6, 0, 0, 0]);
let mut z = flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default());
std::io::Write::write_all(&mut z, &[0; 64]).unwrap();
let mut png = b"\x89PNG\r\n\x1a\n".to_vec();
chunk(&mut png, b"IHDR", &ihdr);
chunk(&mut png, b"IDAT", &z.finish().unwrap());
chunk(&mut png, b"IEND", &[]);
const { assert!(krilla::CRAFT_UNWIND_SAFE_DROP) };
assert!(krilla::image::Image::from_png(krilla::Data::from(png), true).is_err());
}