CVE-2026-17810
Overview
Background
- Dawn
- Chromium’s cross-platform implementation of the WebGPU API, including the OpenGL/OpenGL ES backend under
src/dawn/native/opengl. - WebGPU compatibility mode
- a restricted WebGPU profile targeting older GPUs that nonetheless assumes float color formats are renderable.
- `GL_EXT_color_buffer_float`
- an OpenGL ES extension that makes float32/float16/
rg11b10ufloattextures usable as renderable color attachments. - Uninitialized use
- reading memory whose contents were never validly written, here a float texture treated as renderable when the GL driver never rendered into it.
Root Cause Analysis
In PhysicalDevice::InitializeImpl, the OpenGL ES branch previously computed isFloat32Renderable, isFloat16Renderable, and isRG11B10UfloatRenderable conditionally from the GLES version and available extensions, so on an ES 3.1 device lacking GL_EXT_color_buffer_float these flags could be false. However, WebGPU compatibility mode and downstream Dawn operations assumed float color formats were always renderable, so paths like CopyTextureToTexture implemented via render/blit operated on a float texture the driver would not actually render into. Because the texture was never validly initialized by a render pass, the copy produced or read uninitialized GPU memory. The mismatch between Dawn’s assumption and the device’s real capabilities is the root cause.
The fix adds a DAWN_INVALID_IF that requires GL_EXT_color_buffer_float (or ES 3.2) at device creation, making float renderability a guaranteed precondition. With the guarantee enforced, the three flags are DAWN_ASSERTed and hardcoded to true, closing the gap between assumption and capability.
Attack Path
- Target a weak device
Reach an ES 3.1 GPU/driver that lacks
GL_EXT_color_buffer_float, where float color formats are not truly renderable. - Create a compat device Obtain a WebGPU compatibility-mode device that Dawn admits despite the missing float renderability guarantee.
- Allocate a float texture
Create a float32/float16/
rg11b10ufloattexture that Dawn assumes is renderable but the driver cannot initialize via rendering. - Trigger render-based copy
Invoke
CopyTextureToTexture(implemented via render/blit) so Dawn operates on the never-initialized float texture. - Exfiltrate residue Read back the destination to recover uninitialized GPU memory contents.
Impact Assessment
Files Changed
src/dawn/native/opengl/PhysicalDeviceGL.cpp
Audit Directions
- Assumed-vs-actual capabilityAudit other Dawn backends and features that assume a format is renderable, copyable, or filterable without validating the device’s real GL/driver support at admission time.
- Render-implemented copiesReview paths like
CopyTextureToTextureand blit/clear helpers that rely on rendering into a texture, ensuring the target format’s renderability is guaranteed before use. - Conditional-flag-to-hardcode changesSearch for capability flags computed from version/extension checks and used as preconditions elsewhere, confirming the precondition is enforced rather than merely assumed.
Patch
From b84c4b43197dedf9e22d242270b497a138c6358c Mon Sep 17 00:00:00 2001
From: Shrek Shao <shrekshao@google.com>
Date: Tue, 23 Jun 2026 09:30:58 -0700
Subject: [PATCH] Compat: Require GL_EXT_color_buffer_float for GL device creation
Require the GL_EXT_color_buffer_float extension in
PhysicalDevice::InitializeImpl(). As it is required in
WebGPU compatibility mode spec.
Since GL_EXT_color_buffer_float is now guaranteed in compat device,
the CopyTextureToTexture vulnerability is gone.
GL_EXT_color_buffer_half_float is subset so no need checking it
anymore now.
Bug: 516882109
Change-Id: I82ca687def2cd57d8a08ed84363f2bf85b93e784
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/318275
Commit-Queue: Shrek Shao <shrekshao@google.com>
Auto-Submit: Shrek Shao <shrekshao@google.com>
Reviewed-by: Stephen White <senorblanco@chromium.org>
---
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.cpp b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
index b597959..49d07ac 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.cpp
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
@@ -158,6 +158,9 @@
switch (GetBackendType()) {
case wgpu::BackendType::OpenGLES:
DAWN_INVALID_IF(!mFunctions.IsAtLeastGLES(3, 1), "OpenGL ES 3.1 is required.");
+ DAWN_INVALID_IF(!mFunctions.IsAtLeastGLES(3, 2) &&
+ !mFunctions.IsGLExtensionSupported("GL_EXT_color_buffer_float"),
+ "GL_EXT_color_buffer_float is required for OpenGL ES 3.1.");
break;
case wgpu::BackendType::OpenGL:
DAWN_INVALID_IF(!mFunctions.IsAtLeastGL(4, 4), "Desktop OpenGL 4.4 is required.");
@@ -443,11 +446,11 @@
bool supportsStencilWriteTexture =
gl.GetVersion().IsDesktop() || gl.IsGLExtensionSupported("GL_OES_texture_stencil8");
- bool isFloat32Renderable = gl.GetVersion().IsDesktop() || gl.IsAtLeastGLES(3, 2) ||
- gl.IsGLExtensionSupported("GL_EXT_color_buffer_float");
- bool isFloat16Renderable =
- isFloat32Renderable || gl.IsGLExtensionSupported("GL_EXT_color_buffer_half_float");
- bool isRG11B10UfloatRenderable = isFloat32Renderable;
+ DAWN_ASSERT(gl.GetVersion().IsDesktop() || gl.IsAtLeastGLES(3, 2) ||
+ gl.IsGLExtensionSupported("GL_EXT_color_buffer_float"));
+ bool isFloat32Renderable = true;
+ bool isFloat16Renderable = true;
+ bool isRG11B10UfloatRenderable = true;
// TODO(crbug.com/dawn/343): Investigate emulation.
deviceToggles->Default(Toggle::DisableIndexedDrawBuffers, !supportsIndexedDrawBuffers);
Original Bug Report
Potential GPU memory leak on GLES 3.1 devices due to missing float format checks in T2T copies
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 texture-to-texture (T2T) copy workaround routing logic in Dawn lacks checks for float-renderability toggles. On OpenGL ES 3.1 devices where float renderability is unsupported, direct copies silently fail while the destination texture is incorrectly marked as initialized. Subsequent reads of the texture bypass lazy-clearing and expose uninitialized GPU heap memory.
Affected files:
third_party/dawn/src/dawn/native/CommandEncoder.cppthird_party/dawn/src/dawn/native/opengl/CommandBufferGL.cppthird_party/dawn/src/dawn/native/opengl/UtilsGL.cpp
Estimated timestamp from git blame: 2025-01-17
Description
There is a potential security vulnerability in Dawn’s Texture-to-Texture (T2T) copy path on OpenGL ES 3.1 devices that do not support float-renderability extensions (such as GL_EXT_color_buffer_float or GL_EXT_color_buffer_half_float).
In third_party/dawn/src/dawn/native/CommandEncoder.cpp, the function ShouldUseT2B2TForT2T determines if a copy operation must use an intermediate workaround buffer or if it can use a direct native copy. However, this function lacks checks for the following float-renderability toggles:
UseBlitForRG11B10UfloatTextureCopyUseBlitForFloat16TextureCopyUseBlitForFloat32TextureCopy
Because these toggles are not checked, ShouldUseT2B2TForT2T returns false on devices requiring float-copy workarounds, causing Dawn to attempt a direct native copy.
Mechanism of Failure
- When executing
CopyTextureToTextureinthird_party/dawn/src/dawn/native/opengl/CommandBufferGL.cpp, the destination texture subresource is marked as initialized before performing the actual copy if the copy completely covers the subresource:if (IsCompleteSubresourceCopiedTo(dstTexture, copySize.ToExtent3D(), dst.mipLevel, dst.aspect)) { dstTexture->SetIsSubresourceContentInitialized(true, dstRange); } - The OpenGL backend executes
CopyImageSubDatainthird_party/dawn/src/dawn/native/opengl/UtilsGL.cpp. On OpenGL ES 3.1 devices, it falls back to manualglBlitFramebufferemulation using temporary framebuffers (FBOs). - Attaching non-color-renderable textures to the FBO yields a
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENTstatus, causingglBlitFramebufferto generate aGL_INVALID_FRAMEBUFFER_OPERATIONerror and fail silently without writing any data. - In release builds,
DAWN_GL_TRYcompiles to direct calls without active error-checking ((gl.call)), letting the failure pass silently. - The destination texture’s memory remains uninitialized, but internal tracking registers it as initialized. A subsequent readback via compute shader (T2B) samples raw, uninitialized GPU memory and transfers it to the renderer.
Potential Reproduction Steps
Note: These are suggested steps based on static analysis of the source code. Our tooling currently lacks the capability to execute live code on GLES 3.1 emulation targets.
- On a platform with a GLES 3.1 driver lacking float color-renderability (such as
GL_EXT_color_buffer_float), obtain a WebGPU compatibility adapter. - Create a destination float texture (
rgba16floatorrgba32float) and a source texture containing known data. - Execute a
copyTextureToTexturecall to copy the source to the destination completely. The destination is marked as initialized, but the copy silently fails. - Execute
copyTextureToBufferto read back the destination texture to a host-mappable buffer. The T2B path utilizes the compute shader blit workaround. - Because the destination is marked as initialized, the lazy-clearing check is bypassed. The compute shader reads uncleared GPU memory into the buffer, leaking cross-origin GPU heap data.
Suggested Fix
Update ShouldUseT2B2TForT2T in third_party/dawn/src/dawn/native/CommandEncoder.cpp to check float-renderability toggles and return true if they are enabled for the corresponding textures:
bool ShouldUseT2B2TForT2T(const DeviceBase* device,
const Format& srcFormat,
const Format& dstFormat) {
// ... existing checks ...
// Float formats checks
if ((srcFormat.format == wgpu::TextureFormat::RG11B10Ufloat &&
device->IsToggleEnabled(Toggle::UseBlitForRG11B10UfloatTextureCopy)) ||
((srcFormat.format == wgpu::TextureFormat::R16Float ||
srcFormat.format == wgpu::TextureFormat::RG16Float ||
srcFormat.format == wgpu::TextureFormat::RGBA16Float) &&
device->IsToggleEnabled(Toggle::UseBlitForFloat16TextureCopy)) ||
((srcFormat.format == wgpu::TextureFormat::R32Float ||
srcFormat.format == wgpu::TextureFormat::RG32Float ||
srcFormat.format == wgpu::TextureFormat::RGBA32Float) &&
device->IsToggleEnabled(Toggle::UseBlitForFloat32TextureCopy))) {
return true;
}
return false;
}
Evaluated with Chrome root at commit: b1520ef4a76878853a31f0943b565e42060edec8
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.