Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in ANGLE
DescriptionInsufficient validation of untrusted input in ANGLE
ComponentANGLE
Bug ClassLogic Error
Tracker500047428
Fix commit847b036be553 (angle/angle) +38/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-05-27

Files Changed

  • extensions/ANGLE_yuv_internal_format.txt
From 847b036be55376e2dcae10e1d10e5b4c993f2adf Mon Sep 17 00:00:00 2001
From: Mohan Maiya <[email protected]>
Date: Wed, 22 Apr 2026 13:19:50 -0500
Subject: [PATCH] Update ANGLE_yuv_internal_format spec

Added clarification to allow sample-only usage of textures

Bug: chromium:500047428
Change-Id: I56a5fdf6b4502abb851e61763f3b709012c31b94
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7784198
Auto-Submit: mohan maiya <[email protected]>
Reviewed-by: Kenneth Russell <[email protected]>
Commit-Queue: Kenneth Russell <[email protected]>
Reviewed-by: Shahbaz Youssefi <[email protected]>
---

diff --git a/extensions/ANGLE_yuv_internal_format.txt b/extensions/ANGLE_yuv_internal_format.txt
index 7ae5363..2c2ba3f 100644
--- a/extensions/ANGLE_yuv_internal_format.txt
+++ b/extensions/ANGLE_yuv_internal_format.txt
@@ -26,7 +26,7 @@
 
 Version
 
-    Version 5, June 23, 2021
+    Version 7, April 23, 2026
 
 Number
 
@@ -36,6 +36,8 @@
 
     OpenGL ES 3.0 is required.
 
+    This extension interacts with GL_EXT_YUV_target, see issue 4
+
 Overview
 
     This extension introduces a few sized internal YUV texture formats
@@ -96,8 +98,43 @@
        for textures with the above YUV formats is assumed to be ITU-R BT.601 with YUV
        values in limited range. Refer to ITU-R BT.601 spec for further details.
 
+    3. Can textures created with these new formats be rendered to via color attachments?
+
+       No, this extension only allows for sampling from such textures. This means attaching
+       textures created using ANGLE_yuv_internal_format as framebuffer color attachments is
+       invalid and the framebuffer completeness check fails with a
+       FRAMEBUFFER_INCOMPLETE_ATTACHMENT error.
+
+       Some additional context - GLES has no native support for YUV formats. Support for
+       usecases that need to sample from YUV formats, like camera and video, is achieved
+       through a multi-step process of creating EGLImages backed by "external memory" and
+       binding them to external texture targets.
+
+       On Android, for example, an app can create an Android Hardware Buffer (AHB) with a
+       YUV format, create an EGLImage out of it using EGL_ANDROID_image_native_buffer,
+       bind the image to an external texture target using GL_OES_EGL_image_external and then
+       sample from that texture. This severely limits validation of YUV features to only
+       those platforms that support all these extensions (or their equivalents).
+
+       The intent behind ANGLE_yuv_internal_format extension is to decouple YUV code paths
+       from EGLImages and "external memory" in ANGLE when using the Vulkan backend
+       (since Vulkan is capable of supporting YUV formats natively).
+
+    4. How does this extension interact with EXT_YUV_target?
+
+       EXT_YUV_target extension provides 2 categories of enhancements - raw YUV sampling
+       from textures and rendering to YUV textures, only the former is relevant to
+       ANGLE_yuv_internal_format. It is valid to sample raw YUV values from a texture
+       created using ANGLE_yuv_internal_format
+
 Revision History
 
+    #7 - (April 23, 2026) Mohan Maiya
+         Clarify interaction with EXT_YUV_target
+
+    #6 - (April 22, 2026) Mohan Maiya
+         Clarification about sample-only usage of textures
+
     #5 - (June 23, 2021) Mohan Maiya
          Renamed format enums from *_ANGLEX to *_ANGLE
 
Loading diff…

Original Bug Report

reported by [email protected]

Validation Bypass and VUID Violation via Native YUV Textures in ANGLE

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 security team.

Overview: A potential vulnerability exists where native YUV textures bypass validation due to a missing isYUV() override in gl::Texture. A compromised renderer can pass an arbitrary YUV format to the passthrough decoder, causing ANGLE to send malformed multi-planar commands to the Vulkan backend. This results in undefined driver behavior and potential GPU process memory corruption.

