CVE-2026-11686
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fsrc/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp |
modified |
Files Changed
src/dawn/native/Texture.cppsrc/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp
Patch
From 836ae06d5a9063469d793f6f176e4f69f992df24 Mon Sep 17 00:00:00 2001
From: Corentin Wallez <cwallez@chromium.org>
Date: Mon, 01 Jun 2026 17:31:29 -0700
Subject: [PATCH] [dawn][native] Disallow TransientAttachment for internal usages.
Contrary to additional usages that are strict additions,
TransientAttachment is an opt-in to additional constraints, so it would
have user-visible effects (plus validation for external usages would need
to take into account the potential internal TransientAttachment).
Fixed: 517247333
Change-Id: Ib197ad592433a2c6ee1b2de2e50e734995f3a111
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/311915
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
---
diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp
index 5c734f5..ca23557 100644
--- a/src/dawn/native/Texture.cpp
+++ b/src/dawn/native/Texture.cpp
@@ -759,6 +759,19 @@
!device->HasFeature(Feature::DawnInternalUsages),
"The internalUsageDesc is not empty while the dawn-internal-usages feature is not "
"enabled");
+
+ // Disallow TransientAttachment because it is not an expansion of usages but instead an
+ // additional constraint and would need to have visible effects (for users of the API that
+ // don't have access to the internal usages). Use an allow-list to explicitly opt-in usages
+ // to be allowed as internal usages in the future.
+ constexpr wgpu::TextureUsage kAllowedInternalUsages =
+ wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
+ wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::StorageBinding |
+ wgpu::TextureUsage::RenderAttachment;
+ DAWN_INVALID_IF(!IsSubset(internalUsageDesc->internalUsage, kAllowedInternalUsages),
+ "internalUsage contains %s which are not allowed as internal usages.",
+ internalUsageDesc->internalUsage & ~kAllowedInternalUsages);
+
usage |= internalUsageDesc->internalUsage;
}
diff --git a/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp b/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp
index d37de44..8a32f52 100644
--- a/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp
@@ -108,6 +108,29 @@
device.CreateTexture(&textureDesc);
}
+// Test that TransientAttachment cannot be passed as internal usage.
+TEST_F(TextureInternalUsageValidationTest, TransientAttachment) {
+ wgpu::TextureDescriptor textureDesc = {};
+ textureDesc.size = {1, 1};
+ textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
+
+ wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
+ textureDesc.nextInChain = &internalDesc;
+
+ // Success case: Texture is Render+Transient and Render as internal usage.
+ textureDesc.usage =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment;
+ internalDesc.internalUsage = wgpu::TextureUsage::RenderAttachment;
+ device.CreateTexture(&textureDesc);
+
+ // Failure case: Texture is Render+Transient for both normal and internal usages.
+ textureDesc.usage =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment;
+ internalDesc.internalUsage =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
+}
+
// Test that internal usages takes part in other validation that
// depends on the usage.
TEST_F(TextureInternalUsageValidationTest, UsageValidation) {
Regression Test / PoC
diff --git a/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp b/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp
index d37de44..8a32f52 100644
--- a/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/InternalUsageValidationTests.cpp
@@ -108,6 +108,29 @@
device.CreateTexture(&textureDesc);
}
+// Test that TransientAttachment cannot be passed as internal usage.
+TEST_F(TextureInternalUsageValidationTest, TransientAttachment) {
+ wgpu::TextureDescriptor textureDesc = {};
+ textureDesc.size = {1, 1};
+ textureDesc.format = wgpu::TextureFormat::RGBA8Unorm;
+
+ wgpu::DawnTextureInternalUsageDescriptor internalDesc = {};
+ textureDesc.nextInChain = &internalDesc;
+
+ // Success case: Texture is Render+Transient and Render as internal usage.
+ textureDesc.usage =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment;
+ internalDesc.internalUsage = wgpu::TextureUsage::RenderAttachment;
+ device.CreateTexture(&textureDesc);
+
+ // Failure case: Texture is Render+Transient for both normal and internal usages.
+ textureDesc.usage =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment;
+ internalDesc.internalUsage =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&textureDesc));
+}
+
// Test that internal usages takes part in other validation that
// depends on the usage.
TEST_F(TextureInternalUsageValidationTest, UsageValidation) {
Original Bug Report
Potential validation bypass in Dawn via internal transient attachment usage mismatch
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 validation logic mismatch in Dawn allows a compromised renderer to bypass transient attachment load/store operation restrictions. By specifying transient usage internally, the frontend validation is bypassed while the Metal backend allocates a memoryless texture. On Apple Silicon, this mismatch can potentially be used to read uncleared GPU tile memory, leading to cross-origin graphics data disclosure.
Affected files:
third_party/dawn/src/dawn/native/CommandEncoder.cppthird_party/dawn/src/dawn/native/metal/TextureMTL.mm
Estimated timestamp from git blame: 2024-10-01
Description
There is a potential validation discrepancy in Dawn regarding how transient texture attachments are handled between the frontend validation and the Metal backend.
In third_party/dawn/src/dawn/native/CommandEncoder.cpp (lines 667 and 782), frontend validation functions such as ValidateRenderPassColorAttachment and ValidateRenderPassDepthStencilAttachment enforce load and store restrictions (e.g., forcing loadOp to be Clear and storeOp to be Discard) on transient attachments by checking the view’s public usage mask:
if (attachment->GetUsage() & wgpu::TextureUsage::TransientAttachment) {
// Enforce loadOp / storeOp restrictions
}
However, in the Metal backend (third_party/dawn/src/dawn/native/metal/TextureMTL.mm at line 238), Dawn decides whether to allocate a texture using MTLStorageModeMemoryless based on its internal usage:
if (GetInternalUsage() & wgpu::TextureUsage::TransientAttachment &&
[ToBackend(GetDevice())->GetMTLDevice() supportsFamily:MTLGPUFamilyApple2]) {
mtlDesc.storageMode = MTLStorageModeMemoryless;
}
Because Chrome automatically requests and enables wgpu::FeatureName::DawnInternalUsages under the hood for WebGPU devices (in gpu/command_buffer/service/webgpu_decoder_impl.cc at line 1513), a compromised renderer can pass a chained DawnTextureInternalUsageDescriptor upon texture creation to specify wgpu::TextureUsage::TransientAttachment only as an internal usage, while keeping the public usage set to a standard RenderAttachment.
Since attachment->GetUsage() returns the public usage mask (which does not contain the transient bit), the frontend’s load and store restrictions are bypassed, permitting arbitrary operations such as loadOp = Load and storeOp = Store. Meanwhile, on the Metal backend, the texture is allocated as memoryless. On Apple Silicon, executing MTLLoadActionLoad against memoryless textures can allow reading the uncleared, stale contents of the GPU’s on-chip tile memory, representing a potential cross-origin GPU memory disclosure vulnerability.
Note: These are potential steps and analysis; our current tooling has not executed a live proof-of-concept.
Potential Steps to Reproduce
A compromised renderer acting over dawn_wire could potentially perform the following sequence:
- Call
DeviceCreateTexturewithdescriptor.usage = RenderAttachmentand a chainedDawnTextureInternalUsageDescriptorspecifyinginternalUsage = TransientAttachment. - Call
TextureCreateViewon the created texture to obtain a view. The view’s publicmUsagewill inheritRenderAttachment, while itsmInternalUsagewill resolve toRenderAttachment | TransientAttachment. - Execute a first dummy render pass on the view with
loadOp = Clearto initialize the subresource state. - Execute a second render pass on the view specifying
loadOp = Load,storeOp = Discard, and a non-transient textureresolveas theresolveTarget. - Copy the resolved texture to a buffer and map it back to the renderer process to read the stale GPU tile memory loaded during the pass.
Suggested Fix
The frontend validation in CommandEncoder.cpp should enforce transient attachment constraints based on the texture’s internal usage (GetInternalUsage()) rather than its public usage (GetUsage()):
if (attachment->GetInternalUsage() & wgpu::TextureUsage::TransientAttachment) {
// Enforce loadOp / storeOp restrictions
}
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.