CVE-2026-13825
Overview
Files Changed
src/dawn/native/Blob.cppsrc/dawn/native/Blob.hsrc/dawn/native/vulkan/PipelineCacheVk.cpp
Patch
From e7eb019e0d8237395c80b6df7790085d09591105 Mon Sep 17 00:00:00 2001 From: Kyle Charbonneau <[email protected]> Date: Fri, 15 May 2026 07:40:37 -0700 Subject: [PATCH] Trim data returned for VkPipelineCache vkCreateGraphicsPipeline() can write less data than the allocated blob stores. If that happens shrink the blob to match the size written. Also if VulkanIncompletePipelineCacheWorkaround is triggered then ensure it's not stored into the cache. The data is suspected to be corrupted if the workaround triggers. Bug: 513209610 Change-Id: I4490dcecdd2a5a18d3118557d8fe233f37ac2ac8 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/308856 Commit-Queue: Kyle Charbonneau <[email protected]> Reviewed-by: Loko Kung <[email protected]> --- diff --git a/src/dawn/native/Blob.cpp b/src/dawn/native/Blob.cpp index 1c6072d..784a0f4 100644 --- a/src/dawn/native/Blob.cpp +++ b/src/dawn/native/Blob.cpp @@ -53,8 +53,8 @@ } // static -Blob Blob::Create(Blob&& original, size_t offset) { - Blob result(original.mData.subspan(offset), std::move(original.mDeleter)); +Blob Blob::Create(Blob&& original, size_t offset, size_t extent) { + Blob result(original.mData.subspan(offset, extent), std::move(original.mDeleter)); original.mData = {}; original.mDeleter = nullptr; return result; diff --git a/src/dawn/native/Blob.h b/src/dawn/native/Blob.h index 195c5bf1..d398a56 100644 --- a/src/dawn/native/Blob.h +++ b/src/dawn/native/Blob.h @@ -47,8 +47,9 @@ // Creates a blob of the given size. static Blob Create(size_t size); - // Takes ownership of the original blob, creating a new one that offsets the data by |offset|. - static Blob Create(Blob&& original, size_t offset); + // Takes ownership of the original blob, creating a new one with subspan of the original using + // `offset` and optionally `extent`. + static Blob Create(Blob&& original, size_t offset, size_t extent = std::dynamic_extent); template <typename T> static Blob Create(std::vector<T> vec) diff --git a/src/dawn/native/vulkan/PipelineCacheVk.cpp b/src/dawn/native/vulkan/PipelineCacheVk.cpp index 26ef309..bfa7fcd 100644 --- a/src/dawn/native/vulkan/PipelineCacheVk.cpp +++ b/src/dawn/native/vulkan/PipelineCacheVk.cpp @@ -28,6 +28,7 @@ #include "dawn/native/vulkan/PipelineCacheVk.h" #include <memory> +#include <utility> #include "dawn/native/Device.h" #include "dawn/native/Error.h" @@ -102,10 +103,18 @@ // store it to the blob cache and don't call vkGetPipelineCacheData() since it will return // corrupted data in future calls. mSkipSerialize = true; + *blob = {}; return {}; } DAWN_TRY(CheckVkSuccess(result, "GetPipelineCacheData")); + + if (bufferSize < blob->Size()) { + // vkGetPipelineCacheData() returned less data than expected. Shrink the blob so + // uninitialized data isn't stored in cache. + *blob = Blob::Create(std::move(*blob), 0, bufferSize); + } + mStoredDataSize = bufferSize; return {};
Original Bug Report
Potential uninitialized memory persistence and corruption in Dawn Vulkan pipeline cache
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 Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A logic error in Dawn’s Vulkan backend allows uninitialized GPU process heap memory to be persisted to the on-disk shader cache when a specific driver workaround is triggered. This occurs because the code fails to clear a previously allocated buffer after an incomplete serialization attempt. The persisted data is later reloaded and passed to the Vulkan driver, potentially leading to memory corruption.
Affected files:
third_party/dawn/src/dawn/native/vulkan/PipelineCacheVk.cppthird_party/dawn/src/dawn/native/PipelineCache.cppthird_party/dawn/src/dawn/native/Blob.cpp
Estimated timestamp from git blame: Unknown (Google3 checkout)
Description
A potential logic error exists in PipelineCache::SerializeToBlobImpl within Dawn’s Vulkan backend that can cause uninitialized heap memory to be persisted to the persistent blob cache. This occurs when the VulkanIncompletePipelineCacheWorkaround is triggered on specific hardware (e.g., Pixel 10, Samsung Xclipse).
Root Cause Analysis
In third_party/dawn/src/dawn/native/vulkan/PipelineCacheVk.cpp, the function SerializeToBlobImpl handles the serialization of the Vulkan pipeline cache:
- At line 95, a blob is allocated to hold the cache data:
*blob = Blob::Create(bufferSize);. Blob::Createinthird_party/dawn/src/dawn/native/Blob.cpp(line 46) allocates memory vianew uint8_t[size], which leaves the buffer uninitialized, containing residual data from the GPU process heap.vkGetPipelineCacheDatais called to fill this buffer (line 96).- If the call returns
VK_INCOMPLETEand the workaround is enabled (line 99), the code setsmSkipSerialize = trueand returns success (return {};) at line 105.
However, the function fails to clear or reset the *blob out-parameter before returning. The caller, PipelineCacheBase::Flush() in third_party/dawn/src/dawn/native/PipelineCache.cpp, subsequently checks if (blob.Size() > 0) at line 62. Since the blob was assigned an uninitialized buffer of bufferSize, this condition is true, and the uninitialized memory is stored to the persistent cache via mCache->Store(mKey, blob); (line 65).
Potential Impact
- Information Leak: Sensitive residue from the GPU process heap is written to the persistent shader cache on disk.
- Memory Corruption: On subsequent sessions, the persisted uninitialized blob is reloaded and passed as
pInitialDatatovkCreatePipelineCache(line 130 ofPipelineCacheVk.cpp). If the driver’s binary parser is not robust against malformed or uninitialized input, this could lead to memory corruption within the GPU process. - Sandbox Escape (Android): On Android, the GPU process is typically unsandboxed by default. Memory corruption in this process could allow an attacker to achieve arbitrary code execution with the user’s full privileges.
Potential Reproduction Steps (Suggested)
Note: These steps are theoretical as they rely on specific hardware behavior and have not been validated by a running exploit.
- Use an affected Android device (e.g., Pixel 10 or Samsung Xclipse) with WebGPU enabled.
- From a web page, trigger the compilation of a new shader (e.g., via
createComputePipeline). - The Vulkan driver returns
VK_INCOMPLETEduring cache serialization. - Dawn’s workaround triggers but fails to clear the blob out-parameter.
- The uninitialized heap memory is written to the on-disk cache.
- Restart the browser and re-trigger the same pipeline creation. The corrupted cache is loaded and passed to the driver’s
vkCreatePipelineCache, potentially causing corruption.
Suggested Fix
Ensure the *blob out-parameter is cleared before returning in the VK_INCOMPLETE workaround path in third_party/dawn/src/dawn/native/vulkan/PipelineCacheVk.cpp:
if (result == VK_INCOMPLETE && mInvalidResultWorkaround) {
mSkipSerialize = true;
*blob = Blob(); // Clear the out-parameter to prevent storage
return {};
}
Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e
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.