From 95ee5708fa432a2903d39c40df5e38ff435f30c1 Mon Sep 17 00:00:00 2001 From: Andrei Volykhin Date: Thu, 17 Apr 2025 09:41:23 +0300 Subject: [PATCH] imagedata: Fix overflow panic for too large ImageData (#36569) In Servo debug build there are runtime crash due to "attempt to multiply with overflow" panic in case of creation too large ImageData (new ImageData(1<<31, 1<<31)) Use checked integer multiplication to catch occurred overflow and throwing JS error (RangeError OR IndexSizeError). -- - [x] ./mach build -d does not report any errors - [x] ./mach test-tidy does not report any errors - [x] There are tests for these changes tests/wpt/tests/html/canvas/element/pixel-manipulation/2d.imageData.object.ctor.basics.html Signed-off-by: Andrei Volykhin --- components/script/dom/imagedata.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs index d49d17d3bf9..bd45a80fce2 100644 --- a/components/script/dom/imagedata.rs +++ b/components/script/dom/imagedata.rs @@ -41,7 +41,15 @@ impl ImageData { mut data: Option>, can_gc: CanGc, ) -> Fallible> { - let len = width * height * 4; + // The color components of each pixel must be stored in four sequential + // elements in the order of red, green, blue, and then alpha. + let len = 4u32 + .checked_mul(width) + .and_then(|v| v.checked_mul(height)) + .ok_or(Error::Range( + "The requested image size exceeds the supported range".to_owned(), + ))?; + unsafe { let cx = GlobalScope::get_cx(); rooted!(in (*cx) let mut js_object = ptr::null_mut::()); @@ -119,8 +127,17 @@ impl ImageData { if width == 0 || height == 0 { return Err(Error::IndexSize); } + + // The color components of each pixel must be stored in four sequential + // elements in the order of red, green, blue, and then alpha. + // Please note when a too-large ImageData is created using a constructor + // historically throwns an IndexSizeError, instead of RangeError. + let len = 4u32 + .checked_mul(width) + .and_then(|v| v.checked_mul(height)) + .ok_or(Error::IndexSize)?; + let cx = GlobalScope::get_cx(); - let len = width * height * 4; let heap_typed_array = match new_initialized_heap_buffer_source::( HeapTypedArrayInit::Info { len, cx }, @@ -173,7 +190,7 @@ impl ImageData { } impl ImageDataMethods for ImageData { - /// + /// fn Constructor( global: &GlobalScope, proto: Option, @@ -184,7 +201,7 @@ impl ImageDataMethods for ImageData { Self::new_without_jsobject(global, proto, width, height, can_gc) } - /// + /// fn Constructor_( _cx: JSContext, global: &GlobalScope,