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 <[email protected]> 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 <[email protected]> Commit-Queue: Shahbaz Youssefi <[email protected]> --- 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