Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in ANGLE
DescriptionUse after free in ANGLE
ComponentANGLE
Bug ClassUAF
Tracker499093536
Fix commit8e610d05a7c8 (angle/angle) +8/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Files Changed

  • src/libANGLE/renderer/vulkan/ShareGroupVk.cpp
  • src/libANGLE/renderer/vulkan/vk_helpers.h
From 8e610d05a7c89a9800dc5a176a3a7f9e00698861 Mon Sep 17 00:00:00 2001
From: Charlie Lao <[email protected]>
Date: Tue, 28 Apr 2026 16:47:04 -0700
Subject: [PATCH] Vulkan: Fix UAF if flushAndSubmitCommands runs into error

If ContextVk::flushAndSubmitCommands() early out, we may left in
mForeignImagesInUse HashSet. This will cause use-after-free later on
when it is accessed, for example, during context destroy. This CL
ensures we clear mForeignImagesInUse if flushAndSubmitCommands returns
error. The worst side effect is that the image will be left in wrong
layout, much better than a crash.

This is hard to write test. The suggested test will actually cause test
gets lowmemorykiller before it can run to the end.

Bug: b/499093536
Change-Id: I2ab978e305bb22d9434d74b1bc02d2f479ce53d0
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7801425
Reviewed-by: Shahbaz Youssefi <[email protected]>
Commit-Queue: Charlie Lao <[email protected]>
---

diff --git a/src/libANGLE/renderer/vulkan/ShareGroupVk.cpp b/src/libANGLE/renderer/vulkan/ShareGroupVk.cpp
index c87bf46..e7a430e 100644
--- a/src/libANGLE/renderer/vulkan/ShareGroupVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ShareGroupVk.cpp
@@ -436,8 +436,14 @@
                 // out so that VVL will not complain. Note that one image used in two contexts
                 // simultaneously is a bit tricky, this is not rock solid to avoid image layout VVL,
                 // but should solve some usage cases at least.
-                (void)sharedContextVk->flushAndSubmitCommands(
+                const angle::Result result = sharedContextVk->flushAndSubmitCommands(
                     nullptr, nullptr, QueueSubmitReason::ForeignImageRelease);
+
+                // In case of failure, remove the dangling image pointer to avoid UAF
+                if (result != angle::Result::Continue)
+                {
+                    sharedContextVk->forgetAllForeignImagesOnError();
+                }
                 ASSERT(!sharedContextVk->hasForeignImagesToTransition());
             }
         }
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index b4b9fcf..cacfb9e 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -92,6 +92,7 @@
     void onForeignImageUse(ImageHelper *image);
     void finalizeForeignImage(ImageHelper *image);
     void finalizeAllForeignImages();
