Critical chrome Type Confusion 📄 Reporter bug report 🔧 Commit mapped

Overview

Critical
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactType Confusion in Dawn
DescriptionType Confusion in Dawn
ComponentDawn
Bug ClassType Confusion
Tracker513012139
Fix commita9365ae383d3 (dawn) +20/-15
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
if
src/dawn/native/RenderPassEncoder.cpp
modified
for
src/dawn/native/RenderPassEncoder.cpp
modified

Files Changed

  • src/dawn/native/RenderPassEncoder.cpp
From a9365ae383d3fb461aa36a41d47e5d252abce122 Mon Sep 17 00:00:00 2001
From: Brandon Jones <bajones@chromium.org>
Date: Thu, 14 May 2026 13:20:05 -0700
Subject: [PATCH] Don't allocate command space for 0 render bundles

Early terminates APIExecuteBundles on the Render Pass if count is
0, which was otherwise causing allocation issues.

Bug: 513012139
Fixes: 513012139
Change-Id: Ia58e6da36c8049573e5a60a558c65fdfa72bedc8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/308855
Auto-Submit: Brandon Jones <bajones@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Brandon Jones <bajones@chromium.org>
---

diff --git a/src/dawn/native/RenderPassEncoder.cpp b/src/dawn/native/RenderPassEncoder.cpp
index 17bb569..f9898aa 100644
--- a/src/dawn/native/RenderPassEncoder.cpp
+++ b/src/dawn/native/RenderPassEncoder.cpp
@@ -362,26 +362,31 @@
                 }
             }
 
+            // Always reset state
             mCommandBufferState = CommandBufferStateTracker{};
 
-            ExecuteBundlesCmd* cmd =
-                allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
-            cmd->count = count;
+            // Only encode an ExecuteBundles command if count > 0
+            if (count) {
+                ExecuteBundlesCmd* cmd =
+                    allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
+                cmd->count = count;
 
-            Ref<RenderBundleBase>* bundles = allocator->AllocateData<Ref<RenderBundleBase>>(count);
-            for (uint32_t i = 0; i < count; ++i) {
-                bundles[i] = renderBundles[i];
+                Ref<RenderBundleBase>* bundles =
+                    allocator->AllocateData<Ref<RenderBundleBase>>(count);
+                for (uint32_t i = 0; i < count; ++i) {
+                    bundles[i] = renderBundles[i];
 
-                mUsageTracker.MergeResourceUsages(bundles[i]->GetResourceUsage());
-                if (bundles[i]->GetResourceUsage().usesFramebufferFetch) {
-                    mUsageTracker.MarkFramebufferFetchUsed();
+                    mUsageTracker.MergeResourceUsages(bundles[i]->GetResourceUsage());
+                    if (bundles[i]->GetResourceUsage().usesFramebufferFetch) {
+                        mUsageTracker.MarkFramebufferFetchUsed();
+                    }
+
+                    if (IsValidationEnabled()) {
+                        mIndirectDrawMetadata.AddBundle(renderBundles[i]);
+                    }
+
+                    mDrawCount += bundles[i]->GetDrawCount();
                 }
-
-                if (IsValidationEnabled()) {
-                    mIndirectDrawMetadata.AddBundle(renderBundles[i]);
-                }
-
-                mDrawCount += bundles[i]->GetDrawCount();
             }
 
             return {};
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential command stream desynchronization in Dawn via transient OOM in ExecuteBundles

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 RenderPassEncoder::APIExecuteBundles allows for command stream desynchronization when a transient out-of-memory (OOM) condition occurs during the execution of an empty bundle list. This leads to type confusion in the GPU process, where attacker-controlled command data is interpreted as internal object pointers.

Affected files:

  • third_party/dawn/src/dawn/native/RenderPassEncoder.cpp
  • third_party/dawn/src/dawn/native/CommandAllocator.cpp
  • third_party/dawn/src/dawn/native/CommandAllocator.h
  • third_party/dawn/src/dawn/native/vulkan/CommandBufferVk.cpp
  • third_party/dawn/src/dawn/native/Commands.cpp

Estimated timestamp from git blame: Unknown (Google3 checkout)

Summary

A potential vulnerability in Dawn (Chromium’s WebGPU implementation) could allow a compromised renderer to desynchronize the GPU process’s command stream. This is achieved by triggering a transient out-of-memory (OOM) condition during an executeBundles call with a count of zero. The resulting desynchronization leads to type confusion, allowing renderer-controlled data to be interpreted as internal pointers (Ref<T>), which could enable arbitrary code execution in the GPU process.

Root Cause Analysis

In third_party/dawn/src/dawn/native/RenderPassEncoder.cpp, the APIExecuteBundles function records an ExecuteBundlesCmd and then unconditionally attempts to allocate space for a bundle array using allocator->AllocateData<Ref<RenderBundleBase>>(count):

ExecuteBundlesCmd* cmd = allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
cmd->count = count;
Ref<RenderBundleBase>* bundles = allocator->AllocateData<Ref<RenderBundleBase>>(count);

When count is 0, AllocateData still attempts to write a kAdditionalData marker to the command stream. If the current command block lacks sufficient space, Allocate invokes AllocateInNewBlock. In third_party/dawn/src/dawn/native/CommandAllocator.cpp, if the allocation of a new block fails due to transient memory pressure, it returns nullptr, and the kAdditionalData marker is never written.

Crucially, because count is zero, the encoder’s loop never dereferences the returned nullptr, and the function returns success without checking if the allocation (and the marker write) actually succeeded. This results in a command stream that is missing a required marker.

Potential Exploitation Path

  1. Induce Memory Pressure: An attacker induces transient memory pressure in the GPU process via WebGPU resource exhaustion.
  2. Trigger Vulnerability: The attacker calls executeBundles(0, []). If the timing is precise, the ExecuteBundlesCmd is written to a full block, but the subsequent kAdditionalData marker allocation fails.
  3. Command Injection: The attacker encodes a payload command with controlled data, such as setBlendConstant({R, G, B, A}).
  4. Backend Desynchronization: During command execution in the GPU process, the iterator processes ExecuteBundlesCmd and calls NextData<T>(0). Because the kAdditionalData marker is missing, the iterator incorrectly consumes the first uint32_t of the next block (the next command’s ID) as the marker.
  5. Type Confusion: The iterator is now misaligned and interprets the payload of the subsequent command (e.g., the floats in SetBlendConstant) as a new command ID. By controlling these bytes, an attacker can inject a command like SetRenderPipeline, which contains a Ref<T> field. The GPU process will then interpret controlled bytes as a pointer and call Release() on it during cleanup, leading to RCE.

Impact

This allows for arbitrary code execution in the GPU process. On Android, the GPU process is typically unsandboxed, making this a critical privilege escalation. On other platforms, it represents a significant step toward a full sandbox escape.

Suggested Fix

All calls to Allocate and AllocateData in RenderPassEncoder.cpp (and other encoders) should be checked for nullptr. If an allocation fails, the encoder should return a MaybeError to the EncodingContext, ensuring the command buffer is marked as invalid and not submitted for execution. Alternatively, the CommandAllocator could be modified to track a persistent error state upon any allocation failure.

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.

View on issue tracker