From 413707da33041d01383712bb33e3f585465ae833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Sat, 12 Sep 2026 15:40:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E5=89=8D=E6=8B=92=E7=BB=9D=E9=AB=98?= =?UTF-8?q?=E4=BD=8D=E6=B7=B1=20PNG=20=E8=A7=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 通过 image crate 的 ImageReader decoder 元数据在像素缓冲分配前拒绝 16-bit PNG。 继续使用同一外部 decoder 执行受限像素读取校验,不手写 PNG 解析器。 --- server-rs/crates/api-server/src/raw_image.rs | 26 ++++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/server-rs/crates/api-server/src/raw_image.rs b/server-rs/crates/api-server/src/raw_image.rs index bead3a52e..6f3b55c52 100644 --- a/server-rs/crates/api-server/src/raw_image.rs +++ b/server-rs/crates/api-server/src/raw_image.rs @@ -4,7 +4,7 @@ use axum::{ http::StatusCode, }; use bytes::Bytes; -use image::{GenericImageView, ImageFormat, ImageReader}; +use image::{ImageDecoder, ImageFormat, ImageReader}; use platform_image::{ GPT_IMAGE_2_2K_LONG_EDGE_THRESHOLD, RAW_IMAGE_MAX_EDGE, RAW_IMAGE_MAX_PIXELS, RawImageEditImage, RawImageEditOptions, create_vector_engine_raw_image_edit, @@ -393,11 +393,11 @@ fn decode_image( if reader.format() != Some(ImageFormat::Png) { return Err(bad_request(format!("{field} 文件必须是有效 PNG 文件"))); } - let decoded = reader - .decode() + let decoder = reader + .into_decoder() .map_err(|error| map_decode_image_error(field, error))?; if matches!( - decoded.color(), + decoder.color_type(), image::ColorType::Rgba16 | image::ColorType::Rgb16 | image::ColorType::L16 @@ -407,7 +407,23 @@ fn decode_image( "{field} 必须为 8-bit PNG(每通道 8 位)" ))); } - let (width, height) = decoded.dimensions(); + let (width, height) = decoder.dimensions(); + let decoded_bytes = usize::try_from(decoder.total_bytes()).map_err(|_| { + bad_request(format!( + "{field} 文件超出 PNG 尺寸或解码资源上限(单边不超过 {RAW_IMAGE_MAX_EDGE}px)" + )) + })?; + let max_decoded_bytes = + usize::try_from(RAW_IMAGE_MAX_PIXELS.saturating_mul(4)).unwrap_or(usize::MAX); + if decoded_bytes > max_decoded_bytes { + return Err(bad_request(format!( + "{field} 文件超出 PNG 尺寸或解码资源上限(单边不超过 {RAW_IMAGE_MAX_EDGE}px)" + ))); + } + let mut decoded = vec![0_u8; decoded_bytes]; + decoder + .read_image(&mut decoded) + .map_err(|error| map_decode_image_error(field, error))?; Ok(( RawImageEditImage { bytes,