Skip to content

Commit e464a33

Browse files
authored
fix integer overflow in PIZ wavelet buffer arithmetic (#2328)
Three classes of signed integer overflow in the PIZ codec path, all reachable from corrupt `dataWindow` dimensions in the EXR file header. **`wav_2D_encode` / `wav_2D_decode` — wavelet loop pointer arithmetic** `oy` is passed as `int` (value `wcount * nx`, at most ~INT32_MAX after the guard below). Inside the hierarchical wavelet loop the expressions ey = in + oy * (ny - p2) // pointer end-of-row sentinel oy1 = oy * p // row stride at level p oy2 = oy * p2 // row stride at level p2 multiply two values that can each approach INT32_MAX, producing a signed 32-bit product that wraps to a small or negative value. The wrapped value is used as a pointer offset, causing reads and writes through `px` / `py` to land outside the allocated wavelet buffer. Fix: widen by introducing `int64_t oy64 = oy` and using it for all three expressions; `oy1` and `oy2` are also declared `int64_t`. **`wavbuf += nx * ny * wcount` — per-channel buffer advance** `nx`, `ny`, and `wcount` are all `int`. Their triple product overflows int32 for moderately large images, causing subsequent channels to be processed at an incorrect (too-small) offset into the wavelet buffer, corrupting both encode and decode output. Fix: cast to `(uint64_t)` before multiplying. **`wcount * nx` — call-site argument overflow** The fifth argument to `wav_2D_encode` / `wav_2D_decode` is `wcount * nx` (`oy` = y-stride = elements per row). `wcount` is 1 or 2 (`bytes_per_element / 2`); for `wcount = 2` the product overflows int32 when `nx > INT32_MAX / 2`. Fix: add an early bounds check `if (wcount > 0 && nx > INT_MAX / wcount)` that rejects such input as `EXR_ERR_CORRUPT_CHUNK` before any arithmetic is performed. This also keeps `wcount * nx` within int32 range at the call site, ensuring `oy` arrives in the wavelet functions with a valid non-overflowed value. Made-with: Cursor Signed-off-by: Cary Phillips <cary@ilm.com>
1 parent f5beec2 commit e464a33

1 file changed

Lines changed: 23 additions & 16 deletions

File tree

src/lib/OpenEXRCore/internal_piz.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "internal_huf.h"
1111
#include "internal_xdr.h"
1212

13+
#include <limits.h>
1314
#include <string.h>
1415

1516
/**************************************/
@@ -232,10 +233,11 @@ wdec16 (uint16_t l, uint16_t h, uint16_t* a, uint16_t* b)
232233
static void
233234
wav_2D_encode (uint16_t* in, int nx, int ox, int ny, int oy, uint16_t mx)
234235
{
235-
int w14 = (mx < (1 << 14)) ? 1 : 0;
236-
int n = (nx > ny) ? ny : nx;
237-
int p = 1; // == 1 << level
238-
int p2 = 2; // == 1 << (level+1)
236+
int w14 = (mx < (1 << 14)) ? 1 : 0;
237+
int n = (nx > ny) ? ny : nx;
238+
int p = 1; // == 1 << level
239+
int p2 = 2; // == 1 << (level+1)
240+
int64_t oy64 = oy;
239241

240242
//
241243
// Hierarchical loop on smaller dimension n
@@ -244,9 +246,9 @@ wav_2D_encode (uint16_t* in, int nx, int ox, int ny, int oy, uint16_t mx)
244246
while (p2 <= n)
245247
{
246248
uint16_t* py = in;
247-
uint16_t* ey = in + oy * (ny - p2);
248-
int oy1 = oy * p;
249-
int oy2 = oy * p2;
249+
uint16_t* ey = in + oy64 * (ny - p2);
250+
int64_t oy1 = oy64 * p;
251+
int64_t oy2 = oy64 * p2;
250252
int ox1 = ox * p;
251253
int ox2 = ox * p2;
252254
uint16_t i00, i01, i10, i11;
@@ -345,10 +347,11 @@ wav_2D_decode (
345347
int oy, // i : y offset
346348
uint16_t mx) // i : maximum in[x][y] value
347349
{
348-
int w14 = (mx < (1 << 14)) ? 1 : 0;
349-
int n = (nx > ny) ? ny : nx;
350-
int p = 1;
351-
int p2;
350+
int w14 = (mx < (1 << 14)) ? 1 : 0;
351+
int n = (nx > ny) ? ny : nx;
352+
int p = 1;
353+
int p2;
354+
int64_t oy64 = oy;
352355

353356
//
354357
// Search max level
@@ -368,9 +371,9 @@ wav_2D_decode (
368371
while (p >= 1)
369372
{
370373
uint16_t* py = in;
371-
uint16_t* ey = in + oy * (ny - p2);
372-
int oy1 = oy * p;
373-
int oy2 = oy * p2;
374+
uint16_t* ey = in + oy64 * (ny - p2);
375+
int64_t oy1 = oy64 * p;
376+
int64_t oy2 = oy64 * p2;
374377
int ox1 = ox * p;
375378
int ox2 = ox * p2;
376379
uint16_t i00, i01, i10, i11;
@@ -566,11 +569,13 @@ internal_exr_apply_piz (exr_encode_pipeline_t* encode)
566569
nx = curc->width;
567570
ny = curc->height;
568571
wcount = (int) (curc->bytes_per_element / 2);
572+
if (wcount > 0 && nx > INT_MAX / wcount)
573+
return EXR_ERR_CORRUPT_CHUNK;
569574
for (int j = 0; j < wcount; ++j)
570575
{
571576
wav_2D_encode (wavbuf + j, nx, wcount, ny, wcount * nx, maxValue);
572577
}
573-
wavbuf += nx * ny * wcount;
578+
wavbuf += (uint64_t) nx * ny * wcount;
574579
}
575580

576581
nBytes = 0;
@@ -722,11 +727,13 @@ internal_exr_undo_piz (
722727
nx = curc->width;
723728
ny = curc->height;
724729
wcount = (int) (curc->bytes_per_element / 2);
730+
if (wcount > 0 && nx > INT_MAX / wcount)
731+
return EXR_ERR_CORRUPT_CHUNK;
725732
for (int j = 0; j < wcount; ++j)
726733
{
727734
wav_2D_decode (wavbuf + j, nx, wcount, ny, wcount * nx, maxValue);
728735
}
729-
wavbuf += nx * ny * wcount;
736+
wavbuf += (uint64_t) nx * ny * wcount;
730737
}
731738

732739
//

0 commit comments

Comments
 (0)