Skip to content

Commit 55888db

Browse files
Reject oversized exrmetrics vector allocations on ILP32 (#2539)
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 <cary@ilm.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 04c52e7 commit 55888db

1 file changed

Lines changed: 26 additions & 6 deletions

File tree

src/bin/exrmetrics/exrmetrics.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <chrono>
2727
#include <ctime>
28+
#include <limits>
2829
#include <list>
2930
#include <stdexcept>
3031
#include <vector>
@@ -46,6 +47,25 @@ using std::vector;
4647
using std::chrono::steady_clock;
4748
using std::isinf;
4849

50+
namespace {
51+
52+
//
53+
// Validate that count*sampleSize casts to size_t without overflow, before
54+
// using the value to resize a std::vector.
55+
//
56+
57+
size_t
58+
vectorSize (uint64_t count, int sampleSize = 1)
59+
{
60+
const uint64_t sampleSizeU = static_cast<uint64_t> (sampleSize);
61+
const uint64_t maxSize = std::numeric_limits<size_t>::max ();
62+
if (sampleSizeU > 0 && count > maxSize / sampleSizeU)
63+
throw IEX_NAMESPACE::OverflowExc ("Integer multiplication overflow.");
64+
return static_cast<size_t> (count * sampleSizeU);
65+
}
66+
67+
} // namespace
68+
4969
double
5070
timing (steady_clock::time_point start, steady_clock::time_point end)
5171
{
@@ -92,7 +112,7 @@ initScanLine (
92112
size_t pixelsInChannel = (width / i.channel ().xSampling) *
93113
(height / i.channel ().ySampling);
94114
rawSize += pixelsInChannel * samplesize;
95-
pixelData[channelNumber].resize (numPixels * samplesize);
115+
pixelData[channelNumber].resize (vectorSize (numPixels, samplesize));
96116

97117
buf.insert (
98118
i.name (),
@@ -205,7 +225,7 @@ initTiled (
205225
{
206226
int samplesize = pixelTypeSize (i.channel ().type);
207227
pixelData[levelIndex][channelNumber].resize (
208-
numPixels * samplesize);
228+
vectorSize (numPixels, samplesize));
209229

210230
buf[levelIndex].insert (
211231
i.name (),
@@ -324,7 +344,7 @@ initAndReadDeepScanLine (
324344
uint64_t height = dw.max.y + 1 - dw.min.y;
325345
uint64_t numPixels = width * height;
326346
int numChans = channelCount (in.header ());
327-
sampleCount.resize (numPixels);
347+
sampleCount.resize (vectorSize (numPixels));
328348

329349
uint64_t offsetToOrigin = width * static_cast<uint64_t> (dw.min.y) +
330350
static_cast<uint64_t> (dw.min.x);
@@ -342,7 +362,7 @@ initAndReadDeepScanLine (
342362
i != outHeader.channels ().end ();
343363
++i)
344364
{
345-
pixelPtrs[channelNumber].resize (numPixels);
365+
pixelPtrs[channelNumber].resize (vectorSize (numPixels));
346366
int samplesize = pixelTypeSize (i.channel ().type);
347367
buf.insert (
348368
i.name (),
@@ -492,7 +512,7 @@ initAndReadDeepTiled (
492512
static_cast<uint64_t> (dw.min.x);
493513

494514
pixelPtrs.resize (numChans);
495-
sampleCount.resize (numPixels);
515+
sampleCount.resize (vectorSize (numPixels));
496516

497517
buf.insertSampleCountSlice (Slice (
498518
UINT,
@@ -506,7 +526,7 @@ initAndReadDeepTiled (
506526
i != outHeader.channels ().end ();
507527
++i)
508528
{
509-
pixelPtrs[channelNumber].resize (numPixels);
529+
pixelPtrs[channelNumber].resize (vectorSize (numPixels));
510530
int samplesize = pixelTypeSize (i.channel ().type);
511531
buf.insert (
512532
i.name (),

0 commit comments

Comments
 (0)