diff --git a/media/mojo/clients/mojo_video_encode_accelerator.cc b/media/mojo/clients/mojo_video_encode_accelerator.cc index 0000000..0000000 100644 --- a/media/mojo/clients/mojo_video_encode_accelerator.cc +++ b/media/mojo/clients/mojo_video_encode_accelerator.cc @@ -176,12 +176,43 @@ void MojoVideoEncodeAccelerator::Encode( DVLOG(2) << __func__ << " tstamp=" << frame->timestamp(); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(vea_.is_bound()); UMA_HISTOGRAM_ENUMERATION("Media.MojoVideoEncodeAccelerator.InputStorageType", frame->storage_type(), static_cast(VideoFrame::STORAGE_MAX) + 1); + + // --------------------------------------------------------------------------- + // POC INJECTION (compromised-renderer simulation, Windows only): + // + // The MFVEA SharedImage zero-copy path allocates a coded_size D3D11 texture + // with pInitialData=nullptr (uninitialised GPU VRAM), CopySubresourceRegion()s + // only |visible_rect| into it, then advertises the full texture to the vendor + // encoder MFT via SetCurrentLength(GetMaxLength()). PopulateInputSampleBufferGpu + // checks only visible_rect.size() == input_visible_size_ -- NOT the actual + // texture dimensions -- so an oversized coded_size texture passes through with + // its uninitialised tail intact. + // + // To trigger: ensure the SharedImage backing is strictly larger than + // input_visible_size_ (e.g. 1920x1088 for a 1920x1080 encoder), and shrink the + // VideoFrame's visible_rect to exactly input_visible_size_. Mojo traits at + // video_frame_mojom_traits.cc:233 only require visible_rect ⊆ coded_size and + // coded_size == shared_image->size(), both satisfied. + // --------------------------------------------------------------------------- + if (frame->HasSharedImage() && !frame->HasMappableSharedImage() && + frame->format() == PIXEL_FORMAT_NV12 && + frame->shared_image()->size().height() > frame->visible_rect().height()) { + // Re-wrap the (oversized) SharedImage with visible_rect == configured + // input_visible_size_ so PopulateInputSampleBufferGpu's check at :2395 + // passes and the under-written coded_size texture is handed straight to the + // encoder MFT. + LOG(ERROR) << "[POC] sending oversized SharedImage frame: si=" + << frame->shared_image()->size().ToString() + << " coded=" << frame->coded_size().ToString() + << " visible=" << frame->visible_rect().ToString(); + } vea_->Encode(frame, options, base::DoNothingWithBoundArgs(frame)); } void MojoVideoEncodeAccelerator::UseOutputBitstreamBuffer( diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc index 0000000..0000000 100644 --- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc +++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc @@ -1,3 +1,29 @@ +// --------------------------------------------------------------------------- +// POC NOTE (compromised-renderer simulation): +// +// A real exploit does NOT depend on WebCodecs producing an oversized +// SharedImage by accident. A compromised renderer: +// +// 1. Binds media.mojom.VideoEncodeAcceleratorProvider via +// Platform::Current()->GetBrowserInterfaceBroker() and calls +// CreateVideoEncodeAccelerator() with a valid EncodeCommandBufferId +// (channel_token + route_id from its existing GPU channel). +// 2. Calls Initialize(input_format=NV12, input_visible_size=1920x1080, +// output_profile=H264PROFILE_BASELINE, storage_type=kGpuMemoryBuffer). +// 3. Uses gpu::SharedImageInterface (already exposed to the renderer for +// WebGL/canvas) to CreateSharedImage(viz::MultiPlaneFormat::kNV12, +// gfx::Size(1920, 1088), ...). +// 4. Builds a media::VideoFrame via VideoFrame::WrapSharedImage( +// PIXEL_FORMAT_NV12, shared_image, sync_token, ReleaseMailboxCB(), +// /*visible_rect=*/gfx::Rect(0, 0, 1920, 1080), +// /*natural_size=*/gfx::Size(1920, 1080), timestamp); +// -> coded_size is taken from shared_image->size() == 1920x1088. +// 5. Calls vea_remote->Encode(frame, {force_keyframe=true}). +// 6. Receives the H.264 bitstream via BitstreamBufferReady, decodes it, and +// reads luma rows [1080,1088) / chroma rows [540,544) -> stale GPU VRAM. +// --------------------------------------------------------------------------- + // Copyright 2020 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.