Affected files:

  • third_party/angle/src/libANGLE/Texture.h
  • third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.h
  • third_party/angle/src/libANGLE/Texture.cpp
  • third_party/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp
  • third_party/angle/src/libANGLE/Image.cpp
  • third_party/angle/src/libANGLE/validationES.cpp
  • third_party/angle/src/libANGLE/Framebuffer.cpp

Estimated timestamp from git blame: 2023-10-17

Description

A potential vulnerability exists in how ANGLE handles native YUV textures (e.g., GL_G8_B8R8_2PLANE_420_UNORM_ANGLE), allowing a compromised renderer to bypass validation and trigger undefined behavior in the GPU process via Vulkan API violations. This relies on three chained flaws in the GPU process:

  1. Passthrough Decoder Validation Bypass: The GLES2DecoderPassthroughImpl blindly forwards the internalformat argument of commands like TexStorage2DEXT directly to ANGLE without validating it against Chrome’s validators_.texture_internal_format_storage. A compromised renderer can manually construct an IPC to submit arbitrary internal formats.
  2. Missing gl::Texture::isYUV() Override: gl::Texture inherits from egl::ImageSibling but does not override the virtual isYUV() method. The default egl::ImageSibling::isYUV() implementation returns false unless the texture is an EGLImage target (mTargetOf). Native YUV textures created via glTexStorage2DEXT have a null mTargetOf, causing isYUV() to incorrectly return false. This causes ANGLE validation functions (e.g., ValidateCopyTexImageParametersBase) to treat the texture as a standard color format and bypass GL_INVALID_OPERATION errors for YUV-restricted operations.
  3. Vulkan Backend Format Misidentification: In the Vulkan backend (e.g., ImageHelper::readPixelsImpl), ANGLE checks if a texture requires YUV-to-RGBA staging by evaluating getExternalFormat() != 0. Because native Vulkan YUV formats have an external format of 0, this check fails, and the safe staging path is skipped.

When these flaws are combined, ANGLE attempts direct operations (e.g., vkCmdCopyImageToBuffer) on the multi-planar YUV image using VK_IMAGE_ASPECT_COLOR_BIT. This violates Vulkan specification requirements (VUID-vkCmdCopyImageToBuffer-srcImage-07971), resulting in undefined behavior and out-of-bounds memory accesses in the underlying graphics driver.

Potential Reproduction Steps

Note: Our tooling agent does not have the ability to run code. These are the suggested steps an attacker would follow.

  1. Obtain arbitrary code execution within a sandboxed renderer process.
  2. Write a raw glRequestExtensionCHROMIUM IPC to the command buffer to enable the GL_ANGLE_yuv_internal_format extension for the context.
  3. Construct a raw TexStorage2DEXT IPC, manually setting the internalformat argument to GL_G8_B8R8_2PLANE_420_UNORM_ANGLE (enum value 0x96B1).
  4. Create a Framebuffer Object (FBO) and bind the native YUV texture to color attachment 0. ANGLE will report the framebuffer as GL_FRAMEBUFFER_COMPLETE.
  5. Trigger a command strictly prohibited for YUV framebuffers, such as glCopyTexImage2D or glReadPixels.
  6. Because validation is bypassed, the invalid operation reaches the Vulkan backend, passing a malformed command to the driver and triggering a potential sandbox escape.

Suggested Fix

  1. Override isYUV() in gl::Texture: Implement gl::Texture::isYUV() to accurately report its state based on its internal format (e.g., checking if the base level description format has the YUV property).
  2. Update Vulkan Backend Checks: Update the backend (e.g., ImageHelper::readPixelsImpl) to rely on the actual format’s YUV property (getActualFormat().isYUV) instead of strictly checking if the external format is non-zero.
  3. Harden Passthrough Decoder: Implement validation in GLES2DecoderPassthroughImpl::DoTexStorage2DEXT and related commands to reject internalformat values that are not explicitly permitted by Chrome’s feature info.

Evaluated with Chrome root at commit: f200f57a19490707ff8bc7aa5de3cbc443a3afad


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