Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in Dawn
DescriptionImproper input validation in Dawn
ComponentDawn
Bug ClassLogic Error
Tracker525683797
Fix commitbaeac58b753d (angle/angle) +26/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Files Changed

  • src/compiler/translator/Types.h
  • src/tests/gl_tests/GLSLValidationTest.cpp
From baeac58b753dbc08bb9e289842e0aa230b7f9c4b Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 13 Jul 2026 16:54:46 -0400
Subject: [PATCH] Translator: Fix type size cache for interface blocks

`TType::operator<` did not differentiate between interface blocks, so a
large UBO after a small UBO hit the cache and used the small UBO's size.

Bug: chromium:525315564
Bug: chromium:525683797
Change-Id: Ic58a260a217d6159e88c0d40840bb3eb232d3689
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8087299
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
---

diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h
index 2dbc6a0..b3e6950 100644
--- a/src/compiler/translator/Types.h
+++ b/src/compiler/translator/Types.h
@@ -308,7 +308,13 @@
                 return mArraySizes[i] < right.mArraySizes[i];
         }
         if (mStructure != right.mStructure)
+        {
             return mStructure < right.mStructure;
+        }
+        if (mInterfaceBlock != right.mInterfaceBlock)
+        {
+            return mInterfaceBlock < right.mInterfaceBlock;
+        }
 
         return false;
     }
diff --git a/src/tests/gl_tests/GLSLValidationTest.cpp b/src/tests/gl_tests/GLSLValidationTest.cpp
index 4b8cf0d..bed9ed9 100644
--- a/src/tests/gl_tests/GLSLValidationTest.cpp
+++ b/src/tests/gl_tests/GLSLValidationTest.cpp
@@ -2979,6 +2979,26 @@
                   "'Block' : Size of declared variable exceeds implementation-defined limit");
 }
 
+// Test that too large array in UBO fails after another UBO within limit is declared.
+TEST_P(WebGL2GLSLValidationTest, LargeArrayUBOAfterSmallUBO)
+{
+    constexpr char kFS[] = R"(#version 300 es
+uniform Small
+{
+    int i;
+};
+uniform Block
+{
+    int rr[~1U];
+};
+out int o;
+void main() {
+    o = rr[1] + i;
+})";
+    validateError(GL_FRAGMENT_SHADER, kFS,
+                  "'Block' : Size of declared variable exceeds implementation-defined limit");
+}
+
 // Regression test for a 32-bit overflow bug when setting initializer for a large constant.
 TEST_P(WebGL2GLSLValidationTest, LargeConstantVariableWithInitializer)
 {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/src/tests/gl_tests/GLSLValidationTest.cpp b/src/tests/gl_tests/GLSLValidationTest.cpp
index 4b8cf0d..bed9ed9 100644
--- a/src/tests/gl_tests/GLSLValidationTest.cpp
+++ b/src/tests/gl_tests/GLSLValidationTest.cpp
@@ -2979,6 +2979,26 @@
                   "'Block' : Size of declared variable exceeds implementation-defined limit");
 }
 
