CVE-2026-9975
Overview
Files Changed
include/platform/autogen/FeaturesVk_autogen.hinclude/platform/vk_features.jsonsrc/libANGLE/renderer/vulkan/TextureVk.cppsrc/libANGLE/renderer/vulkan/vk_format_utils.cppsrc/tests/gl_tests/VulkanExternalImageTest.cpputil/autogen/angle_features_autogen.cpputil/autogen/angle_features_autogen.h
Patch
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,
Regression Test / PoC
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
Original Bug Report
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.cppthird_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cppthird_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cppthird_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cppthird_party/angle/src/libANGLE/renderer/vulkan/vk_utils.cppgpu/command_buffer/service/shared_image/external_vk_image_backing.ccgpu/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:
- Chromium Allocation: In
gpu/vulkan/vulkan_image.cc, Chromium allocatesNbytes of device memory for aVkImagebased on a specific, requested format (e.g., a narrow 16-bit format) and exports a file descriptor (FD). - Import to ANGLE: Chromium passes this FD and the exact size
Nto ANGLE viaglImportMemoryFdEXT(handled inExternalVkImageBacking::CreateGLTexture). ANGLE stores this size internally asmSize = size;(MemoryObjectVk::importFd). - Format Fallback: When Chromium calls
glTexStorageMemFlags2DANGLEto 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) inTextureVk::setStorageExternalMemory. - Image Recreation: ANGLE calls
MemoryObjectVk::createImageusing this wider fallback format. It queries the memory requirements for the new format, which yields a required sizeMthat is larger than the imported sizeN. - Bypassed Check: The code attempts to verify the sizes match:
ASSERT(externalMemoryRequirements.size == mSize);(MemoryObjectVk.cpp:251). Because this is anASSERT, it is compiled out in production release builds, and the execution continues silently despiteM != N. - Vulkan Spec Violation: ANGLE proceeds to call
vkAllocateMemory. InFindAndAllocateCompatibleMemory(vk_utils.cpp), it setsallocInfo.allocationSize = M, while passing the FD (which only backsNbytes) via thepNextchain (VkImportMemoryFdInfoKHR). This violates the Vulkan specification, which requiresallocationSizeto 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.
- 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). - Bind this SharedImage to a WebGL texture.
- 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_ATTACHMENTsupport for the narrow format but supports a wider 32-bit fallback). - Issue WebGL draw or read calls targeting this texture to force the GPU to access the out-of-bounds
M - Nregion.
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.