CVE-2026-14398
Overview
Files Changed
src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp
Patch
From ca3a627b72709b6fd4b56a1517ff1a926f7c3fca Mon Sep 17 00:00:00 2001
From: Charlie Lao <cclao@google.com>
Date: Wed, 13 May 2026 17:18:28 -0700
Subject: [PATCH] Vulkan: Ensure we clean up mHandle when Event::init() fail
Otherwise we may leave a dangling mHandle in RefCountedEvent and cause
potential UAF later.
Bug: b/512995785
Change-Id: Id9148c7d05fbca4abd9eda0e7f1c73edc372c224
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7846935
Reviewed-by: Yuxin Hu <yuxinhu@google.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Charlie Lao <cclao@google.com>
---
diff --git a/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp b/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp
index 1948b6c..3d855ae 100644
--- a/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp
@@ -60,7 +60,9 @@
// that many VkEvents under normal situation. If we failed to allocate, there is a
// high chance that we may have a leak somewhere. This macro should help us catch
// such potential bugs in the bots if that happens.
- UNREACHABLE();
+ ASSERT(false);
+ // Ensure memory is freed and pointer is nulled
+ SafeDelete(mHandle);
// If still fail to create, we just return. An invalid event will trigger
// pipelineBarrier code path
return false;
Original Bug Report
Potential Use-After-Free in ANGLE Vulkan via RefCountedEvent initialization failure
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 potential Use-After-Free (UAF) vulnerability exists in ANGLE’s Vulkan backend when vkCreateEvent fails during synchronization initialization. A leaked heap-allocated handle persists in recycled command buffers, leading to premature destruction and subsequent dangling pointer access.
Affected files:
third_party/angle/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cppthird_party/angle/src/libANGLE/renderer/vulkan/vk_ref_counted_event.hthird_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cppthird_party/angle/src/libANGLE/renderer/vulkan/vk_renderer.cpp
Estimated timestamp from git blame: 2024-05-10
Summary
A Use-After-Free (UAF) vulnerability has been identified in ANGLE’s Vulkan backend, specifically within the lifecycle management of RefCountedEvent. The issue stems from an inconsistent state created when vkCreateEvent fails, allowing a heap-allocated pointer to survive command buffer recycling. This can lead to memory corruption when the stale pointer is later reused and prematurely freed.
Root Cause Analysis
In third_party/angle/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp, the RefCountedEvent::init() function handles the allocation and initialization of Vulkan events. When a VkEvent fails to initialize (e.g., due to driver handle exhaustion), the function returns false but fails to clean up the newly allocated mHandle member:
// third_party/angle/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp:43
mHandle = new RefCounted<EventAndStage>; // Refcount starts at 0
// ... initialization attempts ...
if (result != VK_SUCCESS)
{
UNREACHABLE();
return false; // mHandle remains non-null, pointing to a RefCounted object with refcount 0
}
The calling function, RefCountedEventArray::initEventAtStage(), receives the false return and does not set the corresponding bit in its mBitMask. Because the CommandBufferHelper recycling logic relies on this bitmask to identify and release active events, the “zombie” mHandle pointer remains in the mEvents array when the helper is returned to a pool.
Potential Exploitation Path
- Triggering the Poisoned State: An attacker uses WebGL to exhaust
VkEventhandles (a common limitation on some drivers) or creates memory pressure, causingvkCreateEventto fail during a synchronization operation. This leaves a recycledCommandBufferHelperwith a non-nullmHandlebut a zero reference count in its event array. - Incorrect Adoption: When the
CommandBufferHelperis reused, a subsequent image operation may check if an event is already valid for its stage. SincemHandleis non-null,RefCountedEvent::valid()returns true.ImageHelper::setCurrentRefCountedEventthen adopts this zombie event via copy assignment, which increments the reference count from 0 to 1. - Premature Free: When the adopting
ImageHelperlater releases its reference (e.g., during a layout transition), the reference count drops from 1 back to 0. On hardware drivers (whererecycleVkEventis typically disabled), this triggersSafeDelete(mHandle), freeing the memory. - Use-After-Free: The
CommandBufferHelperstill holds the now-freed pointer. Subsequent attempts to use that event stage on the same helper—either by anotherImageHelperor during command buffer submission—will result in a UAF write (refcount increment/decrement) or a UAF read (retrieving theVkEventhandle from freed memory).
In ANGLE, mHandle is a bare pointer to a RefCounted object, meaning this vulnerability is not mitigated by MiraclePtr. On Android, where the GPU process is often unsandboxed, this could potentially lead to platform-level arbitrary code execution.
Suggested Fix
Ensure that mHandle is properly deleted and set to nullptr if initialization fails in RefCountedEvent::init():
if (result != VK_SUCCESS)
{
UNREACHABLE();
SafeDelete(mHandle); // Ensure memory is freed and pointer is nulled
return false;
}
Reproducibility Note
These steps are based on a source code analysis of the Vulkan backend synchronization logic. Tooling constraints currently prevent the execution of a proof-of-concept to confirm reachability under specific driver conditions.
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.