High chrome UAF 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Dawn
DescriptionUse after free in Dawn
ComponentDawn
Bug ClassUAF
Tracker549311485
Fix commitdaa0cc047acd (dawn) +19/-7
CISA KEVNot listed
CreditedGoogle
Disclosed2026-09-01

Background

Dawn
Chromium’s implementation of the WebGPU standard that translates WebGPU calls into native GPU APIs such as Vulkan.
`DescriptorSetAllocator`
a Dawn Vulkan helper that owns a VkDescriptorPool and hands out VkDescriptorSet objects allocated from it.
`vkAllocateDescriptorSets`
the Vulkan entry point that carves descriptor sets out of a descriptor pool and can fail with an out-of-memory result.
UAF (use-after-free)
a memory-safety bug where code dereferences or frees memory that has already been freed, producing a wild read or invalid free.

Root Cause Analysis

The vulnerable path is DescriptorSetAllocator::AllocateDescriptorSets, which calls mDevice->fn.AllocateDescriptorSets and, on any error, immediately called mDevice->fn.DestroyDescriptorPool to clean up the pool. The violated invariant is that a descriptor pool is safe to destroy after a failed allocation; on Imagination (PowerVR / IMG) drivers this does not hold, because the driver’s chunk-allocation path publishes the memory chunk before allocating and fails to unpublish it when allocation fails with VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY, leaving a dangling freed meminfo pointer inside the pool. The subsequent vkDestroyDescriptorPool call then dereferences that already-freed pointer, causing a UAF read and a wild free inside the driver.

The fix inspects the vendor via gpu_info::IsImgTec on the physical device and the concrete VkResult, and skips the DestroyDescriptorPool call precisely when the pool is in this corrupted state, avoiding the dangling-pointer dereference. Because the OOM failure is an internal error that leads to device loss anyway, leaking the pool by skipping destruction is acceptable and cannot propagate further.

Key insight
The single core mistake was unconditionally destroying a descriptor pool after a failed allocation, assuming the pool remained in a well-defined state; the fix recognizes that a buggy IMG driver leaves the pool corrupted after an OOM failure and therefore conditionally skips DestroyDescriptorPool for exactly that vendor-and-error combination.

Attack Path

  1. Reach the allocator An attacker runs WebGPU content that repeatedly creates bind groups on a device backed by an Imagination (PowerVR) GPU, driving Dawn into DescriptorSetAllocator::AllocateDescriptorSets.
  2. Force an OOM failure Content exhausts host or device memory so that vkAllocateDescriptorSets returns VK_ERROR_OUT_OF_HOST_MEMORY or VK_ERROR_OUT_OF_DEVICE_MEMORY.
  3. Trigger the corrupted cleanup The error branch calls mDevice->fn.DestroyDescriptorPool on a pool whose meminfo chunk the IMG driver already freed but left published.
  4. Dereference the dangling pointer vkDestroyDescriptorPool follows the freed meminfo pointer, producing a use-after-free read and an invalid free inside the driver.

Impact Assessment

An attacker gains a use-after-free (dangling read plus wild free) triggered from within the GPU process while servicing WebGPU workloads on Imagination/PowerVR hardware. Preconditions are an IMG-vendor GPU and the ability to force a descriptor-set allocation OOM, which is reachable from web content driving WebGPU. In practice the corrupted state leads to device loss, so the primary observable impact is a memory-safety crash in the GPU process rather than a guaranteed higher-order primitive.

Changed Functions

FunctionChangeNotes
if
src/dawn/native/vulkan/DescriptorSetAllocator.cpp
modified

Files Changed

  • src/dawn/native/vulkan/DescriptorSetAllocator.cpp

Audit Directions

  • Error-path resource cleanup
    Audit every Destroy/Free call reached only after an API failure and confirm the object is still in a valid, destroyable state on that specific driver and error code.
  • Vendor-specific driver quirks
    Look for other Vulkan/GPU calls where a known buggy vendor driver leaves objects in an inconsistent state on OOM, and gate cleanup with gpu_info vendor checks like IsImgTec.
  • Discarded specific error results
    Flag places that collapse a detailed VkResult into a generic MaybeError before branching, since the exact code (e.g. VK_ERROR_OUT_OF_HOST_MEMORY) is needed to make safe cleanup decisions.
