CVE-2026-11256
Overview
Files Changed
gpu/command_buffer/client/gles2_implementation.cc
Patch
From 45592325120328db659f3ec23be281af52927d6b Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner <[email protected]> Date: Mon, 13 Apr 2026 06:35:34 -0700 Subject: [PATCH] gpu: Upgrade DCHECKs to CHECKs in GLES2Implementation This upgrades size checks for IPC return data from DCHECK to CHECK to ensure that malformed payloads from a compromised GPU process are caught in release builds, preventing potential size_t underflows and subsequent out-of-bounds reads in the browser process. Fixed: 498856565 Change-Id: I9cd5447d07b322997a4c4c694726eed01be6ccd6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7736355 Reviewed-by: Victor Miura <[email protected]> Commit-Queue: Andrew Paseltiner <[email protected]> Cr-Commit-Position: refs/heads/main@{#1613666} --- diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 77214ff..99f01d7 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -189,7 +189,7 @@ void UpdateProgramInfo(base::span<const uint8_t>& data, ProgramInfoManager* manager, ProgramInfoManager::ProgramInfoType type) { - DCHECK(data.size() > sizeof(cmds::GLES2ReturnProgramInfo)); + CHECK(data.size() >= sizeof(cmds::GLES2ReturnProgramInfo)); const cmds::GLES2ReturnProgramInfo* return_program_info = reinterpret_cast<const cmds::GLES2ReturnProgramInfo*>(data.data()); uint32_t program = return_program_info->program_client_id; @@ -622,7 +622,7 @@ void GLES2Implementation::OnGpuControlReturnData( base::span<const uint8_t> data) { - DCHECK(data.size() > sizeof(cmds::GLES2ReturnDataHeader)); + CHECK(data.size() >= sizeof(cmds::GLES2ReturnDataHeader)); const cmds::GLES2ReturnDataHeader& gles2ReturnDataHeader = *reinterpret_cast<const cmds::GLES2ReturnDataHeader*>(data.data());
Original Bug Report
Blind OOB Read in Browser via size_t Underflow in GLES2Implementation::UpdateProgramInfo
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 without the security team.
Overview: A compromised GPU process can send a small IPC payload that triggers a size_t underflow in the browser process due to omitted DCHECKs in release builds. This underflow creates a massive base::span that defeats subsequent bounds checks, allowing out-of-bounds heap memory to be parsed and saved into the ProgramInfoManager. This results in a blind out-of-bounds read vulnerability in the browser process.
Affected files:
gpu/command_buffer/client/gles2_implementation.ccgpu/command_buffer/client/program_info_manager.cc
Estimated timestamp from git blame: 2025-11-28
Summary
A potential blind out-of-bounds (OOB) read exists in GLES2Implementation::UpdateProgramInfo. A compromised GPU process can trigger a size_t underflow by sending a malformed, undersized OnReturnData IPC payload. Because bounds checks in this code path rely on DCHECK macros (which are compiled out in release builds), the underflow results in the creation of a base::span with an enormously large reported size. This oversized span defeats all subsequent bounds checks in ProgramInfoManager, allowing an attacker to parse out-of-bounds browser heap memory into strings and integers stored in the Program object.
Vulnerability Details
- DCHECK Bypass: When a compromised GPU process sends a small (e.g., 4-byte)
mojom::CommandBufferClient::OnReturnDataIPC message with thekES2ProgramInfotype, it is processed byGLES2Implementation::OnGpuControlReturnData(gpu/command_buffer/client/gles2_implementation.cc). The code expects a larger payload but only checks the size using aDCHECK, which is skipped in release builds. - size_t Underflow: Execution reaches
UpdateProgramInfo(line 188), where anotherDCHECKexpects the data size to be greater than 8 bytes (sizeof(cmds::GLES2ReturnProgramInfo)). Because the check is omitted, the code subtracts 8 from the 4-byte size, causing an unsigned integer underflow. - Massive Span Creation: At line 195, a
base::spannamedinfois constructed using the underflowed size (SIZE_MAX - 3). BecauseCHECKED_SPANis disabled by default in Chromium, the span is constructed successfully with a massive size and a pointer pointing 8 bytes past the start of the data buffer. - Tautological Bounds Checks: The poisoned span is passed to
ProgramInfoManager::Program::UpdateES2(gpu/command_buffer/client/program_info_manager.cc). Here, functions likeLoad<T>andDataIterator::Get<T>usespan::subspanto perform bounds checks. Because the size of the span is nearSIZE_MAX, conditions likeoffset + sizeof(T) <= size()evaluate to true for almost any offset, making the checks tautological. - OOB Read: The code parses structures like
ProgramInfoHeaderandProgramInputfrom the out-of-bounds heap memory. By grooming the browser heap adjacent to the IPC buffer, an attacker can control the parsed lengths and offsets, allowing them to read arbitrary OOB integers and constructstd::stringobjects from OOB memory. These values are persisted in theattrib_infos_anduniform_infos_vectors.
Impact
This vulnerability allows a compromised GPU process to perform a blind out-of-bounds read on the browser process heap (for example, when WebXR is used on Windows, placing the command buffer in the browser process). While the attacker can copy OOB memory into the Program object, there is currently no identified path to return these strings back to the GPU process, making it a blind read. However, it still represents a memory safety violation in the highly privileged browser process.
(Note: These are suggested steps; our tooling agent does not have the ability to run code to confirm exploitability.)
Suggested Fix
The DCHECK macros used for input validation from the GPU process must be upgraded to fatal CHECK macros or graceful early returns.
In gpu/command_buffer/client/gles2_implementation.cc:
void GLES2Implementation::OnGpuControlReturnData(base::span<const uint8_t> data) {
CHECK(data.size() >= sizeof(cmds::GLES2ReturnDataHeader));
// ...
}
void UpdateProgramInfo(base::span<const uint8_t>& data, ...) {
CHECK(data.size() >= sizeof(cmds::GLES2ReturnProgramInfo));
// ...
}
Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; 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.