CVE-2026-7973
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TextureCorruptionTests_WidthAndHeight_IntelGen12src/dawn/tests/end2end/TextureCorruptionTests.cpp |
modified | |
TEST_Psrc/dawn/tests/end2end/TextureCorruptionTests.cpp |
modified | |
TextureCorruptionTests_ArrayLayersrc/dawn/tests/end2end/TextureCorruptionTests.cpp |
modified |
Files Changed
src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cppsrc/dawn/tests/end2end/TextureCorruptionTests.cpp
Patch
From cacb2e67d9cd469074052e537a7e217ac9d6f0c0 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Wed, 01 Apr 2026 12:32:09 -0700
Subject: [PATCH] [d3d12][native] Fix potential uint16 overflow during texture allocation on Intel Gen12
When "d3d12_allocate_extra_memory_for_2d_array_color_texture" is
enabled, it's possible to create a texture that results in a uint16
overflow. Detect this and return an OOM.
Bug: 497565944
Change-Id: Ifeb1b9818db676ac3a990f3f965346f8201fd17a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/300576
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
---
diff --git a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
index 7b52c67..7b61a99 100644
--- a/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
+++ b/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp
@@ -191,7 +191,7 @@
return Align(columnPitch, 4);
}
-uint32_t ComputeExtraArraySizeForIntelGen12(uint32_t width,
+uint64_t ComputeExtraArraySizeForIntelGen12(uint32_t width,
uint32_t height,
uint32_t arrayLayerCount,
uint32_t mipLevelCount,
@@ -355,10 +355,18 @@
// Multisample textures have one layer at most. Only non-multisample textures need the
// workaround.
DAWN_ASSERT(revisedDescriptor.SampleDesc.Count <= 1);
- revisedDescriptor.DepthOrArraySize += ComputeExtraArraySizeForIntelGen12(
- resourceDescriptor.Width, resourceDescriptor.Height,
- resourceDescriptor.DepthOrArraySize, resourceDescriptor.MipLevels,
- resourceDescriptor.SampleDesc.Count, colorFormatBytesPerBlock);
+ // Make sure the result fits in DepthOrArraySize which is a UINT16
+ uint64_t depthOrArraySize =
+ revisedDescriptor.DepthOrArraySize +
+ ComputeExtraArraySizeForIntelGen12(
+ resourceDescriptor.Width, resourceDescriptor.Height,
+ resourceDescriptor.DepthOrArraySize, resourceDescriptor.MipLevels,
+ resourceDescriptor.SampleDesc.Count, colorFormatBytesPerBlock);
+ if (depthOrArraySize >= std::numeric_limits<UINT16>::max()) {
+ return DAWN_OUT_OF_MEMORY_ERROR(
+ "Texture array size with Intel Gen12 workaround exceeds UINT16");
+ }
+ revisedDescriptor.DepthOrArraySize = depthOrArraySize;
}
// TODO(crbug.com/dawn/849): Conditionally disable sub-allocation.
diff --git a/src/dawn/tests/end2end/TextureCorruptionTests.cpp b/src/dawn/tests/end2end/TextureCorruptionTests.cpp
index e172910..e19de3e 100644
--- a/src/dawn/tests/end2end/TextureCorruptionTests.cpp
+++ b/src/dawn/tests/end2end/TextureCorruptionTests.cpp
@@ -399,6 +399,40 @@
{kDefaultSampleCount},
{kDefaultWriteType});
+// Test for UINT16 overflow when calling ComputeExtraArraySizeForIntelGen12 as per
+// crbug.com/497565944.
+class TextureCorruptionTests_WidthAndHeight_IntelGen12 : public TextureCorruptionTests {
+ void GetRequiredLimits(const dawn::utils::ComboLimits& supported,
+ dawn::utils::ComboLimits& required) override {
+ required.maxTextureArrayLayers = supported.maxTextureArrayLayers;
+ }
+};
+TEST_P(TextureCorruptionTests_WidthAndHeight_IntelGen12, Tests) {
+ wgpu::Limits limits;
+ device.GetLimits(&limits);
+ DAWN_SUPPRESS_TEST_IF(limits.maxTextureArrayLayers < 2048);
+
+ uint32_t width = GetParam().mTextureWidth;
+ uint32_t height = GetParam().mTextureHeight;
+ uint32_t depthOrArrayLayerCount = GetParam().mArrayLayerCount;
+ uint32_t mipLevelCount = GetParam().mMipLevelCount;
+ uint32_t sampleCount = GetParam().mSampleCount;
+ wgpu::Extent3D textureSize = {width, height, depthOrArrayLayerCount};
+ wgpu::TextureFormat format = GetParam().mTextureFormat;
+ // This should fail due to an OOM error.
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture =
+ Create2DTexture(textureSize, format, mipLevelCount, sampleCount));
+}
+DAWN_INSTANTIATE_TEST_P(TextureCorruptionTests_WidthAndHeight_IntelGen12,
+ {D3D12Backend({"d3d12_allocate_extra_memory_for_2d_array_color_texture"})},
+ {wgpu::TextureFormat::R16Uint},
+ {1u},
+ {8192u},
+ {1793u},
+ {kDefaultMipLevelCount},
+ {kDefaultSampleCount},
+ {WriteType::WriteTexture});
+
class TextureCorruptionTests_ArrayLayer : public TextureCorruptionTests {};
TEST_P(TextureCorruptionTests_ArrayLayer, Tests) {
Regression Test / PoC
diff --git a/src/dawn/tests/end2end/TextureCorruptionTests.cpp b/src/dawn/tests/end2end/TextureCorruptionTests.cpp
index e172910..e19de3e 100644
--- a/src/dawn/tests/end2end/TextureCorruptionTests.cpp
+++ b/src/dawn/tests/end2end/TextureCorruptionTests.cpp
@@ -399,6 +399,40 @@
{kDefaultSampleCount},
{kDefaultWriteType});
+// Test for UINT16 overflow when calling ComputeExtraArraySizeForIntelGen12 as per
+// crbug.com/497565944.
+class TextureCorruptionTests_WidthAndHeight_IntelGen12 : public TextureCorruptionTests {
+ void GetRequiredLimits(const dawn::utils::ComboLimits& supported,
+ dawn::utils::ComboLimits& required) override {
+ required.maxTextureArrayLayers = supported.maxTextureArrayLayers;
+ }
+};
+TEST_P(TextureCorruptionTests_WidthAndHeight_IntelGen12, Tests) {
+ wgpu::Limits limits;
+ device.GetLimits(&limits);
+ DAWN_SUPPRESS_TEST_IF(limits.maxTextureArrayLayers < 2048);
+
+ uint32_t width = GetParam().mTextureWidth;
+ uint32_t height = GetParam().mTextureHeight;
+ uint32_t depthOrArrayLayerCount = GetParam().mArrayLayerCount;
+ uint32_t mipLevelCount = GetParam().mMipLevelCount;
+ uint32_t sampleCount = GetParam().mSampleCount;
+ wgpu::Extent3D textureSize = {width, height, depthOrArrayLayerCount};
+ wgpu::TextureFormat format = GetParam().mTextureFormat;
+ // This should fail due to an OOM error.
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture =
+ Create2DTexture(textureSize, format, mipLevelCount, sampleCount));
+}
+DAWN_INSTANTIATE_TEST_P(TextureCorruptionTests_WidthAndHeight_IntelGen12,
+ {D3D12Backend({"d3d12_allocate_extra_memory_for_2d_array_color_texture"})},
+ {wgpu::TextureFormat::R16Uint},
+ {1u},
+ {8192u},
+ {1793u},
+ {kDefaultMipLevelCount},
+ {kDefaultSampleCount},
+ {WriteType::WriteTexture});
+
class TextureCorruptionTests_ArrayLayer : public TextureCorruptionTests {};
TEST_P(TextureCorruptionTests_ArrayLayer, Tests) {
Original Bug Report
Potential GPU OOB Access via Integer Overflow in Dawn D3D12 Texture Allocation Workaround
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: An integer overflow exists in Dawn’s D3D12 backend when applying a memory allocation workaround for Intel Gen12 GPUs. A 32-bit padding size is added to a 16-bit texture dimension field without bounds checking, causing the allocation of an undersized GPU buffer. Dawn’s validation relies on the original requested size, allowing WebGPU commands to perform out-of-bounds reads and writes in GPU memory.
Affected files:
third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cppthird_party/dawn/src/dawn/native/d3d12/TextureD3D12.cppthird_party/dawn/src/dawn/native/Texture.cppthird_party/dawn/src/dawn/native/d3d12/UtilsD3D12.cpp
Estimated timestamp from git blame: 2022-12-14
Description
A potential vulnerability exists in Dawn’s D3D12 backend where an integer overflow can lead to the allocation of undersized GPU textures on systems with Intel Gen12 GPUs (e.g., Tiger Lake) running older drivers.
In third_party/dawn/src/dawn/native/d3d12/ResourceAllocatorManagerD3D12.cpp, the AllocateMemory function implements a workaround for a legacy bug in Intel Gen12 GPU drivers (Toggle::D3D12AllocateExtraMemoryFor2DArrayColorTexture). This workaround increases the number of layers in a 2D array texture to avoid corruption:
// ResourceAllocatorManagerD3D12.cpp
revisedDescriptor.DepthOrArraySize += ComputeExtraArraySizeForIntelGen12(
resourceDescriptor.Width, resourceDescriptor.Height,
resourceDescriptor.DepthOrArraySize, resourceDescriptor.MipLevels,
resourceDescriptor.SampleDesc.Count, colorFormatBytesPerBlock);
The vulnerability occurs because ComputeExtraArraySizeForIntelGen12 returns a uint32_t, but revisedDescriptor.DepthOrArraySize is a UINT16 field (as defined in the D3D12_RESOURCE_DESC struct). There are no bounds or overflow checks on this addition.
An attacker can request a texture with dimensions that cause ComputeExtraArraySizeForIntelGen12 to return a very large value. When added to the requested DepthOrArraySize, the resulting sum overflows the 16-bit integer and is truncated. Consequently, D3D12 allocates a resource with a much smaller capacity than requested. However, Dawn’s internal representation (TextureBase::mBaseSize) retains the original, larger size. When the attacker accesses layers beyond the allocated capacity, Dawn’s frontend validation permits the access, passing the out-of-bounds subresource index to the D3D12 runtime, which performs an out-of-bounds memory access in the GPU heap.
Potential Attacker Steps
Note: These steps are theoretical as our tooling agent does not run exploit code directly.
- Meet Preconditions: The victim must be using an Intel Gen12 GPU with a Windows driver older than 30.0.101.1692, triggering the workaround toggle.
- Request Malicious Texture: The attacker requests a 2D array texture via WebGPU. For example, a texture of size
1x8192with1793layers and formatr16uint.- Dawn validates this against the device’s
maxTextureArrayLayerslimit (usually 2048), which passes.
- Dawn validates this against the device’s
- Trigger Overflow: Inside
AllocateMemory,ComputeExtraArraySizeForIntelGen12calculates the required padding. For the above dimensions, it returns457,215.- The addition
1793 + 457215 = 459008overflows theUINT16type. - The value wraps around modulo 65536:
459008 % 65536 = 256.
- The addition
- Undersized Allocation: D3D12 creates a physical GPU resource with only 256 layers, but Dawn’s internal state continues to track it as having 1793 layers.
- Out-of-Bounds Access: The attacker invokes a WebGPU copy command (e.g.,
copyTextureToBuffer) targeting layer1700. Dawn’s validation permits this (1700 < 1793). - Memory Corruption: Dawn issues an
ID3D12GraphicsCommandList::CopyTextureRegioncommand for subresource1700. The GPU driver computes the memory address, pointing far past the allocated 256 layers, resulting in an out-of-bounds read/write in GPU memory (a GPU process sandbox escape primitive).
Suggested Fix
Check for integer overflow before assigning the value to the UINT16 field. If the required size exceeds the capacity of a UINT16, the allocation should fail gracefully (return an out-of-memory error).
uint32_t extraSize = ComputeExtraArraySizeForIntelGen12(...);
uint32_t newSize = resourceDescriptor.DepthOrArraySize + extraSize;
if (newSize > std::numeric_limits<UINT16>::max()) {
return DAWN_OUT_OF_MEMORY_ERROR("Texture array size with Intel Gen12 workaround exceeds UINT16 max");
}
revisedDescriptor.DepthOrArraySize = static_cast<UINT16>(newSize);
Evaluated with Chrome root at commit: a9cbf6e8b275fe4147435aa905f3b7f5a656f5f0
Results from 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.