Chrome · ANGLE › Vulkan
CVE-2026-113266
Memory Corruption in ANGLE (Vulkan)
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
src/tests/gl_tests/TextureTest.cppsrc/tests/angle_end2end_tests_expectations.txtsrc/libANGLE/renderer/vulkan/TextureVk.cpp
Patch
From 97941c8fa29062701a6d30d6a8b00218099c74a2 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Tue, 15 Sep 2026 14:47:34 -0400
Subject: [PATCH] Vulkan: Don't ghost images if base level has changed
Bug: b/560140367
Bug: chromium:561499641
Change-Id: Ib21dfece7075e00c5193214c06440e2c5f90ce91
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8415126
Reviewed-by: Charlie Lao <cclao@google.com>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
---
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index c6161ad..6c69c7f 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1164,6 +1164,9 @@
}
// Size check: Can only ghost the image if the area being overwritten covers the entire image.
+ // Base level check: If base level has changed, don't attempt to ghost it as
+ // getBaseLevelFormat() and initImage() will be wrong below, but also it's
+ // possible the texture has to be reallocated anyway later.
//
// As a targeted optimization, only limit to non-array 2D color textures. Other texture types
// can be very easily added if need, but need additional tests similar to those that have landed
@@ -1171,6 +1174,12 @@
const gl::OwnerLevel overwriteLevel = index.getLevelIndex();
const gl::OwnerLevel imageLevel = mImage->getFirstAllocatedLevel();
+ const gl::OwnerLevel baseLevel = mState.toOwnerLevel(gl::LevelIndex(mState.getBaseLevel()));
+ if (baseLevel != imageLevel)
+ {
+ return angle::Result::Continue;
+ }
+
const bool is2DImage = mImage->getLevelCount() == 1 && mImage->getLayerCount() == 1 &&
mImage->getType() == VK_IMAGE_TYPE_2D;
const bool is2DUpdate = mState.getType() == gl::TextureType::_2D && index.getLayerCount() == 1;
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 4a96d63..749fb55 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -213,6 +213,7 @@
40096690 WIN INTEL VULKAN : TransformFeedbackWithDepthBufferTest.RecordAndDrawWithDepthWriteEnabled/* = SKIP
534082926 WIN INTEL VULKAN : TransformFeedbackTest.RenderOnceChangeXfbBufferRenderAgain/* = SKIP
534082926 WIN INTEL VULKAN : TransformFeedbackTest.BufferRebinding/* = SKIP
+534082926 WIN INTEL VULKAN : TransformFeedbackTest.MultiplePaused/* = SKIP
40096690 WIN INTEL VULKAN : TextureBufferTestES31.UseAsXFBThenAsTextureBuffer/* = SKIP
// Failures on Intel Comet Lake S UHD Graphics 630 (8086:9bc5-31.0.101.2111)
@@ -1383,6 +1384,7 @@
537235694 PIXEL10 GLES : WebGLGLSLTest.FragDataInCommaIndexClampWithoutDrawBuffers/* = SKIP
546627192 PIXEL10 GLES : GLSLTest_ES3.VaryingAnonymousStructAssignment/* = SKIP
546627192 PIXEL10 GLES : GLSLTest_ES3.VaryingAnonymousStructTernary/* = SKIP
+563032519 PIXEL10 GLES : Texture2DTestES3.SampleThenFullUpdateWithBaseChange/* = SKIP
480069042 PIXEL10 VULKAN : ClearTextureEXTTestES31Unrenderable.Clear/ES3_1_Vulkan*__GL_RG16_SNORM_EXT_GL_RG_GL_SHORT_GL_TEXTURE_2D_ARRAY = SKIP
480069042 PIXEL10 VULKAN : ClearTextureEXTTestES31Unrenderable.Clear/ES3_1_Vulkan*__GL_RGB32UI_GL_RGB_INTEGER_GL_UNSIGNED_INT_GL_TEXTURE_2D_ARRAY = SKIP
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 181c9dc..61d4e8d 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -12363,6 +12363,44 @@
}
}
+// Test completely overwriting a texture with a data upload while the texture is being sampled from
+// by the GPU.
+// Test changes base level just before upload.
+TEST_P(Texture2DTestES3, SampleThenFullUpdateWithBaseChange)
+{
+ constexpr uint32_t kWidth = 16;
+ constexpr uint32_t kHeight = 24;
+
+ ANGLE_GL_PROGRAM(program, getVertexShaderSource(), getExpensiveFragmentShaderSource());
+
+ glViewport(0, 0, kWidth, kHeight);
+
+ GLTexture tex;
+ const std::vector<GLColor> texDataRed(kWidth * kHeight, GLColor::red);
+ const std::vector<GLColor> texDataGreen(kWidth * kHeight, GLColor::green);
+ const std::vector<GLColor> texDataBlue(kWidth * kHeight, GLColor::blue);
+
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataRed.data());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ drawQuad(program, "position", 0.0f);
+ ASSERT_GL_NO_ERROR();
+
+ // Set the base level to something random before the upload; that shouldn't have any effect on
+ // the upload.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 123);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ // Restore base level
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ drawQuad(program, "position", 0.0f);
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
+ ASSERT_GL_NO_ERROR();
+}
+
// Test for ASTC decode mode queries
TEST_P(Texture2DTestES3, ASTCDecodeModeQueries)
{
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 4a96d63..749fb55 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -213,6 +213,7 @@
40096690 WIN INTEL VULKAN : TransformFeedbackWithDepthBufferTest.RecordAndDrawWithDepthWriteEnabled/* = SKIP
534082926 WIN INTEL VULKAN : TransformFeedbackTest.RenderOnceChangeXfbBufferRenderAgain/* = SKIP
534082926 WIN INTEL VULKAN : TransformFeedbackTest.BufferRebinding/* = SKIP
+534082926 WIN INTEL VULKAN : TransformFeedbackTest.MultiplePaused/* = SKIP
40096690 WIN INTEL VULKAN : TextureBufferTestES31.UseAsXFBThenAsTextureBuffer/* = SKIP
// Failures on Intel Comet Lake S UHD Graphics 630 (8086:9bc5-31.0.101.2111)
@@ -1383,6 +1384,7 @@
537235694 PIXEL10 GLES : WebGLGLSLTest.FragDataInCommaIndexClampWithoutDrawBuffers/* = SKIP
546627192 PIXEL10 GLES : GLSLTest_ES3.VaryingAnonymousStructAssignment/* = SKIP
546627192 PIXEL10 GLES : GLSLTest_ES3.VaryingAnonymousStructTernary/* = SKIP
+563032519 PIXEL10 GLES : Texture2DTestES3.SampleThenFullUpdateWithBaseChange/* = SKIP
480069042 PIXEL10 VULKAN : ClearTextureEXTTestES31Unrenderable.Clear/ES3_1_Vulkan*__GL_RG16_SNORM_EXT_GL_RG_GL_SHORT_GL_TEXTURE_2D_ARRAY = SKIP
480069042 PIXEL10 VULKAN : ClearTextureEXTTestES31Unrenderable.Clear/ES3_1_Vulkan*__GL_RGB32UI_GL_RGB_INTEGER_GL_UNSIGNED_INT_GL_TEXTURE_2D_ARRAY = SKIP
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 181c9dc..61d4e8d 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -12363,6 +12363,44 @@
}
}
+// Test completely overwriting a texture with a data upload while the texture is being sampled from
+// by the GPU.
+// Test changes base level just before upload.
+TEST_P(Texture2DTestES3, SampleThenFullUpdateWithBaseChange)
+{
+ constexpr uint32_t kWidth = 16;
+ constexpr uint32_t kHeight = 24;
+
+ ANGLE_GL_PROGRAM(program, getVertexShaderSource(), getExpensiveFragmentShaderSource());
+
+ glViewport(0, 0, kWidth, kHeight);
+
+ GLTexture tex;
+ const std::vector<GLColor> texDataRed(kWidth * kHeight, GLColor::red);
+ const std::vector<GLColor> texDataGreen(kWidth * kHeight, GLColor::green);
+ const std::vector<GLColor> texDataBlue(kWidth * kHeight, GLColor::blue);
+
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataRed.data());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ drawQuad(program, "position", 0.0f);
+ ASSERT_GL_NO_ERROR();
+
+ // Set the base level to something random before the upload; that shouldn't have any effect on
+ // the upload.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 123);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ texDataGreen.data());
+ // Restore base level
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ drawQuad(program, "position", 0.0f);
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
+ ASSERT_GL_NO_ERROR();
+}
+
// Test for ASTC decode mode queries
TEST_P(Texture2DTestES3, ASTCDecodeModeQueries)
{
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page