CVE-2026-5879
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
BufferDataTest1gbLimitsrc/tests/gl_tests/BufferDataTest.cpp |
modified |
Files Changed
include/platform/autogen/FeaturesGL_autogen.hinclude/platform/gl_features.jsonsrc/libANGLE/Caps.hsrc/libANGLE/ErrorStrings.hsrc/libANGLE/renderer/gl/renderergl_utils.cppsrc/libANGLE/validationES2.cppsrc/libANGLE/validationES3.cppsrc/libANGLE/validationESEXT.cppsrc/tests/gl_tests/BufferDataTest.cpp
Patch
From 42ae4b5eee733709f37b9f7a50d227a6bc90af70 Mon Sep 17 00:00:00 2001
From: Geoff Lang <geofflang@chromium.org>
Date: Wed, 18 Feb 2026 12:09:39 -0500
Subject: [PATCH] GL: Limit buffer size to 1gb on Intel Macs.
These drivers cannot handle allocations this large so add a limitation
which generates GL_INVALID_OPERATION.
Bug: chromium:40073848
Change-Id: Ibeffb7507e72e4fb5e2a23ed9b873c726c351361
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7589937
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Auto-Submit: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
---
diff --git a/include/platform/autogen/FeaturesGL_autogen.h b/include/platform/autogen/FeaturesGL_autogen.h
index c0c00f1..f1aa71d 100644
--- a/include/platform/autogen/FeaturesGL_autogen.h
+++ b/include/platform/autogen/FeaturesGL_autogen.h
@@ -668,6 +668,12 @@
&members,
};
+ FeatureInfo limitMaxBufferSizeTo1gb = {
+ "limitMaxBufferSizeTo1gb",
+ FeatureCategory::OpenGLWorkarounds,
+ &members,
+ };
+
};
inline FeaturesGL::FeaturesGL() = default;
diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json
index a78b0d4..6d3c820 100644
--- a/include/platform/gl_features.json
+++ b/include/platform/gl_features.json
@@ -868,6 +868,14 @@
"Validate GL_MAX_*_UNIFORM_BLOCKS at compile time instead of link time to work around compiler bugs."
],
"issue": "http://crbug.com/475877320"
+ },
+ {
+ "name": "limit_max_buffer_size_to_1gb",
+ "category": "Workarounds",
+ "description": [
+ "Some drivers have internal failures when attempting to allocate and initialize buffers larger than 1gb."
+ ],
+ "issue": "http://crbug.com/475877320"
}
]
}
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index af19f52..9f05536 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -172,6 +172,10 @@
// GL_ANGLE_base_vertex_base_instance is emulated and should only be exposed to WebGL. Emulated
// by default in shared renderer code.
bool baseInstanceBaseVertexEmulated = true;
+
+ // Size limit for buffers. GL_INVALID_OPERATION should be generated if trying to allocate a
+ // buffer larger than this limit.
+ GLsizeiptr bufferSizeLimit = std::numeric_limits<GLsizeiptr>::max();
};
struct TypePrecision
diff --git a/src/libANGLE/ErrorStrings.h b/src/libANGLE/ErrorStrings.h
index 22a8ed0..16755fc 100644
--- a/src/libANGLE/ErrorStrings.h
+++ b/src/libANGLE/ErrorStrings.h
@@ -68,6 +68,7 @@
inline constexpr const char *kBufferNotMapped = "Buffer is not mapped.";
inline constexpr const char *kBufferNotUpdatable = "Buffer is not updatable.";
inline constexpr const char *kBufferOffsetOverflow = "Buffer offset overflow.";
+inline constexpr const char *kBufferSizeLimitation = "Buffer size is too large (artificial limitation).";
inline constexpr const char *kBufferTextureNotAllowed = "Buffer textures are not allowed.";
inline constexpr const char *kCannotPopDefaultDebugGroup = "Cannot pop the default debug group.";
inline constexpr const char *kClientBufferInvalid = "Size must not exceed the size of clientbuffer.";
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 29abdf4..06dc8b3 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -2221,6 +2221,11 @@
// Restore previous state
functions->blendColor(oldColor[0], oldColor[1], oldColor[2], oldColor[3]);
}
+
+ if (features.limitMaxBufferSizeTo1gb.enabled)
+ {
+ limitations->bufferSizeLimit = 1 << 30;
+ }
}
bool GetSystemInfoVendorIDAndDeviceID(const FunctionsGL *functions,
@@ -2755,6 +2760,9 @@
// IMG GL drivers crash while compiling shaders with more than the limit of uniform blocks.
ANGLE_FEATURE_CONDITION(features, validateMaxPerStageUniformBlocksAtCompileTime,
IsPowerVR(vendor));
+
+ // Mac Intel drivers are unable to allocate buffers larger than ~1gb
+ ANGLE_FEATURE_CONDITION(features, limitMaxBufferSizeTo1gb, isApple && isIntel);
}
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index adaa73e..2b6a85e 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -3636,6 +3636,13 @@
return false;
}
+ const Limitations &limitations = context->getLimitations();
+ if (size > limitations.bufferSizeLimit)
+ {
+ ANGLE_VALIDATION_ERROR(GL_INVALID_OPERATION, kBufferSizeLimitation);
+ return false;
+ }
+
switch (usage)
{
case BufferUsage::StreamDraw:
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index 173841a..170eeb2 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -3303,6 +3303,13 @@
return false;
}
+ const Limitations &limitations = context->getLimitations();
+ if (size > limitations.bufferSizeLimit)
+ {
+ ANGLE_VALIDATION_ERROR(GL_INVALID_OPERATION, kBufferSizeLimitation);
+ return false;
+ }
+
if (checkedReadSum.ValueOrDie() > readBuffer->getSize() ||
checkedWriteSum.ValueOrDie() > writeBuffer->getSize())
{
diff --git a/src/libANGLE/validationESEXT.cpp b/src/libANGLE/validationESEXT.cpp
index b9849fd..5e7055e 100644
--- a/src/libANGLE/validationESEXT.cpp
+++ b/src/libANGLE/validationESEXT.cpp
@@ -2681,6 +2681,13 @@
return false;
}
+ const Limitations &limitations = context->getLimitations();
+ if (size > limitations.bufferSizeLimit)
+ {
+ ANGLE_VALIDATION_ERROR(GL_INVALID_OPERATION, kBufferSizeLimitation);
+ return false;
+ }
+
constexpr GLbitfield kAllUsageFlags =
(GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_READ_BIT | GL_MAP_WRITE_BIT |
GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT | GL_CLIENT_STORAGE_BIT_EXT);
@@ -2800,6 +2807,13 @@
return false;
}
+ const Limitations &limitations = context->getLimitations();
+ if (size > limitations.bufferSizeLimit)
+ {
+ ANGLE_VALIDATION_ERROR(GL_INVALID_VALUE, kBufferSizeLimitation);
+ return false;
+ }
+
return true;
}
diff --git a/src/tests/gl_tests/BufferDataTest.cpp b/src/tests/gl_tests/BufferDataTest.cpp
index f9960a4..97a8fba 100644
--- a/src/tests/gl_tests/BufferDataTest.cpp
+++ b/src/tests/gl_tests/BufferDataTest.cpp
@@ -2413,6 +2413,33 @@
glBindBuffer(GL_COPY_READ_BUFFER, 0);
}
+class BufferDataTest1gbLimit : public BufferDataTest
+{};
+
+// Allocating >1gb should generate an INVALID_OPERATION when LimitMaxBufferSizeTo1gb is enabled.
+TEST_P(BufferDataTest1gbLimit, ErrorGeneratedOnLargeAllocation)
+{
+ GLBuffer buffer;
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ EXPECT_GL_NO_ERROR();
+
+ // First make sure a small allocation works
+ glBufferData(GL_ARRAY_BUFFER, (1 << 10) + 1, nullptr, GL_STATIC_DRAW);
+ EXPECT_GL_NO_ERROR();
+
+ // >1gb should fail.
+ glBufferData(GL_ARRAY_BUFFER, (1 << 30) + 1, nullptr, GL_STATIC_DRAW);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+
+ // glCopyBufferSubData can't be tested because a source buffer > 1gb cannot be created.
Regression Test / PoC
diff --git a/src/tests/gl_tests/BufferDataTest.cpp b/src/tests/gl_tests/BufferDataTest.cpp
index f9960a4..97a8fba 100644
--- a/src/tests/gl_tests/BufferDataTest.cpp
+++ b/src/tests/gl_tests/BufferDataTest.cpp
@@ -2413,6 +2413,33 @@
glBindBuffer(GL_COPY_READ_BUFFER, 0);
}
+class BufferDataTest1gbLimit : public BufferDataTest
+{};
+
+// Allocating >1gb should generate an INVALID_OPERATION when LimitMaxBufferSizeTo1gb is enabled.
+TEST_P(BufferDataTest1gbLimit, ErrorGeneratedOnLargeAllocation)
+{
+ GLBuffer buffer;
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ EXPECT_GL_NO_ERROR();
+
+ // First make sure a small allocation works
+ glBufferData(GL_ARRAY_BUFFER, (1 << 10) + 1, nullptr, GL_STATIC_DRAW);
+ EXPECT_GL_NO_ERROR();
+
+ // >1gb should fail.
+ glBufferData(GL_ARRAY_BUFFER, (1 << 30) + 1, nullptr, GL_STATIC_DRAW);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+
+ // glCopyBufferSubData can't be tested because a source buffer > 1gb cannot be created.
+
+ if (EnsureGLExtensionEnabled("GL_EXT_buffer_storage"))
+ {
+ glBufferStorageEXT(GL_ARRAY_BUFFER, (1 << 30) + 1, nullptr, 0);
+ EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+ }
+}
+
ANGLE_INSTANTIATE_TEST_ES2(BufferDataTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferSubDataTest);
@@ -2437,6 +2464,10 @@
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferStorageTestES3Threaded);
ANGLE_INSTANTIATE_TEST_ES3(BufferStorageTestES3Threaded);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BufferDataTest1gbLimit);
+ANGLE_INSTANTIATE_TEST(BufferDataTest1gbLimit,
+ ES2_OPENGL().enable(Feature::LimitMaxBufferSizeTo1gb),
+ ES3_OPENGL().enable(Feature::LimitMaxBufferSizeTo1gb));
#ifdef _WIN64
// Test a bug where an integer overflow bug could trigger a crash in D3D.
Original Bug Report
ArrayBuffer OOR/W in glBufferData_Exec
Steps to reproduce the problem:
Insufficient input validation for large size ArrayBuffer results in an Out of Bound (R/W) vulnerability in the glBufferData_Exec function of the GL driver.
Problem Description:
ROOT CAUSE ANALYSIS
* Due to various characteristics, it will not be possible to reproduce in ClusterFuzzer.
* Because it occurs within the GL Driver, accurate root cause analysis is impossible.
* Since this vulnerability is reproduced when a page is loaded more than three times, it may be related to GPU task scheduling.
angle::Result Buffer::bufferDataImpl(Context \*context,
BufferBinding target,
const void \*data,
GLsizeiptr size,
BufferUsage usage,
GLbitfield flags)
{
...
if (context && context->isRobustResourceInitEnabled() && !data && size > 0)
{
angle::MemoryBuffer \*scratchBuffer = nullptr;
ANGLE_CHECK_GL_ALLOC(
context, context->getZeroFilledBuffer(static_cast<size_t>(size), &scratchBuffer));
dataForImpl = scratchBuffer->data();
}
...
}
If the size of the ArrayBuffer is close to the maximum value of the GLsizeiptr(signed long int), an integer overflow occurs.
bool ScratchBuffer::getImpl(size_t requestedSize,
MemoryBuffer \*\*memoryBufferOut,
Optional<uint8_t> initValue)
{
...
if (mScratchMemory.size() < requestedSize)
{
if (!mScratchMemory.resize(requestedSize))
{
return false;
}
mResetCounter = mLifetime;
if (initValue.valid())
{
mScratchMemory.fill(initValue.value());
}
}
...
}
The buffer is allocated by the size converted from the size in which the integer overflow has occurred to size_t.
angle::Result BufferGL::setData(const gl::Context \*context,
gl::BufferBinding target,
const void \*data,
size_t size,
gl::BufferUsage usage)
{
...
ANGLE_GL_TRY(context, functions->bufferData(gl::ToGLenum(DestBufferOperationTarget), size, data,
ToGLenum(usage)));
...
}
When handling with data in bufferData functions of GL driver, the actual size of data and size parameters are different, resulting in out of bound r/w memory corruptions.
RECOMMENDED PATCHES
--- a/third_party/angle/src/libANGLE/Buffer.cpp
+++ b/third_party/angle/src/libANGLE/Buffer.cpp
@@ -140,7 +140,7 @@
dataForImpl = scratchBuffer->data();
}
- if (mImpl->setDataWithUsageFlags(context, target, nullptr, dataForImpl, size, usage, flags) ==
+ if (mImpl->setDataWithUsageFlags(context, target, nullptr, dataForImpl, static_cast<size_t>(size), usage, flags) ==
angle::Result::Stop)
{
// If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
When calling the setData function, if the size parameter is also converted to size_t, memory corruptions caused by different sizes from the data can be prevented.
VERSION
* Chrome Version: 116.0.5845.0 (Developer Build) (x86_64)
/ 118.0.5970.0 (Developer Build) (x86_64)
* Operating System: macOS Monterey Version 12.6.8 (21G725)
* Hardware: Intel Core i5, 8GB RAM
* GPU: Intel Iris Graphics 540 1536 MB
(**I have attached the contents of the chrome://gpu page.**)
REPRODUCE CASE
You can simply reproduce by opening the attached poc.html in Chromium.
./Chromium --no-sandbox poc.html
CREDIT
parkminchan, working for SSD Labs Korea.
Additional Comments:
**Chrome version: ** 117.0.0.0 **Channel: ** Stable
OS: Mac OS