CVE-2026-10979
Overview
Files Changed
src/compiler/translator/Types.cpp
Patch
From 8c8f35f183d9d248c4b4ee84323512f5000c8494 Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi <[email protected]> Date: Wed, 20 May 2026 16:16:56 -0400 Subject: [PATCH] Translator: Don't cap object sizes to INT_MAX The calculations are done in size_t, so the cap is changed to size_t's MAX value instead. Fixes a crash if a _very_ big struct is declared, but used only in a way that's constant folded. The test itself is impossible to put in the CQ due to its long execution time. Bug: chromium:513468021 Change-Id: Ia378f915ed509ce52162153054229cc22a9a91af Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7865643 Commit-Queue: Shahbaz Youssefi <[email protected]> Reviewed-by: Geoff Lang <[email protected]> --- diff --git a/src/compiler/translator/Types.cpp b/src/compiler/translator/Types.cpp index a3564df..42ccdcc 100644 --- a/src/compiler/translator/Types.cpp +++ b/src/compiler/translator/Types.cpp @@ -517,8 +517,10 @@ for (size_t arraySize : mArraySizes) { - if (arraySize > INT_MAX / totalSize) - totalSize = INT_MAX; + if (arraySize > std::numeric_limits<size_t>::max() / totalSize) + { + totalSize = std::numeric_limits<size_t>::max(); + } else totalSize *= arraySize; } @@ -877,8 +879,10 @@ for (const TField *field : *mFields) { size_t fieldSize = field->type()->getObjectSize(); - if (fieldSize > INT_MAX - size) - size = INT_MAX; + if (fieldSize > std::numeric_limits<size_t>::max() - size) + { + size = std::numeric_limits<size_t>::max(); + } else size += fieldSize; }
Original Bug Report
Out-of-Bounds Read in ANGLE Constant Folding due to Size Calculation Inconsistency
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: A potential inconsistency between how structure sizes are clamped and how field offsets are calculated in the ANGLE compiler could lead to an out-of-bounds read. This issue could allow a crafted shader to leak memory from the GPU process heap into the translated shader source.
Affected files:
third_party/angle/src/compiler/translator/IntermNode.cppthird_party/angle/src/compiler/translator/Types.cpp
Estimated timestamp from git blame: 2013-07-30
A potential out-of-bounds (OOB) read vulnerability exists in the ANGLE compiler’s constant folding implementation. The issue stems from a discrepancy between the clamping logic used during structure size calculation and the logic used to compute field offsets during constant folding of structure indexing.
Root Cause Analysis
In third_party/angle/src/compiler/translator/Types.cpp, the method TFieldListCollection::calculateObjectSize() calculates the total size (in elements) of a structure and saturates the result at INT_MAX if it exceeds that limit:
size_t TFieldListCollection::calculateObjectSize() const {
size_t size = 0;
for (const TField *field : *mFields) {
size_t fieldSize = field->type()->getObjectSize();
if (fieldSize > INT_MAX - size)
size = INT_MAX; // Saturated clamp
else
size += fieldSize;
}
return size;
}
This clamped size is used to allocate the buffer for constant folding in TIntermAggregate::getConstantValue(). However, when constant-folding a field access (EOpIndexDirectStruct), the offset into this buffer is calculated in TIntermBinary::getConstantValue() (IntermNode.cpp) by summing the sizes of all preceding fields using size_t arithmetic without the same clamping logic:
// third_party/angle/src/compiler/translator/IntermNode.cpp
size_t previousFieldsSize = 0;
for (int i = 0; i < index; ++i)
previousFieldsSize += fields[i]->type()->getObjectSize(); // Un-clamped summation
constIndexingResult = leftConstantValue + previousFieldsSize; // Potential OOB pointer
On 64-bit systems, previousFieldsSize can exceed INT_MAX, causing constIndexingResult to point beyond the allocated TConstantUnion array. Although ANGLE generally restricts constant folding to types with 16 or fewer components, this inconsistency represents a potential bypass if large objects are incorrectly permitted to fold or if specific internal invariants are violated.
Potential Exploitation Path
An attacker could attempt to trigger this by defining a shader with nested structures that exceed the INT_MAX element limit. By using an inline constructor and accessing a trailing field, the attacker may reach the vulnerable offset calculation. If the indexing operation is folded, the resulting leaked heap memory from the GPU process would be embedded as a literal in the translated shader source, which can be retrieved via the WEBGL_debug_shaders extension or by reading back rendered pixels.
Suggested Fix
Ensure that all offset calculations in the constant folder use the same saturated arithmetic or explicit overflow checks as the size calculation. Specifically, in TIntermBinary::getConstantValue, the summation of previousFieldsSize should be checked against the allocated size of the left-hand side constant buffer.
Note: These are potential steps based on code analysis; our current environment does not support executing a proof of concept.
Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e
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.