CVE-2026-9967
Overview
Files Changed
DEPSthird_party/vulkan_memory_allocator
Patch
From 92b71d79a7728fc4396198bfc673c700447e30f3 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 11 May 2026 14:39:52 -0400
Subject: [PATCH] [M144-LTS] Roll cherry-picked fixes to VMA
Bug: chromium:506414791
Change-Id: I0c4b08dc15bc1f0ce601261738d113714a2b7d52
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7835173
Auto-Submit: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Charlie Lao <cclao@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
(cherry picked from commit bfa7c8e9b8f1c33d0a2fc101ca2de646090d87cd)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8051309
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Auto-Submit: Gyuyoung Kim (xWF) <qkim@google.com>
---
diff --git a/DEPS b/DEPS
index bfbe2dd..7f46f6c 100644
--- a/DEPS
+++ b/DEPS
@@ -1134,7 +1134,7 @@
},
'third_party/vulkan_memory_allocator': {
- 'url': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator@cb0597213b0fcb999caa9ed08c2f88dc45eb7d50',
+ 'url': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator@7e55b011e16182fc349149abbd3aaf3b1db46421',
'condition': 'not build_with_chromium',
},
diff --git a/third_party/vulkan_memory_allocator b/third_party/vulkan_memory_allocator
index cb05972..7e55b01 160000
--- a/third_party/vulkan_memory_allocator
+++ b/third_party/vulkan_memory_allocator
@@ -1 +1 @@
-Subproject commit cb0597213b0fcb999caa9ed08c2f88dc45eb7d50
+Subproject commit 7e55b011e16182fc349149abbd3aaf3b1db46421
Original Bug Report
Potential wild memory write in GPU process via VMA mapping hysteresis desynchronization
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 the Vulkan Memory Allocator (VMA) allows its mapping hysteresis state machine to become desynchronized if a vkMapMemory call fails. This causes subsequent mapping requests to return success with a NULL base pointer, which downstream components like Skia offset and write to, leading to arbitrary memory corruption in the GPU process.
Affected files:
third_party/vulkan_memory_allocator/include/vk_mem_alloc.hthird_party/skia/src/gpu/ganesh/vk/GrVkBuffer.cppthird_party/skia/src/gpu/ganesh/vk/GrVkGpu.cppthird_party/skia/src/gpu/graphite/vk/VulkanBuffer.cppthird_party/angle/src/libANGLE/renderer/vulkan/vk_renderer.cpp
Estimated timestamp from git blame: 2022-06-14
Summary
A potential vulnerability exists in the Vulkan Memory Allocator (VMA) library used by Chrome’s GPU process (via Skia and ANGLE). When VMA’s mapping hysteresis feature is enabled (which is the default), a failed memory mapping request leaves the internal state machine in a desynchronized state. Subsequent requests to map the same memory block will hit a fast path, falsely returning VK_SUCCESS but providing a NULL base pointer. Because VMA suballocations include an offset, downstream callers receive a non-NULL pointer (e.g., NULL + offset) and bypass standard null checks, leading to wild memory writes of attacker-controlled data.
Root Cause Analysis
In third_party/vulkan_memory_allocator/include/vk_mem_alloc.h, the VmaDeviceMemoryBlock::Map() function manages persistent mapping state and hysteresis.
// third_party/vulkan_memory_allocator/include/vk_mem_alloc.h
VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex);
const uint32_t oldTotalMapCount = m_MapCount + m_MappingHysteresis.GetExtraMapping();
m_MappingHysteresis.PostMap(); // State is advanced here
if (oldTotalMapCount != 0) {
// Fast path: assumes memory is already mapped
m_MapCount += count;
VMA_ASSERT(m_pMappedData != VMA_NULL);
if (ppData != VMA_NULL) { *ppData = m_pMappedData; }
return VK_SUCCESS;
} else {
VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(..., &m_pMappedData);
if (result == VK_SUCCESS) {
// ...
m_MapCount = count;
}
return result; // Failure path: NO rollback of PostMap()
}
The PostMap() function increments counters. If a threshold is reached, it sets m_ExtraMapping = 1, simulating an active map to keep memory resident. However, oldTotalMapCount is calculated before PostMap() executes.
If the subsequent vkMapMemory call fails (e.g., due to host memory exhaustion), the function returns the error but fails to revert the m_ExtraMapping state change made by PostMap(). The block is now desynchronized: m_ExtraMapping is 1, but m_pMappedData remains VMA_NULL.
On the next Map() call, oldTotalMapCount evaluates to 1. The code enters the fast path, bypassing vkMapMemory, and returns VK_SUCCESS while assigning VMA_NULL to *ppData. (Note: The VMA_ASSERT is compiled out in release builds).
Exploitation Scenario
An attacker could potentially exploit this from a malicious webpage using WebGL or WebGPU:
- The attacker creates a host-mappable buffer (the “victim”), which VMA suballocates from a larger
VmaDeviceMemoryBlockwith a non-zero offset (e.g.,0x8000000). - The attacker updates the buffer multiple times, causing repeated map/unmap cycles. This increments the hysteresis counters until they are one step away from triggering
m_ExtraMapping = 1. - The attacker exhausts host virtual address space in the GPU process by allocating numerous large textures.
- The attacker issues another buffer update.
PostMap()setsm_ExtraMapping = 1, butvkMapMemoryfails due to memory exhaustion. The error is returned, and state is desynchronized. - The attacker frees the textures to restore memory availability.
- The attacker issues a final update to the victim buffer with a malicious payload. VMA hits the fast path and returns
VK_SUCCESSwith a base pointer of0x0. VmaAllocator_T::Map()adds the suballocation offset:*ppData = 0x0 + 0x8000000.- Skia’s
GrVkBuffer::onUpdateDatachecksif (!fMapPtr). Since0x8000000is not null, the check passes. - Skia executes
memcpy(fMapPtr + offset, src, size), copying attacker data directly to0x8000000.
By spraying the address space (especially on 32-bit platforms like Android, where the GPU process is unsandboxed), the attacker can ensure this low address maps to critical data structures, leading to arbitrary code execution.
Note: These steps are suggested based on code analysis; a full proof-of-concept has not yet been executed by our tooling.
Suggested Fix
In VmaDeviceMemoryBlock::Map(), if vkMapMemory fails, the state change introduced by m_MappingHysteresis.PostMap() must be rolled back. Alternatively, PostMap() should only be called after vkMapMemory succeeds.
Evaluated with Chrome root at commit: a1e33f5848218e21d4a16ae2c1bc94e815c30c7f
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.