CVE-2026-15122
Overview
Files Changed
media/gpu/windows/d3d12_video_encode_h264_delegate.ccmedia/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc
Patch
From bc4a64d30b6903080223ace65989ed8ec923cc5b Mon Sep 17 00:00:00 2001 From: Qiu Jianlin <[email protected]> Date: Mon, 22 Jun 2026 19:56:38 -0700 Subject: [PATCH] Cap H264 max_num_ref_frames_ by MaxLongTermReferences. Cap max_num_ref_frames_ at min(MaxDPBCapacity, MaxLongTermReferences + 1). The +1 reserves one DPB slot for the H.264 frame_num gap handling, mirroring the SVC path. Update the H264 delegate unit test mock to advertise a realistic MaxLongTermReferences (15 instead of 1) so the manual-reference test still has headroom under the new cap. The previous value of 1 combined with the disable_d3d12_h264_encoder_non_reference_frames workaround left zero usable manual buffers under the new cap. Bug: 523717219 Change-Id: I2ea0a9ae1f007bd4afcabdf0791e6ccbf50d47b3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7976402 Commit-Queue: Qiu, Jianlin <[email protected]> Reviewed-by: Eugene Zemtsov <[email protected]> Cr-Commit-Position: refs/heads/main@{#1650736} --- diff --git a/media/gpu/windows/d3d12_video_encode_h264_delegate.cc b/media/gpu/windows/d3d12_video_encode_h264_delegate.cc index f6365db..2f554e89 100644 --- a/media/gpu/windows/d3d12_video_encode_h264_delegate.cc +++ b/media/gpu/windows/d3d12_video_encode_h264_delegate.cc @@ -4,6 +4,8 @@ #include "media/gpu/windows/d3d12_video_encode_h264_delegate.h" +#include <algorithm> + #include "base/bits.h" #include "base/containers/fixed_flat_map.h" #include "base/strings/stringprintf.h" @@ -648,7 +650,13 @@ "support manual reference control, got %u", picture_control_support_h264.MaxDPBCapacity)}; } - max_num_ref_frames_ = picture_control_support_h264.MaxDPBCapacity; + // Manual reference control is implemented via H.264 long-term references, + // so the number of usable slots must not exceed the driver's + // MaxLongTermReferences. Reserve one extra DPB slot for frame_num gap + // handling (matches the SVC path), but never exceed MaxDPBCapacity. + max_num_ref_frames_ = std::min<uint32_t>( + picture_control_support_h264.MaxDPBCapacity, + picture_control_support_h264.MaxLongTermReferences + 1); } if ((config.bitrate.mode() == Bitrate::Mode::kConstant || diff --git a/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc b/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc index 457d49b6..fd032dc 100644 --- a/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc +++ b/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc @@ -72,7 +72,7 @@ return E_INVALIDARG; } picture_control->PictureSupport.pH264Support->MaxLongTermReferences = - 1; + 15; picture_control->PictureSupport.pH264Support->MaxDPBCapacity = 16; return S_OK; });
Regression Test / PoC
diff --git a/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc b/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc
index 457d49b6..fd032dc 100644
--- a/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc
+++ b/media/gpu/windows/d3d12_video_encode_h264_delegate_unittest.cc
@@ -72,7 +72,7 @@
return E_INVALIDARG;
}
picture_control->PictureSupport.pH264Support->MaxLongTermReferences =
- 1;
+ 15;
picture_control->PictureSupport.pH264Support->MaxDPBCapacity = 16;
return S_OK;
});
Original Bug Report
Potential OOB access in D3D12 UMD via incorrect H.264 long-term reference validation
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: The D3D12 H.264 video encode delegate incorrectly bounds manual reference frame indices using the driver’s Decoded Picture Buffer capacity (MaxDPBCapacity) instead of its long-term reference capacity (MaxLongTermReferences). A compromised renderer can supply indices that exceed the hardware’s supported limits, which are then passed unvalidated to the D3D12 User-Mode Driver (UMD). This could lead to an out-of-bounds memory access in the driver, potentially resulting in a sandbox escape from the renderer to the GPU process.
Affected files:
media/gpu/windows/d3d12_video_encode_h264_delegate.ccmedia/gpu/windows/d3d12_video_encode_delegate.cc
Estimated timestamp from git blame: Unknown (Google3 checkout)
Background
Chrome allows clients (e.g., via the WebCodecs API and the VideoEncodeAccelerator Mojo interface) to manually manage video encoder reference frames using the update_buffer and reference_buffers options. In the D3D12 hardware encoder implementation for H.264 (D3D12VideoEncodeH264Delegate), these manual reference indices are translated directly into H.264 long-term reference commands: Memory Management Control Operations (MMCO) and Reference Picture List Modifications (RPLM).
Vulnerability Details
During hardware capability enumeration, Chrome queries the D3D12 driver for limits, including MaxDPBCapacity (the maximum size of the Decoded Picture Buffer) and MaxLongTermReferences (the maximum number of long-term references supported simultaneously).
In D3D12VideoEncodeH264Delegate::InitializeVideoEncoder, the internal state variable max_num_ref_frames_ is initialized using MaxDPBCapacity:
// media/gpu/windows/d3d12_video_encode_h264_delegate.cc:651
max_num_ref_frames_ = picture_control_support_h264.MaxDPBCapacity;
This variable dictates the internal tracking capacity and serves as the upper bound for incoming IPC requests. While the code verifies that MaxLongTermReferences >= 1 to ensure basic support, it fails to restrict max_num_ref_frames_ to this specific capability. In many drivers, MaxDPBCapacity is significantly larger than MaxLongTermReferences (e.g., MaxDPBCapacity = 16, MaxLongTermReferences = 1).
When D3D12VideoEncodeDelegate::Encode receives the Mojo IPC payload, it validates the provided update_buffer and reference_buffers indices against GetMaxNumOfManualRefBuffers(), which is derived from max_num_ref_frames_. Consequently, an attacker can supply an index that is within the generous DPB capacity bound but strictly greater than the driver’s long-term reference capability.
In D3D12VideoEncodeH264Delegate::EncodeImpl, these out-of-bounds indices are packed into the D3D12 structures:
update_bufferis mapped tolong_term_frame_idxin MMCOop-6.reference_buffersare mapped tolong_term_pic_numin RPLMop-2.
The resulting pic_params_ are passed down to the vendor-provided User-Mode Driver (UMD) via command_list_->EncodeFrame. Because the UMD operates under the assumption that the application respects the hardware capabilities it reported, it may use these out-of-bounds indices to directly access undersized internal tracking arrays, causing a memory corruption vulnerability within the GPU process.
Potential Attacker Steps
(Note: These are theoretical steps, as our tooling agent cannot execute a live proof-of-concept.)
- An attacker compromises a renderer process.
- The attacker initializes a hardware-accelerated WebCodecs encoding session.
- The attacker queries the encoder capabilities. Assume the underlying D3D12 driver reports
MaxDPBCapacity = 16andMaxLongTermReferences = 1. - The attacker crafts a malicious
VideoEncoderEncodeOptionspayload, settingupdate_bufferto10. - The renderer sends this payload to the GPU process via Mojo.
- The GPU process receives the payload. Because
10 < 16(the incorrectly used limit derived fromMaxDPBCapacity), validation succeeds. - The GPU process crafts a D3D12
EncodeFramecommand containing MMCO commands withlong_term_frame_idx = 10. - The driver processes the command, attempts to index an internal array of size
1with index10, resulting in an out-of-bounds write or read.
Impact
This vulnerability could allow an attacker with code execution in the renderer process to trigger an out-of-bounds memory access in the D3D12 UMD. Since the UMD runs within the Chromium GPU process, this can be exploited to achieve arbitrary code execution in the GPU process, resulting in a Sandbox Escape on Windows.
Suggested Fix
During initialization in D3D12VideoEncodeH264Delegate::InitializeVideoEncoder, constrain max_num_ref_frames_ (or introduce a new limit specifically for manual indices) to ensure it does not exceed the driver’s maximum supported long-term references:
// Ensure the manual reference limits do not exceed hardware long-term tracking capabilities.
max_num_ref_frames_ = std::min(
static_cast<uint32_t>(picture_control_support_h264.MaxDPBCapacity),
static_cast<uint32_t>(picture_control_support_h264.MaxLongTermReferences) + 1);
Evaluated with Chrome root at commit: 65b3256311f3ab6fb9870eaa522de7e6dd2663bb
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.