diff --git a/components/eye_dropper/eye_dropper_view.cc b/components/eye_dropper/eye_dropper_view.cc index 1bff11db91509..1b8d4697465d4 100644 --- a/components/eye_dropper/eye_dropper_view.cc +++ b/components/eye_dropper/eye_dropper_view.cc @@ -158,8 +158,21 @@ void EyeDropperView::ScreenCapturer::OnCaptureResult( // TODO(crbug.com/352187279): Support other pixel formats. CHECK_EQ(frame->pixel_format(), webrtc::FOURCC_ARGB); frame_.allocN32Pixels(frame->size().width(), frame->size().height(), true); - UNSAFE_TODO(memcpy(frame_.getAddr32(0, 0), frame->data(), - frame->size().height() * frame->stride())); + // Copy row-by-row honouring the source stride. The destination is tightly + // packed (rowBytes == width*4) but the source DesktopFrame may have a larger + // stride (e.g. on ChromeOS the stride originates from a less-privileged + // process via viz.mojom.BitmapInSharedMemory.row_bytes), so a single memcpy + // of height*stride bytes would overflow the destination. + const size_t dst_stride = frame_.rowBytes(); + const size_t src_stride = static_cast(frame->stride()); + const size_t row_bytes = std::min(dst_stride, src_stride); + uint8_t* dst = reinterpret_cast(frame_.getAddr32(0, 0)); + const uint8_t* src = frame->data(); + for (int y = 0; y < frame->size().height(); ++y) { + UNSAFE_TODO(memcpy(dst, src, row_bytes)); + UNSAFE_TODO(dst += dst_stride); + UNSAFE_TODO(src += src_stride); + } frame_.setImmutable(); // The captured frame is in full desktop coordinates. E.g. the top left diff --git a/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc b/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc index 9d6bdd42622df..bc9c7d6521522 100644 --- a/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc +++ b/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc @@ -93,6 +93,13 @@ bool StructTraits::Read( return false; if (!image_info.validRowBytes(data.row_bytes())) return false; + // The sender (above) always emits minRowBytes(); reject anything larger so a + // compromised peer cannot inflate stride into downstream consumers (e.g. + // EyeDropperView::ScreenCapturer::OnCaptureResult on ChromeOS does + // memcpy(height * stride) over a width*height*4 allocation). + if (data.row_bytes() != image_info.minRowBytes()) { + return false; + } std::optional region_opt; if (!data.ReadPixels(®ion_opt))