From daa0cc047acd570fbd5c127db4262e1a98637eb7 Mon Sep 17 00:00:00 2001
From: Lokbondo Kung <[email protected]>
Date: Fri, 21 Aug 2026 11:13:48 -0700
Subject: [PATCH] [vulkan] Add workaround for UAF in DestroyDescriptorPool.

- As per the bug and the related internal Android issue,
  this works around a temporary issue in the IMG driver
  that causes a UAF when we attempt to call
  AllocateDescriptorSets and run into an OOM.
- The more "proper" fix would probably be to implement
  suballocations, but since that is a much larger effort,
  this is a band-aid fix to avoid the UAF issue for now.
- Note that since the error that is generated is an
  internal error, this eventually leads to a device loss
  so it is acceptable to skip the Destroy call in this
  case since even if it would lead to a leak, it cannot
  propagate further.

Bug: 549311485
Change-Id: I8c951e879bb405943698c179962275687e828168
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/334695
Reviewed-by: Kai Ninomiya <[email protected]>
Commit-Queue: Loko Kung <[email protected]>
---

diff --git a/src/dawn/native/vulkan/DescriptorSetAllocator.cpp b/src/dawn/native/vulkan/DescriptorSetAllocator.cpp
index ed36582..d14b23e 100644
--- a/src/dawn/native/vulkan/DescriptorSetAllocator.cpp
+++ b/src/dawn/native/vulkan/DescriptorSetAllocator.cpp
@@ -30,6 +30,8 @@
 #include <algorithm>
 #include <utility>
 
+#include "src/dawn/common/GPUInfo.h"
+#include "src/dawn/native/PhysicalDevice.h"
 #include "src/dawn/native/Queue.h"
 #include "src/dawn/native/vulkan/DeviceVk.h"
 #include "src/dawn/native/vulkan/FencedDeleter.h"
@@ -184,15 +186,25 @@
     allocateInfo.pSetLayouts = AsVkArray(layouts.data());
 
     std::vector<VkDescriptorSet> sets(mMaxSets);
-    MaybeError result =
-        CheckVkSuccess(mDevice->fn.AllocateDescriptorSets(mDevice->GetVkDevice(), &allocateInfo,
-                                                          AsVkArray(sets.data())),
-                       "AllocateDescriptorSets");
+    VkResult vkResult = VkResult::WrapUnsafe(
+        INJECT_ERROR_OR_RUN(mDevice->fn.AllocateDescriptorSets(
+                                mDevice->GetVkDevice(), &allocateInfo, AsVkArray(sets.data())),
+                            VK_FAKE_ERROR_FOR_TESTING));
+    MaybeError result = CheckVkSuccessImpl(vkResult, "AllocateDescriptorSets");
     if (result.IsError()) {
-        // On an error we can destroy the pool immediately because no command references it.
-        mDevice->fn.DestroyDescriptorPool(mDevice->GetVkDevice(), descriptorPool, nullptr);
-        DAWN_TRY(std::move(result));
+        // TODO(crbug.com/549311485): On Imagination (PowerVR) drivers, when AllocateDescriptorSets
+        // fails with host or device OOM, the driver's chunk allocation path publishes the chunk
+        // before allocation and fails to unpublish on error. Calling vkDestroyDescriptorPool
+        // dereferences the dangling freed meminfo pointer and crashes (UAF read / wild free).
+        bool isCorruptedImaginationPool =
+            gpu_info::IsImgTec(mDevice->GetPhysicalDevice()->GetVendorId()) &&
+            (vkResult == VK_ERROR_OUT_OF_HOST_MEMORY || vkResult == VK_ERROR_OUT_OF_DEVICE_MEMORY);
+        if (!isCorruptedImaginationPool) {
+            // On an error we can destroy the pool immediately because no command references it.
+            mDevice->fn.DestroyDescriptorPool(mDevice->GetVkDevice(), descriptorPool, nullptr);
+        }
     }
+    DAWN_TRY(std::move(result));
 
     std::vector<SetIndex> freeSetIndices;
     freeSetIndices.reserve(mMaxSets);
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.