CVE-2026-11109
Overview
Files Changed
src/libANGLE/renderer/gl/BlitGL.cppsrc/tests/gl_tests/RobustResourceInitTest.cpp
Patch
From ef5a8a5275da668cf381adc8f87ee17767be4573 Mon Sep 17 00:00:00 2001
From: Geoff Lang <geofflang@chromium.org>
Date: Tue, 14 Apr 2026 16:17:19 -0400
Subject: [PATCH] GL: Disable rasterizer discard for robust resource init
If the frontend had enabled rasterizer discard, the backend robust
resource init clear operations would be discarded. Ensure that
rasterizer discard is disabled.
Bug: chromium:500524833
Change-Id: I7d990ba518c50dc1ccc9683eee51515c46affb4b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7759472
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
---
diff --git a/src/libANGLE/renderer/gl/BlitGL.cpp b/src/libANGLE/renderer/gl/BlitGL.cpp
index 154be25..0fec270 100644
--- a/src/libANGLE/renderer/gl/BlitGL.cpp
+++ b/src/libANGLE/renderer/gl/BlitGL.cpp
@@ -162,6 +162,7 @@
}
stateManager->setScissorTestEnabled(false);
+ stateManager->setRasterizerDiscardEnabled(false);
return angle::Result::Continue;
}
diff --git a/src/tests/gl_tests/RobustResourceInitTest.cpp b/src/tests/gl_tests/RobustResourceInitTest.cpp
index b70fbdf..56ca97b 100644
--- a/src/tests/gl_tests/RobustResourceInitTest.cpp
+++ b/src/tests/gl_tests/RobustResourceInitTest.cpp
@@ -726,6 +726,29 @@
EXPECT_GL_NO_ERROR();
}
+// Test that having rasterizer discard enabled still causes textures to be properly initialized
+TEST_P(RobustResourceInitTestES3, RasterizerDiscardDuringInit)
+{
+ ANGLE_SKIP_TEST_IF(!hasGLExtension());
+
+ GLTexture tex;
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glEnable(GL_RASTERIZER_DISCARD);
+ ANGLE_GL_PROGRAM(blue, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
+ drawQuad(blue, essl1_shaders::PositionAttrib(), 1.0f);
+
+ checkNonZeroPixels(&tex, 0, 0, 0, 0, GLColor::transparentBlack);
+}
+
// Calling invalidate should not lead to uninitialized memory being read.
TEST_P(RobustResourceInitTestES3, InvalidateThenReadBack)
{
Regression Test / PoC
diff --git a/src/tests/gl_tests/RobustResourceInitTest.cpp b/src/tests/gl_tests/RobustResourceInitTest.cpp
index b70fbdf..56ca97b 100644
--- a/src/tests/gl_tests/RobustResourceInitTest.cpp
+++ b/src/tests/gl_tests/RobustResourceInitTest.cpp
@@ -726,6 +726,29 @@
EXPECT_GL_NO_ERROR();
}
+// Test that having rasterizer discard enabled still causes textures to be properly initialized
+TEST_P(RobustResourceInitTestES3, RasterizerDiscardDuringInit)
+{
+ ANGLE_SKIP_TEST_IF(!hasGLExtension());
+
+ GLTexture tex;
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glEnable(GL_RASTERIZER_DISCARD);
+ ANGLE_GL_PROGRAM(blue, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
+ drawQuad(blue, essl1_shaders::PositionAttrib(), 1.0f);
+
+ checkNonZeroPixels(&tex, 0, 0, 0, 0, GLColor::transparentBlack);
+}
+
// Calling invalidate should not lead to uninitialized memory being read.
TEST_P(RobustResourceInitTestES3, InvalidateThenReadBack)
{
Original Bug Report
Robust resource initialization bypass in ANGLE-GL via RASTERIZER_DISCARD
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 in ANGLE’s native OpenGL backend allows robust resource initialization to be bypassed when GL_RASTERIZER_DISCARD is enabled. This results in the driver ignoring glClear commands while the front-end marks the buffer as initialized, potentially leading to the disclosure of uninitialized GPU memory.
Affected files:
third_party/angle/src/libANGLE/renderer/gl/BlitGL.cppthird_party/angle/src/libANGLE/renderer/gl/FramebufferGL.cppthird_party/angle/src/libANGLE/renderer/gl/RenderbufferGL.cppthird_party/angle/src/libANGLE/renderer/gl/StateManagerGL.cppthird_party/angle/src/libANGLE/Framebuffer.cppthird_party/angle/src/libANGLE/Context.cpp
Estimated timestamp from git blame: 2018-12-06
Summary
The ANGLE native OpenGL backend fails to disable GL_RASTERIZER_DISCARD before performing robust resource initialization clears. This leads to a situation where the driver ignores the clear command (per the OpenGL specification), but ANGLE’s state tracking incorrectly marks the resource as initialized. This bypasses the security guarantee that all allocated GPU memory is zero-initialized before use, leading to a potential cross-origin information leak of recycled GPU VRAM.
Details
In ANGLE, robust resource initialization ensures that newly allocated textures, renderbuffers, and framebuffers are cleared to zero before they are accessed by a WebGL context. On the native GL backend, this is handled by BlitGL.cpp through functions like clearFramebuffer.
These functions rely on SetClearState (third_party/angle/src/libANGLE/renderer/gl/BlitGL.cpp:139-167) to configure the OpenGL state for the clear operation. However, SetClearState fails to explicitly disable GL_RASTERIZER_DISCARD.
Crucially, during Context::prepareForDraw (third_party/angle/src/libANGLE/Context.inl.h), syncDirtyObjects (which triggers robust resource initialization) is called before syncDirtyBits (which pushes context state to the native driver). This means if a user previously enabled rasterizer discard and latched it to the driver, that state remains active in the native driver when ensureDrawAttachmentsInitialized triggers a clear via BlitGL.
Per the OpenGL specification, when GL_RASTERIZER_DISCARD is enabled, glClear and glClearBuffer* commands are silently ignored by the driver.
As a result, the robust initialization clear is skipped by the driver, but ANGLE incorrectly marks the resource as initialized. An attacker can then disable rasterizer discard and read the uninitialized GPU memory.
Potential Reproduction Steps
Note: These steps describe the theoretical path an attacker would take to trigger this issue. A working PoC has not been executed in this environment.
- Initialize a WebGL2 context using the ANGLE native-GL backend.
- Enable rasterizer discard:
gl.enable(gl.RASTERIZER_DISCARD). - Perform a dummy draw call to push the
GL_RASTERIZER_DISCARDstate to the native driver. - Create a new FBO with a fresh, uninitialized color renderbuffer and bind it.
- Perform a draw call (e.g.,
gl.drawArrays(gl.TRIANGLES, 0, 3)).- ANGLE’s
prepareForDrawcallssyncDirtyObjects, which attempts robust initialization viaBlitGL::clearFramebuffer. - Because
GL_RASTERIZER_DISCARDis still active natively, the driver ignores theglClearcommand. - ANGLE incorrectly marks the FBO attachments as
InitState::Initialized.
- ANGLE’s
- Disable rasterizer discard:
gl.disable(gl.RASTERIZER_DISCARD). - Call
gl.readPixelson the FBO. Because it is marked as initialized, ANGLE allows the read, returning uninitialized, recycled GPU memory.
Suggested Fix
Modify SetClearState in third_party/angle/src/libANGLE/renderer/gl/BlitGL.cpp to explicitly disable GL_RASTERIZER_DISCARD before any clearing operations are performed:
angle::Result SetClearState(StateManagerGL *stateManager,
bool colorClear,
bool depthClear,
bool stencilClear,
GLbitfield *outClearMask)
{
// ... existing code ...
stateManager->setScissorTestEnabled(false);
stateManager->setRasterizerDiscardEnabled(false); // Add this line
return angle::Result::Continue;
}
Evaluated with Chrome root at commit: 137d451a126685dd5010e6609db9f6d4a78d8234
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.