+    void forgetAllForeignImagesOnError() { mForeignImagesInUse.clear(); }
 
     bool hasForeignImagesToTransition() const
     {
Loading diff…

Original Bug Report

reported by [email protected]

Potential Use-After-Free in ANGLE Vulkan via swallowed OOM error

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 potential Use-After-Free vulnerability exists in ANGLE’s Vulkan backend due to incorrect lifecycle management of EGLImages during memory pressure. When a command flush fails under out-of-device-memory conditions, a raw pointer to an ImageHelper is leaked in a tracking set, leading to a UAF when the image is later destroyed. This could allow a compromised renderer to achieve Remote Code Execution in the GPU process.

Affected files:

  • third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/ContextVk.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/ImageVk.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.h

Estimated timestamp from git blame: 2025-12-15

Summary

A potential Use-After-Free (UAF) vulnerability in the ANGLE Vulkan backend allows for potential Remote Code Execution (RCE) in the unsandboxed GPU process. The issue stems from a raw pointer being retained in a tracking set within vk::Context when a Vulkan command flush fails due to an out-of-memory error. If the underlying EGLImage is subsequently destroyed, the pointer dangles. A later successful flush during context destruction then accesses this freed memory.

Root Cause Analysis

  1. Vulnerable Tracking: In vk_helpers.h, vk::Context::mForeignImagesInUse is an angle::HashSet<ImageHelper*>. This set uses bare pointers and is not protected by MiraclePtr (as ANGLE does not currently utilize raw_ptr<T>).
  2. Swallowed Error in finalizeImageLayout: When a foreign image is processed, ContextVk::finalizeImageLayout (in ContextVk.cpp) attempts to transition the image layout back to the foreign queue by calling flushAndSubmitCommands. However, the result of this call is explicitly cast to (void), discarding any error results:
    // ContextVk.cpp:7720
    (void)flushAndSubmitCommands(nullptr, nullptr, QueueSubmitReason::ForeignImageRelease);
    
  3. Incomplete Cleanup on OOM: If the system is under heavy memory pressure, flushAndSubmitCommands can fail (e.g., VK_ERROR_OUT_OF_DEVICE_MEMORY). When it fails early, it skips the call to prepareToSubmitAllCommands(), which is responsible for calling finalizeAllForeignImages() and removing the image from mForeignImagesInUse. Because the error is swallowed, execution continues, but the ImageHelper pointer is left dangling in the tracking set.
  4. Lifecycle Mismatch: The underlying EGLImage can then be destroyed (e.g., via eglDestroyImage). This eventually reaches HardwareBufferImageSiblingVkAndroid::release, which calls SafeDelete(mImage), freeing the ImageHelper. The tracking set in the context now contains a dangling pointer.
  5. Use-After-Free during Teardown: During context destruction (eglDestroyContext), gl::Context::onDestroy triggers ContextVk::onUnMakeCurrent, which executes a final flushAndSubmitCommands. If the memory pressure has been relieved, this call succeeds, reaching prepareToSubmitAllCommands -> finalizeAllForeignImages. This iterates through the tracking set and calls image->releaseToForeign(mRenderer) on the freed ImageHelper object, resulting in UAF reads and writes (such as writing a 4-byte zero to mCurrentShaderReadStageMask).

Potential Reproduction Steps

Note: These are suggested/potential steps based on code analysis; our tooling agent does not yet have the ability to run code to provide a working proof-of-concept.

  1. On Android with the Vulkan backend, an attacker uses WebGL to create an AHardwareBuffer-backed EGLImage and binds it as a texture.
  2. Trigger a draw call using this texture, which inserts the ImageHelper pointer into the mForeignImagesInUse tracking set.
  3. Induce an Out-Of-Device-Memory (VK_ERROR_OUT_OF_DEVICE_MEMORY) state by allocating massive textures/buffers.
  4. Delete the original WebGL texture. This orphans the EGLImage and triggers ContextVk::finalizeImageLayout. The flush fails due to the OOM condition, leaving the pointer in the set.
  5. Delete the EGLImage, which calls SafeDelete(mImage) on the ImageHelper while its pointer remains in the set.
  6. Relieve the memory pressure by deleting the large allocations from step 3.
  7. Destroy the WebGL context, triggering teardown. The final successful flush will attempt to finalize the foreign images, dereferencing the freed pointer and triggering the Use-After-Free.

Proposed Fix

Do not silently swallow the error in ContextVk::finalizeImageLayout. If flushAndSubmitCommands fails (or if the context is lost), the image must be explicitly removed from mForeignImagesInUse to prevent it from dangling.

angle::Result result = flushAndSubmitCommands(nullptr, nullptr, QueueSubmitReason::ForeignImageRelease);
if (result != angle::Result::Continue)
{
    // Forcefully remove the image from the tracking set to prevent UAF if it is later deleted.
    mRenderPassCommands->getCommandState()->removeForeignImage(image);
    // Handle error appropriately rather than continuing blindly.
}

Alternatively, consider migrating ANGLE’s internal pointer tracking structures to use base::raw_ptr to benefit from MiraclePtr protections.

Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33


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.

View on issue tracker