+// Test that too large array in UBO fails after another UBO within limit is declared.
+TEST_P(WebGL2GLSLValidationTest, LargeArrayUBOAfterSmallUBO)
+{
+    constexpr char kFS[] = R"(#version 300 es
+uniform Small
+{
+    int i;
+};
+uniform Block
+{
+    int rr[~1U];
+};
+out int o;
+void main() {
+    o = rr[1] + i;
+})";
+    validateError(GL_FRAGMENT_SHADER, kFS,
+                  "'Block' : Size of declared variable exceeds implementation-defined limit");
+}
+
 // Regression test for a 32-bit overflow bug when setting initializer for a large constant.
 TEST_P(WebGL2GLSLValidationTest, LargeConstantVariableWithInitializer)
 {
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential bypass of ANGLE's checkVariableSize 2 GiB limit on compute shaders on hardened contexts

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: ANGLE’s parser-level guard checkVariableSize enforces a 2 GiB size limit on hardened contexts but early-returns for shader stages other than vertex and fragment. Consequently, WebGPU compute shaders using Dawn’s OpenGLES backend can potentially compile storage buffer blocks (SSBOs) up to 4 GiB. This delivers oversized layouts directly to the native GPU driver’s shader compiler in the unsandboxed GPU process.

Affected files:

  • third_party/angle/src/compiler/translator/ParseContext.cpp

Estimated timestamp from git blame: 2026-01-14

Description

ANGLE’s checkVariableSize is a parser-level security check designed to prevent driver crash bugs triggered by extremely large variables (such as integer overflows in driver shader compilers) by enforcing a 2 GiB limit (kWebGLMaxVariableSizeInBytes) on hardened contexts. However, this check contains an early-return optimization designed for WebGL that ignores shader stages other than vertex and fragment shaders:

// third_party/angle/src/compiler/translator/ParseContext.cpp:1858-1861
if (!mCompileOptions.rejectWebglShadersWithLargeVariables ||
    (mShaderType != GL_VERTEX_SHADER && mShaderType != GL_FRAGMENT_SHADER))
{
    return true;   // GL_COMPUTE_SHADER bypasses the size check here
}

This early-return was written under the assumption that the hardening is only relevant for WebGL shaders. However, Dawn’s OpenGLES backend (specifically on Android devices running in compatibility mode) utilizes ANGLE as its GLES provider and explicitly requests a hardened ANGLE context:

// third_party/dawn/src/dawn/native/opengl/ContextEGL.cpp:199-201
if (egl.HasExt(EGLExt::ANGLECreateContextWebGLCompatibility)) {
    AddAttrib(EGL_CONTEXT_HARDENED_ANGLE, EGL_TRUE);
}

When EGL_CONTEXT_HARDENED_ANGLE is set, ANGLE configures rejectWebglShadersWithLargeVariables = true. Because Dawn supports WebGPU compute shaders (GL_COMPUTE_SHADER), this is now a hardened client that compiles compute-stage interface blocks (SSBOs). Due to the stage filter in checkVariableSize, compute shaders compiling storage buffers bypass the 2 GiB check entirely.

Potential Attack Vector

Our static analysis suggests the following potential path to trigger the issue from web content:

  1. A web page running on an Android device where WebGPU compatibility mode is active (and falling back to the OpenGLES backend) requests a WebGPU adapter and device.
  2. The attacker creates a compute shader module (device.createShaderModule) declaring a large storage buffer of up to 4 GiB (just under Tint’s 0xFFFFFFFF limit):
    @group(0) @binding(0) var<storage, read> x : array<mat4x4f, 67108863>; // ~4 GiB
    @compute @workgroup_size(1) fn main() { _ = x[0]; }
    
  3. Tint accepts the type (since storage buffers are exempt from the kMaxArrayElementCount limit) and generates GLSL ES 3.10 code containing a layout(std430) buffer with the massive array size.
  4. Dawn attempts to compile this shader using the statically linked ANGLE GLES context via glCompileShader.
  5. In ANGLE, the checkVariableSize function returns true early without checking the size of the block because mShaderType is GL_COMPUTE_SHADER.
  6. ANGLE’s GL backend forwards the translated GLSL directly to the native Android GPU vendor’s shader compiler via glCompileShader inside the unsandboxed GPU process, bypassing the safety firewall.

Note: These steps are based on static code analysis; our tooling agent does not currently have the capability to run code or verify this dynamically on a target device.

Proposed Fix

Modify checkVariableSize to evaluate compute shaders on hardened contexts, and ensure that the size calculation properly handles the std430 layout rules typically used by storage buffer blocks (EvqBuffer / BLOCKLAYOUT_STD430).

Evaluated with Chrome root at commit: 75203b87cbf6681eb7c7dda8e1d0bf781538c76a


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