diff --git a/src/common/utilities.cpp b/src/common/utilities.cpp index d1dc4c68fb1..2d6ee682fb5 100644 --- a/src/common/utilities.cpp +++ b/src/common/utilities.cpp @@ -16,6 +16,7 @@ #include "common/platform.h" #include "common/string_utils.h" +#include #include #if defined(ANGLE_ENABLE_WINDOWS_UWP) @@ -976,9 +977,15 @@ bool SamplerNameContainsNonZeroArrayElement(const std::string &name) unsigned int ArraySizeProduct(const std::vector &arraySizes) { + // Saturate on overflow; a wrapped (small) product defeats downstream size/limit checks. unsigned int arraySizeProduct = 1u; for (unsigned int arraySize : arraySizes) { + if (arraySize != 0u && + arraySizeProduct > std::numeric_limits::max() / arraySize) + { + return std::numeric_limits::max(); + } arraySizeProduct *= arraySize; } return arraySizeProduct; @@ -986,10 +993,17 @@ unsigned int ArraySizeProduct(const std::vector &arraySizes) unsigned int InnerArraySizeProduct(const std::vector &arraySizes) { + // Saturate on overflow; a wrapped (small) product defeats downstream size/limit checks. unsigned int arraySizeProduct = 1u; for (size_t index = 0; index + 1 < arraySizes.size(); ++index) { - arraySizeProduct *= arraySizes[index]; + const unsigned int arraySize = arraySizes[index]; + if (arraySize != 0u && + arraySizeProduct > std::numeric_limits::max() / arraySize) + { + return std::numeric_limits::max(); + } + arraySizeProduct *= arraySize; } return arraySizeProduct; } diff --git a/src/compiler/translator/Types.cpp b/src/compiler/translator/Types.cpp index 42ccdcc6861..81e0205e483 100644 --- a/src/compiler/translator/Types.cpp +++ b/src/compiler/translator/Types.cpp @@ -559,10 +559,20 @@ int TType::getLocationCount() const unsigned int TType::getArraySizeProduct() const { + // Saturate on overflow instead of silently wrapping. A wrapped (small) product would + // defeat downstream size/limit checks that treat this value as the element count of the + // type (e.g. CalculateVariableSize() feeding TParseContext::checkVariableSize(), and the + // packing limit in VariablePacker), leading to under-sized allocations / out-of-bounds + // access for attacker-controlled array dimensions such as float x[65536][65536]. + // Mirrors the saturating behavior already used by getObjectSize()/getLocationCount(). unsigned int product = 1u; for (unsigned int arraySize : mArraySizes) { + if (arraySize != 0u && product > std::numeric_limits::max() / arraySize) + { + return std::numeric_limits::max(); + } product *= arraySize; } return product;