From 0d7d9594f5b58bac33bdd8cdf16b8ee93c181aba Mon Sep 17 00:00:00 2001 From: Cary Phillips Date: Fri, 10 Jul 2026 18:43:44 -0700 Subject: [PATCH] Reject oversized exrmetrics vector allocations on ILP32 exrmetrics computed image buffer sizes as uint64_t but passed them to std::vector::resize(size_type), which silently truncates on 32-bit builds and left decode writing past undersized channel and sample-count buffers. Validate count and size to confirm the cast to size_t does not overflow. Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-r8mj-rhfc-38g4 Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-pgc2-hppj-q623 Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-g5m8-8w79-34q8 Addresses https://github.com/AcademySoftwareFoundation/openexr/security/advisories/GHSA-xc77-xm9h-qxm4 Signed-off-by: Cary Phillips Co-authored-by: Cursor --- src/bin/exrmetrics/exrmetrics.cpp | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/bin/exrmetrics/exrmetrics.cpp b/src/bin/exrmetrics/exrmetrics.cpp index 46c19a7ba..776ae22f4 100644 --- a/src/bin/exrmetrics/exrmetrics.cpp +++ b/src/bin/exrmetrics/exrmetrics.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -46,6 +47,25 @@ using std::vector; using std::chrono::steady_clock; using std::isinf; +namespace { + +// +// Validate that count*sampleSize casts to size_t without overflow, before +// using the value to resize a std::vector. +// + +size_t +vectorSize (uint64_t count, int sampleSize = 1) +{ + const uint64_t sampleSizeU = static_cast (sampleSize); + const uint64_t maxSize = std::numeric_limits::max (); + if (sampleSizeU > 0 && count > maxSize / sampleSizeU) + throw IEX_NAMESPACE::OverflowExc ("Integer multiplication overflow."); + return static_cast (count * sampleSizeU); +} + +} // namespace + double timing (steady_clock::time_point start, steady_clock::time_point end) { @@ -92,7 +112,7 @@ initScanLine ( size_t pixelsInChannel = (width / i.channel ().xSampling) * (height / i.channel ().ySampling); rawSize += pixelsInChannel * samplesize; - pixelData[channelNumber].resize (numPixels * samplesize); + pixelData[channelNumber].resize (vectorSize (numPixels, samplesize)); buf.insert ( i.name (), @@ -205,7 +225,7 @@ initTiled ( { int samplesize = pixelTypeSize (i.channel ().type); pixelData[levelIndex][channelNumber].resize ( - numPixels * samplesize); + vectorSize (numPixels, samplesize)); buf[levelIndex].insert ( i.name (), @@ -324,7 +344,7 @@ initAndReadDeepScanLine ( uint64_t height = dw.max.y + 1 - dw.min.y; uint64_t numPixels = width * height; int numChans = channelCount (in.header ()); - sampleCount.resize (numPixels); + sampleCount.resize (vectorSize (numPixels)); uint64_t offsetToOrigin = width * static_cast (dw.min.y) + static_cast (dw.min.x); @@ -342,7 +362,7 @@ initAndReadDeepScanLine ( i != outHeader.channels ().end (); ++i) { - pixelPtrs[channelNumber].resize (numPixels); + pixelPtrs[channelNumber].resize (vectorSize (numPixels)); int samplesize = pixelTypeSize (i.channel ().type); buf.insert ( i.name (), @@ -492,7 +512,7 @@ initAndReadDeepTiled ( static_cast (dw.min.x); pixelPtrs.resize (numChans); - sampleCount.resize (numPixels); + sampleCount.resize (vectorSize (numPixels)); buf.insertSampleCountSlice (Slice ( UINT, @@ -506,7 +526,7 @@ initAndReadDeepTiled ( i != outHeader.channels ().end (); ++i) { - pixelPtrs[channelNumber].resize (numPixels); + pixelPtrs[channelNumber].resize (vectorSize (numPixels)); int samplesize = pixelTypeSize (i.channel ().type); buf.insert ( i.name (),