Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free Video
DescriptionUse after free Video
ComponentChromium
Bug ClassUAF
Tracker518002958
Fix commit5f731169915a (chromium/src) +8/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-11

Changed Functions

FunctionChangeNotes
if
media/gpu/windows/d3d12_video_encode_accelerator.cc
modified

Files Changed

  • media/gpu/windows/d3d12_video_encode_accelerator.cc
From 5f731169915a1d6e0509af5b5b2d7ab4db265ba8 Mon Sep 17 00:00:00 2001
From: Qiu Jianlin <jianlin.qiu@intel.com>
Date: Mon, 01 Jun 2026 16:12:04 -0700
Subject: [PATCH] Avoid UAF of texture resources by D3D12 accelerator on destruction.

The input/upload texutre might be released before we destroy the copy
command wrapper. Make sure the copy command wrapper finish copy before
those resources are released.

Bug: 518002958
Change-Id: I3567d293f61e579b4dafec1759b11a5fb9f9fcbe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7886292
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Auto-Submit: Qiu, Jianlin <jianlin.qiu@intel.com>
Commit-Queue: Qiu, Jianlin <jianlin.qiu@intel.com>
Cr-Commit-Position: refs/heads/main@{#1639755}
---

diff --git a/media/gpu/windows/d3d12_video_encode_accelerator.cc b/media/gpu/windows/d3d12_video_encode_accelerator.cc
index c63ff71..ef4e5e067 100644
--- a/media/gpu/windows/d3d12_video_encode_accelerator.cc
+++ b/media/gpu/windows/d3d12_video_encode_accelerator.cc
@@ -413,6 +413,14 @@
   VLOGF(2);
   DCHECK_CALLED_ON_VALID_SEQUENCE(encoder_sequence_checker_);
 
+  // Wait for any in-flight copy to complete before the members are destroyed,
+  // so that the resources backing the copy (e.g. `upload_buffer_`,
+  // `input_texture_`) are not released while the GPU may still be reading from
+  // or writing to them.
+  if (copy_command_queue_) {
+    copy_command_queue_->WaitSync();
+  }
+
   if (!error_occurred_ && encoded_at_least_one_frame_) {
     base::UmaHistogramEnumeration(
         GetEncoderStatusHistogramName(config_.output_profile),
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential GPU Use-After-Free in D3D12VideoEncodeAccelerator due to member destruction order

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A potential Use-After-Free (UAF) / lifetime issue exists in D3D12VideoEncodeAccelerator on Windows because the persistent D3D12 resources are destroyed before the copy command queue blocks on GPU synchronization. Under specific conditions such as early validation failures or abrupt teardown, an active copy operation may still be executing on the GPU while the backing resources are freed. This can allow an attacker-controlled copy operation to read or write to released GPU memory heaps, potentially corrupting other GPU process allocations.

Affected files:

  • media/gpu/windows/d3d12_video_encode_accelerator.h
  • media/gpu/windows/d3d12_video_encode_accelerator.cc

Estimated timestamp from git blame: 2025-12-11

Summary

A potential Use-After-Free (UAF) / lifetime issue exists in D3D12VideoEncodeAccelerator on Windows due to the C++ declaration order of its member variables. When the accelerator is destroyed, the persistent resources input_texture_ and upload_buffer_ are released on the CPU before ~D3D12CopyCommandQueueWrapper() blocks on the GPU sync fence (WaitSync()). As a result, the GPU’s asynchronous COPY engine may still be reading from or writing to the underlying memory heaps of these resources after they are freed.

Root Cause Analysis

In media/gpu/windows/d3d12_video_encode_accelerator.h, the member variables are declared in the following order:

  std::unique_ptr<D3D12CopyCommandQueueWrapper> copy_command_queue_
      GUARDED_BY_CONTEXT(encoder_sequence_checker_);
  ...
  // Persistent D3D12 resources for if the input frame needs to be copied from
  // shared memory.
  Microsoft::WRL::ComPtr<ID3D12Resource> upload_buffer_
      GUARDED_BY_CONTEXT(encoder_sequence_checker_);
  Microsoft::WRL::ComPtr<ID3D12Resource> input_texture_
      GUARDED_BY_CONTEXT(encoder_sequence_checker_);

Under C++ rules, non-static class members are destroyed in the reverse order of their declaration. During the destruction of D3D12VideoEncodeAccelerator, input_texture_ (line 240) and upload_buffer_ (line 238) are released first. Only afterwards is copy_command_queue_ (line 210) destroyed, which triggers its destructor to wait on the CPU for the GPU copy operation to complete via WaitSync():

D3D12CopyCommandQueueWrapper::~D3D12CopyCommandQueueWrapper() {
  WaitSync();
}

Because the ID3D12Resource pointers are released before the wait is executed, their COM reference counts can drop to zero, prompting the D3D12 driver to immediately free or recycle the underlyingDEFAULT/UPLOAD memory heaps while the GPU COPY engine is still actively reading/writing to them.

Suggested / Potential Trigger Path

Because our automated tooling agent cannot run code, we do not have a working proof of concept, and the following is a potential trigger path:

  1. Initiate Encode: A compromised renderer sends an Encode() request containing a shared-memory–backed VideoFrame (STORAGE_SHMEM). This forces the GPU process to execute CreateResourceForSharedMemoryVideoFrame() (media/gpu/windows/d3d12_video_encode_accelerator.cc line 751).
  2. Execute Copy: The accelerator calls copy_command_queue_->CopyBufferToNV12Texture and executes it via copy_command_queue_->Execute() (line 832). This queues an asynchronous DMA transfer on the GPU’s COPY engine, reading from upload_buffer_ and writing to input_texture_.
  3. Early Rejection: If the renderer supplies invalid EncodeOptions (such as out-of-bounds reference buffers), the validation check inside D3D12VideoEncodeDelegate::Encode fails (line 277). It returns kBadReferenceBuffer early without calling the actual video encoder wrapper. This bypasses the typical SignalAndWaitCPU() call that would synchronize the GPU and CPU threads.
  4. Immediate Destruction: Simultaneously, the renderer closes the Mojo IPC pipe, which schedules a DestroyTask on the child sequence. This task executes delete this on D3D12VideoEncodeAccelerator.
  5. GPU UAF / Corruption: The destructor runs. Due to reverse destruction order, input_texture_ and upload_buffer_ are released. The GPU COPY engine continues to access the freed memory, causing a use-after-free on the GPU.

Proposed Remediation

This issue can be fixed by either:

  1. Reordering the member declarations in media/gpu/windows/d3d12_video_encode_accelerator.h so that copy_command_queue_ is declared after upload_buffer_ and input_texture_. This ensures ~D3D12CopyCommandQueueWrapper() executes its GPU wait block before the resources are destroyed.
  2. Alternatively, explicitly calling copy_command_queue_->WaitSync() inside the destructor ~D3D12VideoEncodeAccelerator() before any other members are released.

Evaluated with Chrome root at commit: fb72408a8493c46bc75fae1c70d03daec96b3040


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker