Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds read and write in ANGLE
DescriptionOut of bounds read and write in ANGLE
ComponentANGLE
Bug ClassOOB
Tracker511719039
Fix commitdb169a4acad9 (angle/angle) +26/-3
CISA KEVNot listed
CreditedGoogle
Disclosed2026-05-27

Files Changed

  • include/platform/autogen/FeaturesVk_autogen.h
  • include/platform/vk_features.json
  • src/libANGLE/renderer/vulkan/TextureVk.cpp
  • src/libANGLE/renderer/vulkan/vk_format_utils.cpp
  • src/tests/gl_tests/VulkanExternalImageTest.cpp
  • util/autogen/angle_features_autogen.cpp
  • util/autogen/angle_features_autogen.h
From db169a4acad977725071c9f9376594265cc644b0 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <[email protected]>
Date: Thu, 14 May 2026 10:04:26 -0400
Subject: [PATCH] Vulkan: Don't use renderable-format-fallback for external images

Complementary fix to 189b249fba4d8fb331f4ac145b8c2754f7ef5f01, use the
external image's format to determine VkImageUsageFlags, instead of the
renderable fallback which could be different.

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

diff --git a/include/platform/autogen/FeaturesVk_autogen.h b/include/platform/autogen/FeaturesVk_autogen.h
index fae0230..dbdbca0 100644
--- a/include/platform/autogen/FeaturesVk_autogen.h
+++ b/include/platform/autogen/FeaturesVk_autogen.h
@@ -50,6 +50,12 @@
         &members,
     };
 
+    FeatureInfo forceRenderableFallbackFormat = {
+        "forceRenderableFallbackFormat",
+        FeatureCategory::VulkanWorkarounds,
+        &members,
+    };
+
     FeatureInfo clampPointSize = {
         "clampPointSize",
         FeatureCategory::VulkanWorkarounds,
diff --git a/include/platform/vk_features.json b/include/platform/vk_features.json
index d33794f..ed839c9 100644
--- a/include/platform/vk_features.json
+++ b/include/platform/vk_features.json
@@ -45,6 +45,13 @@
             ]
         },
         {
+            "name": "force_renderable_fallback_format",
+            "category": "Workarounds",
+            "description": [
+                "Force a fallback renderable format for angle_end2end_tests"
+            ]
+        },
+        {
             "name": "clamp_point_size",
             "category": "Workarounds",
             "description": [
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index 1daf139..94fe1fd 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -2241,7 +2241,8 @@
     vk::Renderer *renderer         = contextVk->getRenderer();
 
     const vk::Format &vkFormat     = renderer->getFormat(internalFormat);
-    angle::FormatID actualFormatID = vkFormat.getActualRenderableImageFormatID();
+    angle::FormatID actualFormatID =
+        vkFormat.getActualImageFormatID(vk::ImageFormatSupport::SampleOnly);
 
     releaseAndDeleteImageAndViews(contextVk);
 
diff --git a/src/libANGLE/renderer/vulkan/vk_format_utils.cpp b/src/libANGLE/renderer/vulkan/vk_format_utils.cpp
index 7550422..60e647c 100644
--- a/src/libANGLE/renderer/vulkan/vk_format_utils.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_format_utils.cpp
@@ -181,6 +181,11 @@
     if (testFunction != HasNonFilterableTextureFormatSupport &&
         !(format.isSnorm() && format.channelCount == 3) && !format.isBlock)
     {
+        if (renderer->getFeatures().forceRenderableFallbackFormat.enabled)
+        {
+            skip = 1;
+        }
+
         // Rendering to RGB SNORM textures is not supported on Android.
         // Compressed textures also need to perform this check.
         testFunction = HasFullTextureFormatSupport;
diff --git a/src/tests/gl_tests/VulkanExternalImageTest.cpp b/src/tests/gl_tests/VulkanExternalImageTest.cpp
index 05f66bc..b54ba5e 100644
--- a/src/tests/gl_tests/VulkanExternalImageTest.cpp
+++ b/src/tests/gl_tests/VulkanExternalImageTest.cpp
@@ -1804,6 +1804,8 @@
                                                    enableDebugLayers());
 }
 
-ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VulkanExternalImageTest);
-ANGLE_INSTANTIATE_TEST_ES31(VulkanExternalImageTestES31);
+ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(VulkanExternalImageTest,
+                                       ES3_VULKAN().enable(Feature::ForceRenderableFallbackFormat));
+ANGLE_INSTANTIATE_TEST_ES31_AND(VulkanExternalImageTestES31,
+                                ES31_VULKAN().enable(Feature::ForceRenderableFallbackFormat));
 }  // namespace angle
diff --git a/util/autogen/angle_features_autogen.cpp b/util/autogen/angle_features_autogen.cpp
index ffe34a2..f6a42e4 100644
--- a/util/autogen/angle_features_autogen.cpp
+++ b/util/autogen/angle_features_autogen.cpp
@@ -205,6 +205,7 @@
     {Feature::ForceNearestMipFiltering, "forceNearestMipFiltering"},
     {Feature::ForceNonCSBaseMipmapGeneration, "forceNonCSBaseMipmapGeneration"},
     {Feature::ForcePassthroughShaders, "forcePassthroughShaders"},
+    {Feature::ForceRenderableFallbackFormat, "forceRenderableFallbackFormat"},
     {Feature::ForceRobustResourceInit, "forceRobustResourceInit"},
     {Feature::ForceSampleUsageForAhbBackedImages, "forceSampleUsageForAhbBackedImages"},
     {Feature::ForceSizePointerForBoundVertexBuffers, "forceSizePointerForBoundVertexBuffers"},
diff --git a/util/autogen/angle_features_autogen.h b/util/autogen/angle_features_autogen.h
index 8dc083f..4cc4975 100644
--- a/util/autogen/angle_features_autogen.h
+++ b/util/autogen/angle_features_autogen.h
@@ -205,6 +205,7 @@
     ForceNearestMipFiltering,
     ForceNonCSBaseMipmapGeneration,
     ForcePassthroughShaders,
+    ForceRenderableFallbackFormat,
     ForceRobustResourceInit,
     ForceSampleUsageForAhbBackedImages,
     ForceSizePointerForBoundVertexBuffers,
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/src/tests/gl_tests/VulkanExternalImageTest.cpp b/src/tests/gl_tests/VulkanExternalImageTest.cpp
index 05f66bc..b54ba5e 100644
--- a/src/tests/gl_tests/VulkanExternalImageTest.cpp
+++ b/src/tests/gl_tests/VulkanExternalImageTest.cpp
@@ -1804,6 +1804,8 @@
                                                    enableDebugLayers());
 }
 
-ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VulkanExternalImageTest);
-ANGLE_INSTANTIATE_TEST_ES31(VulkanExternalImageTestES31);
+ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(VulkanExternalImageTest,
+                                       ES3_VULKAN().enable(Feature::ForceRenderableFallbackFormat));
+ANGLE_INSTANTIATE_TEST_ES31_AND(VulkanExternalImageTestES31,
+                                ES31_VULKAN().enable(Feature::ForceRenderableFallbackFormat));
 }  // namespace angle
Loading diff…

Original Bug Report

reported by [email protected]

Potential OOB GPU access in ANGLE via undersized imported VkDeviceMemory on format fallback

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: ANGLE’s Vulkan backend may fall back to a wider texture format than the one used to allocate an imported external memory object. This results in passing an allocation size to the Vulkan driver that is larger than the underlying imported file descriptor. The critical check for this mismatch is an ASSERT, which is disabled in release builds, potentially leading to out-of-bounds VRAM access.

Affected files:

  • third_party/angle/src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/vk_utils.cpp
  • gpu/command_buffer/service/shared_image/external_vk_image_backing.cc
  • gpu/command_buffer/service/shared_image/shared_image_format_service_utils.cc

Estimated timestamp from git blame: 2023-12-20

