From b1fad7bbed5f736e34c7a718ecc4f54c3c33f0aa Mon Sep 17 00:00:00 2001 From: FrederickStempfle Date: Sun, 26 Jul 2026 02:56:22 +0200 Subject: [PATCH] fix: validate RGBA clipboard dimensions (#15672) --- src/clipboard.rs | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/clipboard.rs b/src/clipboard.rs index 01dc0c9ed..c7c01d6c4 100644 --- a/src/clipboard.rs +++ b/src/clipboard.rs @@ -36,6 +36,17 @@ const CLIPBOARD_GET_MAX_RETRY: usize = 3; #[cfg(not(target_os = "android"))] const CLIPBOARD_GET_RETRY_INTERVAL_DUR: Duration = Duration::from_millis(33); +#[cfg(not(target_os = "android"))] +fn valid_rgba_dimensions(width: i32, height: i32, data_len: usize) -> Option<(usize, usize)> { + let width = usize::try_from(width).ok()?; + let height = usize::try_from(height).ok()?; + if width == 0 || height == 0 { + return None; + } + let expected_len = width.checked_mul(height)?.checked_mul(4)?; + (data_len == expected_len).then_some((width, height)) +} + #[cfg(not(target_os = "android"))] const SUPPORTED_FORMATS: &[ClipboardFormat] = &[ ClipboardFormat::Text, @@ -722,11 +733,15 @@ mod proto { Ok(ClipboardFormat::Text) => String::from_utf8(data).ok().map(ClipboardData::Text), Ok(ClipboardFormat::Rtf) => String::from_utf8(data).ok().map(ClipboardData::Rtf), Ok(ClipboardFormat::Html) => String::from_utf8(data).ok().map(ClipboardData::Html), - Ok(ClipboardFormat::ImageRgba) => Some(ClipboardData::Image(arboard::ImageData::rgba( - clipboard.width as _, - clipboard.height as _, - data.into(), - ))), + Ok(ClipboardFormat::ImageRgba) => { + let (width, height) = + super::valid_rgba_dimensions(clipboard.width, clipboard.height, data.len())?; + Some(ClipboardData::Image(arboard::ImageData::rgba( + width, + height, + data.into(), + ))) + } Ok(ClipboardFormat::ImagePng) => { Some(ClipboardData::Image(arboard::ImageData::png(data.into()))) } @@ -770,6 +785,22 @@ mod proto { } } +#[cfg(all(test, not(target_os = "android")))] +mod rgba_tests { + use super::valid_rgba_dimensions; + + #[test] + fn validates_dimensions_against_content_length() { + assert_eq!(valid_rgba_dimensions(1, 1, 4), Some((1, 1))); + assert_eq!(valid_rgba_dimensions(1, 1, 3), None); + assert_eq!(valid_rgba_dimensions(-1, 1, 4), None); + assert_eq!(valid_rgba_dimensions(0, 1, 0), None); + assert_eq!(valid_rgba_dimensions(i32::MAX, i32::MAX, 4), None); + #[cfg(target_pointer_width = "32")] + assert_eq!(valid_rgba_dimensions(i32::MAX, 2, 0), None); + } +} + #[cfg(target_os = "android")] pub fn handle_msg_clipboard(mut cb: Clipboard) { use hbb_common::protobuf::Message;