Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds write in ANGLE
DescriptionOut of bounds write in ANGLE
ComponentANGLE
Bug ClassOOB
Tracker517534944
Fix commit9ed0db473ba1 (chromium/src) +5/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Files Changed

  • gpu/command_buffer/service/shared_image/external_vk_image_backing_factory.cc
From 9ed0db473ba13db46bc2a067cb4b4a6a444bce7f Mon Sep 17 00:00:00 2001
From: Stacy Gaikovaia <gaiko@google.com>
Date: Thu, 28 May 2026 16:12:33 -0700
Subject: [PATCH] [viz] Add FILTER_LINEAR to shared image vk backing factory

R=syoussefi@chromium.org

Bug: 517534944
Change-Id: I7cb8caab9ac0278928350e4f0c13a8b644316754
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7882232
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Stacy Gaikovaia <gaiko@google.com>
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Auto-Submit: Stacy Gaikovaia <gaiko@google.com>
Cr-Commit-Position: refs/heads/main@{#1638023}
---

diff --git a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory.cc b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory.cc
index 2185056..c6ecbb3 100644
--- a/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory.cc
+++ b/gpu/command_buffer/service/shared_image/external_vk_image_backing_factory.cc
@@ -42,10 +42,14 @@
   // support is required when SAMPLED_IMAGE is supported. In Vulkan 1.0 all
   // formats support these features implicitly. See discussion in
   // https://github.com/KhronosGroup/Vulkan-Docs/issues/1223
-  if (feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
+  // FILTER_LINEAR is additionally required to match ANGLE as the
+  // image may be exported to it.
+  if ((feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
+      (feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
     usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT |
                    VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
                    VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+  }
 
   // VUID-VkImageViewCreateInfo-usage-02652: support for INPUT_ATTACHMENT is
   // implied by both of COLOR_ATTACHNENT and DEPTH_STENCIL_ATTACHMENT
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential GPU OOB memory access via R4G4B4A4 format widening in ANGLE Vulkan

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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A format validation discrepancy between Chromium and ANGLE can cause a size mismatch when importing RGBA4444 external images. On Vulkan drivers lacking linear filtering for R4G4B4A4, ANGLE falls back to R8G8B8A8, binding a larger VkImage to a smaller imported memory allocation. This can potentially result in out-of-bounds GPU heap access in release builds where size assertions are compiled out.

Affected files:

  • third_party/angle/src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp

Estimated timestamp from git blame: 2021-09-01

Potential Root Cause Analysis

There is a discrepancy in the format feature validation predicates between Chromium’s external image allocator and ANGLE’s Vulkan backend. This difference can cause a mismatch where Chromium allocates memory for a smaller, lower bpp format, while ANGLE widens the format (e.g., from 2 bpp R4G4B4A4 to 4 bpp R8G8B8A8), creating a mismatch when binding the memory to a VkImage via vkBindImageMemory.

In third_party/angle/src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp (line 187), ANGLE resolves the fallback format for external memory image creation by querying getActualImageFormatID with vk::ImageFormatSupport::SampleOnly:

const vk::Format &vkFormat     = renderer->getFormat(internalFormat);
const angle::FormatID intendedFormatID = vkFormat.getIntendedFormatID();
angle::FormatID actualFormatID =
    vkFormat.getActualImageFormatID(vk::ImageFormatSupport::SampleOnly);

However, in third_party/angle/src/libANGLE/renderer/vulkan/vk_format_utils.cpp (line 165), the format selection logic resolves mActualSampleOnlyImageFormatID using HasNonRenderableTextureFormatSupport as the test function for filterable formats:

bool HasNonRenderableTextureFormatSupport(vk::Renderer *renderer, angle::FormatID formatID)
{
    constexpr uint32_t kBitsColor =
        VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
    constexpr uint32_t kBitsDepth = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
    return renderer->hasImageFormatFeatureBits(formatID, kBitsColor) || ...;
}

This predicate strictly requires both SAMPLED_IMAGE_BIT and SAMPLED_IMAGE_FILTER_LINEAR_BIT on the format.

In contrast, Chromium’s allocator (gpu/command_buffer/service/shared_image/external_vk_image_backing_factory.cc, line 45) queries the exact same optimalTilingFeatures but only requires VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT:

VkImageUsageFlags GetMaximalImageUsageFlags(VkFormatFeatureFlags feature_flags) {
  VkImageUsageFlags usage_flags = 0;
  if (feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
    usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT | TRANSFER_SRC | TRANSFER_DST;
  ...
}

The Trigger Case (RGBA_4444)

Per the Vulkan specification, VK_FORMAT_R4G4B4A4_UNORM_PACK16 has zero mandatory optimal tiling features. Conforming Vulkan drivers are allowed to advertise SAMPLED_IMAGE support without supporting FILTER_LINEAR for this format. On such a driver:

  1. Chromium side: VK_FORMAT_R4G4B4A4_UNORM_PACK16 is used, and because SAMPLED_IMAGE_BIT is supported, Chromium proceeds to allocate a 2 bpp external image memory backing (~32 MiB for a 4096x4096 size).
  2. ANGLE side: HasNonRenderableTextureFormatSupport evaluates to false because FILTER_LINEAR is missing. The fallback format chain advances to R8G8B8A8_UNORM (4 bpp).
  3. Binding mismatch: ANGLE creates a VK_FORMAT_R8G8B8A8_UNORM image requiring 4 bpp (~64 MiB for 4096x4096). It imports the 32 MiB external memory allocation with allocationSize = 64 MiB and binds it.

This violates VUID-vkBindImageMemory-size-01049. The check ensuring memory requirements match in ANGLE (ASSERT(externalMemoryRequirements.size == mSize)) is a debug-only assert and is completely compiled out in release/production builds.

Potential Impact

An attacker in control of a compromised renderer process could potentially trigger out-of-bounds (OOB) reads and writes on the GPU heap within the GPU process:

  • OOB Write: By submitting glTexSubImage2D commands, ANGLE performs staging uploads into the 64 MiB image space, writing past the boundaries of the 32 MiB physical backing into adjacent GPU driver allocations.
  • OOB Read: By rendering with the texture as a source or using glCopyTexSubImage2D into a readable attachment, an attacker could potentially leak adjacent GPU-heap memory allocations.

Note that the following steps are theoretical/potential as our tooling does not currently have the capability to run code to produce a working proof-of-concept.

Suggested Steps to Trigger the Potential Vulnerability

  1. From a compromised renderer, send an IPC command gpu.mojom.SharedImageInterface::CreateSharedImage with:
    • format = viz.mojom.SingleplanarFormat::RGBA_4444
    • size = {4096, 4096}
    • usage = SHARED_IMAGE_USAGE_GLES2_READ | SHARED_IMAGE_USAGE_GLES2_WRITE
  2. The GPU process selects ExternalVkImageBackingFactory and allocates a native VK_FORMAT_R4G4B4A4_UNORM_PACK16 external-memory image (~32 MiB) and exports its opaque handle (e.g., FD).
  3. Request GL interop by sending a command-buffer IPC calling glCreateAndTexStorage2DSharedImageINTERNAL. The GPU process calls glImportMemoryFdEXT on the ~32 MiB FD followed by glTexStorageMemFlags2DANGLE with GL_RGBA4 and size 4096, 4096.
  4. Inside ANGLE, the GL_RGBA4 is resolved via SampleOnly fallback to R8G8B8A8_UNORM (due to the lack of linear filter support). ANGLE creates a VK_FORMAT_R8G8B8A8_UNORM image (~64 MiB required) and binds it to the imported 32 MiB allocation.
  5. Issue glTexSubImage2D writes or texture sampling read-backs to attempt to corrupt or leak adjacent GPU heap allocations.

Suggested Fix

To prevent this discrepancy and potential OOB memory access, the debug-only assertion in third_party/angle/src/libANGLE/renderer/vulkan/MemoryObjectVk.cpp (line 261) should be converted into a runtime check that returns an error on release builds:

    if (externalMemoryRequirements.size != mSize)
    {
        ANGLE_VK_CHECK(contextVk, false, VK_ERROR_INITIALIZATION_FAILED);
    }

Evaluated with Chrome root at commit: 5133b93d189b383c37805b1cf3a9d2dbfe8d7379


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.

View on issue tracker