CVE-2026-11086
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifsrc/dawn/native/Texture.cpp |
modified | |
switchsrc/dawn/native/Texture.cpp |
modified | |
ifsrc/dawn/native/vulkan/TextureVk.cpp |
modified |
Files Changed
src/dawn/native/Texture.cppsrc/dawn/native/vulkan/TextureVk.cpp
Patch
From e01ebb9771eac8a4b4853d51a5839c52e39df04b Mon Sep 17 00:00:00 2001 From: Brandon Jones <[email protected]> Date: Wed, 08 Apr 2026 15:33:29 -0700 Subject: [PATCH] Validate internal usage when creating views Validates texture usage constraints against the internal usage of a texture rather that the public usage when creating a view. This prevents things like STORAGE usages from being used when creating views that use a an sRGB format. Bug: 500140111 Change-Id: I7e284c88284bebdf21a5a194a3809dba006b9234 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/301456 Reviewed-by: Loko Kung <[email protected]> Reviewed-by: Brandon Jones <[email protected]> Commit-Queue: Brandon Jones <[email protected]> Auto-Submit: Brandon Jones <[email protected]> --- diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp index d23bd66..08acd26 100644 --- a/src/dawn/native/Texture.cpp +++ b/src/dawn/native/Texture.cpp @@ -696,6 +696,30 @@ return internalUsage; } +// Removes internal usages incompatible with the format/dimension before calling AddInternalUsages. +wgpu::TextureUsage AdjustViewInternalUsages(const DeviceBase* device, + wgpu::TextureUsage usage, + const Format& format, + const wgpu::TextureViewDimension dimension, + uint32_t sampleCount, + uint32_t mipLevelCount, + uint32_t arrayLayerCount) { + wgpu::TextureUsage internalUsage = usage; + + // Remove render attachment usage if the dimension is 1D + if (dimension == wgpu::TextureViewDimension::e1D) { + internalUsage &= ~wgpu::TextureUsage::RenderAttachment; + } + + // Remove storage usage if neither read or write is supported. + if (!format.SupportsReadOnlyStorageUsage() && !format.SupportsWriteOnlyStorageUsage()) { + internalUsage &= ~wgpu::TextureUsage::StorageBinding; + } + + return AddInternalUsages(device, internalUsage, format, sampleCount, mipLevelCount, + arrayLayerCount); +} + wgpu::ComponentSwizzle ComposeSwizzleComponent(wgpu::TextureComponentSwizzle swizzle, wgpu::ComponentSwizzle component) { switch (component) { @@ -1828,13 +1852,14 @@ {descriptor->baseArrayLayer, descriptor->arrayLayerCount}, {descriptor->baseMipLevel, descriptor->mipLevelCount}}), mUsage(GetTextureViewUsage(texture->GetUsage(), descriptor->usage)), - mInternalUsage( - AddInternalUsages(GetDevice(), - GetTextureViewUsage(texture->GetInternalUsage(), descriptor->usage), - *mFormat, - texture->GetSampleCount(), - texture->GetNumMipLevels(), - texture->GetArrayLayers())) { + mInternalUsage(AdjustViewInternalUsages( + GetDevice(), + GetTextureViewUsage(texture->GetInternalUsage(), descriptor->usage), + *mFormat, + descriptor->dimension, + texture->GetSampleCount(), + texture->GetNumMipLevels(), + texture->GetArrayLayers())) { if (auto* swizzleDesc = descriptor.Get<TextureComponentSwizzleDescriptor>()) { auto swizzle = swizzleDesc->swizzle.WithTrivialFrontendDefaults(); mSwizzleRed = swizzle.r; diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp index f5f4acb..f5ec1cf 100644 --- a/src/dawn/native/vulkan/TextureVk.cpp +++ b/src/dawn/native/vulkan/TextureVk.cpp @@ -668,6 +668,9 @@ } } if (usage & wgpu::TextureUsage::StorageBinding) { + // Storage bit should only be included if the format actually supports a storage uage. + DAWN_ASSERT(format.SupportsReadOnlyStorageUsage() || + format.SupportsWriteOnlyStorageUsage()); flags |= VK_IMAGE_USAGE_STORAGE_BIT; } if (usage & wgpu::TextureUsage::RenderAttachment) {
Original Bug Report
Vulkan VUID violation via Dawn internal usage validation bypass
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 renderer can use DawnTextureInternalUsageDescriptor to bypass texture view validation in Dawn. This allows the creation of Vulkan image views with incompatible formats and usage flags, such as SRGB formats with storage usage. This violates Vulkan specifications and can cause undefined behavior in the GPU process.
Affected files:
third_party/dawn/src/dawn/native/Texture.cppthird_party/dawn/src/dawn/native/vulkan/TextureVk.cppgpu/command_buffer/service/webgpu_decoder_impl.cc
Estimated timestamp from git blame: 2025-11-11
Background
In Dawn, textures and texture views possess both public and internal usages. Public usages are defined through the standard WebGPU API, while internal usages are utilized for implementation-specific optimizations and interop. The DawnTextureInternalUsageDescriptor allows specifying internal usages directly. In Chrome, the DawnInternalUsages feature is enabled by default in the GPU process for all web contexts (via gpu/command_buffer/service/webgpu_decoder_impl.cc), and this descriptor is wire-serializable, meaning a compromised renderer can send it over IPC.
Vulnerability
There is a critical divergence between how a TextureView’s usage is validated and how it is ultimately constructed:
- Validation: When a texture view is created with a requested usage of
None(0), it inherits its usage from the base texture. The validation functionValidateTextureViewUsagecalculates this by callingGetTextureViewUsage(texture->GetUsage(), usage). Crucially, this only fetches the base texture’s public usage and ignores its internal usage. - Construction: During object construction, the
TextureViewBaseconstructor initializes the view’s internal usage by callingGetTextureViewUsage(texture->GetInternalUsage(), descriptor->usage). This populates the view with all internal flags from the base texture.
If a texture is created with a public usage of TextureBinding and an internal usage of StorageBinding, creating a view with None usage and an SRGB format (like RGBA8UnormSrgb) will pass validation. ValidateTextureViewUsage only sees TextureBinding (which is compatible with SRGB formats). However, the resulting view object inherits the internal StorageBinding flag.
Impact
When the Vulkan backend initializes the view (TextureView::Initialize in TextureVk.cpp), it translates the view’s internal usages to Vulkan flags. The hidden StorageBinding is translated to VK_IMAGE_USAGE_STORAGE_BIT.
The backend then calls vkCreateImageView with VK_FORMAT_R8G8B8A8_SRGB and VK_IMAGE_USAGE_STORAGE_BIT. This violates Vulkan specification VUID-VkImageViewCreateInfo-usage-02275, which strictly requires that any image view with a storage usage bit must have a format that supports VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT. Since SRGB formats universally lack this feature, the graphics driver is forced into undefined behavior. This can lead to driver crashes, memory corruption, or potential sandbox escapes from the GPU process.
Suggested Reproduction Steps
Note: These are potential steps as our tooling agent cannot execute arbitrary code.
- From a compromised renderer process, send a
DeviceCreateTextureIPC command to create a texture with:format:wgpu::TextureFormat::RGBA8Unormusage:wgpu::TextureUsage::TextureBindingviewFormats:[wgpu::TextureFormat::RGBA8UnormSrgb]nextInChain: ADawnTextureInternalUsageDescriptorwithinternalUsageset towgpu::TextureUsage::StorageBinding.
- Send a
TextureCreateViewIPC command for the new texture, specifying:format:wgpu::TextureFormat::RGBA8UnormSrgbusage:wgpu::TextureUsage::None(0).
- Observe that
ValidateTextureViewUsagepasses because it only checksTextureBindingagainstRGBA8UnormSrgb. - The view is constructed with an internal usage that includes
StorageBinding. - In the GPU process’s Vulkan backend,
vkCreateImageViewis executed with an SRGB format andVK_IMAGE_USAGE_STORAGE_BIT, triggering the VUID violation.
Suggested Fix
ValidateTextureViewUsage in third_party/dawn/src/dawn/native/Texture.cpp must be updated to validate the internal usages that the texture view will actually inherit.
Instead of only checking GetTextureViewUsage(texture->GetUsage(), usage), the validation logic should compute the inherited internal usage (GetTextureViewUsage(texture->GetInternalUsage(), usage)) and ensure that these combined usage flags are compatible with the requested view format before allowing the view to be created.
Evaluated with Chrome root at commit: f200f57a19490707ff8bc7aa5de3cbc443a3afad
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.