Summary

There is a potential out-of-bounds (OOB) memory access vulnerability in ANGLE’s Vulkan backend when handling external memory imports. If a specific texture format is not fully supported by the underlying Vulkan driver, ANGLE falls back to a wider format. This causes ANGLE to require a larger memory allocation than the size of the memory object originally imported from Chromium. Because the size mismatch check is only an ASSERT that compiles out in release builds, ANGLE passes conflicting size information to the Vulkan driver. Depending on how the driver handles this specification violation, it may lead to OOB VRAM read/write access.

Technical Details

The vulnerability occurs due to a disconnect between the memory allocation in Chromium and the texture creation in ANGLE:

  1. Chromium Allocation: In gpu/vulkan/vulkan_image.cc, Chromium allocates N bytes of device memory for a VkImage based on a specific, requested format (e.g., a narrow 16-bit format) and exports a file descriptor (FD).
  2. Import to ANGLE: Chromium passes this FD and the exact size N to ANGLE via glImportMemoryFdEXT (handled in ExternalVkImageBacking::CreateGLTexture). ANGLE stores this size internally as mSize = size; (MemoryObjectVk::importFd).
  3. Format Fallback: When Chromium calls glTexStorageMemFlags2DANGLE to associate the memory with a GL texture, ANGLE evaluates driver support. If the driver doesn’t support the required GL operations on the narrow format, ANGLE selects a wider fallback format (e.g., a 32-bit format) in TextureVk::setStorageExternalMemory.
  4. Image Recreation: ANGLE calls MemoryObjectVk::createImage using this wider fallback format. It queries the memory requirements for the new format, which yields a required size M that is larger than the imported size N.
  5. Bypassed Check: The code attempts to verify the sizes match: ASSERT(externalMemoryRequirements.size == mSize); (MemoryObjectVk.cpp:251). Because this is an ASSERT, it is compiled out in production release builds, and the execution continues silently despite M != N.
  6. Vulkan Spec Violation: ANGLE proceeds to call vkAllocateMemory. In FindAndAllocateCompatibleMemory (vk_utils.cpp), it sets allocInfo.allocationSize = M, while passing the FD (which only backs N bytes) via the pNext chain (VkImportMemoryFdInfoKHR). This violates the Vulkan specification, which requires allocationSize to exactly match the imported memory size.

Impact

The impact heavily depends on the behavior of the specific, often proprietary, Vulkan driver (e.g., Qualcomm Adreno, ARM Mali). If the driver blindly trusts allocationSize = M and maps M bytes into the GPU page tables, the M - N bytes will likely map to adjacent, unassociated physical VRAM pages. When the GPU hardware processes WebGL commands based on the 32-bit format layout, it will read or write past the end of the intended buffer into this M - N region. This can lead to arbitrary VRAM data leaks (cross-origin textures) or corruption of GPU state. Since the GPU process is unsandboxed on platforms like Android, this is a critical security risk.

Potential Steps to Trigger

Note: These are theoretical steps; a functional exploit has not been verified.

  1. From a compromised renderer process or malicious WebGL page, request a SharedImage with a narrow format (e.g., 16-bit RGBA_4444) and usage flags that require GL interop (e.g., renderability).
  2. Bind this SharedImage to a WebGL texture.
  3. Ensure this is run on a device where the Vulkan driver triggers ANGLE’s format fallback for the chosen format (i.e., it lacks native COLOR_ATTACHMENT support for the narrow format but supports a wider 32-bit fallback).
  4. Issue WebGL draw or read calls targeting this texture to force the GPU to access the out-of-bounds M - N region.

Suggested Fix

Convert the ASSERT in MemoryObjectVk::createImage to a hard runtime check that executes in release builds. If externalMemoryRequirements.size != mSize, the function should gracefully fail and return an error (e.g., angle::Result::Stop), preventing the invalid vkAllocateMemory call.

Evaluated with Chrome root at commit: eca8648a4e1cdfdda68c495a6003059fed641955


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