diff --git a/src/dpx.imageio/dpxinput.cpp b/src/dpx.imageio/dpxinput.cpp index 123d6dd331..efdf7c5d01 100644 --- a/src/dpx.imageio/dpxinput.cpp +++ b/src/dpx.imageio/dpxinput.cpp @@ -59,6 +59,7 @@ class DPXInput final : public ImageInput { dpx::Reader m_dpx; default_init_vector m_userBuf; default_init_vector m_decodebuf; // temporary decode buffer + size_t m_filesize = 0; bool m_rawcolor; /// Reset everything to initial state @@ -137,7 +138,8 @@ DPXInput::open(const std::string& name, ImageSpec& newspec) if (!ioproxy_use_or_open(name)) return false; - m_stream = new InStream(ioproxy()); + m_filesize = ioproxy()->size(); + m_stream = new InStream(ioproxy()); if (!m_stream) { errorfmt("Could not open file \"{}\"", name); return false; @@ -547,6 +549,11 @@ DPXInput::seek_subimage(int subimage, int miplevel) // data is per-file, not per-element) if (m_userBuf.empty() && m_dpx.header.UserSize() != 0 && m_dpx.header.UserSize() != 0xFFFFFFFF) { + if (m_dpx.header.UserSize() > m_filesize) { + errorfmt("Corrupt userbuf: size claims {} but whole file size is {}", + m_dpx.header.UserSize(), m_filesize); + return false; + } m_userBuf.resize(m_dpx.header.UserSize()); m_dpx.ReadUserData(&m_userBuf[0]); } diff --git a/src/dpx.imageio/libdpx/ReaderInternal.h b/src/dpx.imageio/libdpx/ReaderInternal.h index 821d3f155a..124f9405a6 100644 --- a/src/dpx.imageio/libdpx/ReaderInternal.h +++ b/src/dpx.imageio/libdpx/ReaderInternal.h @@ -38,6 +38,8 @@ #include +#include + #include "BaseTypeConverter.h" @@ -143,13 +145,13 @@ namespace dpx int actline = line + block.y1; // first get line offset - long offset = actline * lineLength; + int64_t offset = int64_t(actline) * lineLength; // add in eoln padding - offset += line * eolnPad; - + offset += int64_t(line) * eolnPad; + // add in offset within the current line, rounding down so to catch any components within the word - offset += block.x1 * numberOfComponents / 3 * 4; + offset += int64_t(block.x1) * numberOfComponents / 3 * 4; // get the read count in bytes, round to the 32-bit boundary @@ -231,10 +233,12 @@ namespace dpx // the pattern repeats every 96 bits // first determine the word that the data element completely resides in - U16 *d1 = reinterpret_cast(reinterpret_cast(readBuf)+((i * bitDepth) / 8 /*bits*/)); - - // place the component in the MSB and mask it for both 10-bit and 12-bit - U16 d2 = (*d1 << (REVERSE - ((i % REMAIN) * MULTIPLIER))) & MASK; + U8 *d1 = reinterpret_cast(readBuf)+((i * bitDepth) / 8 /*bits*/); + U16 d2; + memcpy(&d2, d1, sizeof(U16)); // Use memcpy to launder any misalignment + + // place the component in the MSB and mask it for both 10-bit and 12-bit. + d2 = (d2 << (REVERSE - ((i % REMAIN) * MULTIPLIER))) & MASK; // For the 10/12 bit cases, specialize the 16-bit conversion by // repacking into the LSB and using a specialized conversion @@ -276,8 +280,8 @@ namespace dpx for (int line = 0; line < height; line++) { // determine offset into image element - long offset = (line + block.y1) * (lineSize * sizeof(U32)) + - (block.x1 * numberOfComponents * dataSize / 32 * sizeof(U32)) + (line * eolnPad); + int64_t offset = int64_t(line + block.y1) * (lineSize * sizeof(U32)) + + (int64_t(block.x1) * numberOfComponents * dataSize / 32 * sizeof(U32)) + int64_t(line) * eolnPad; // calculate read size int readSize = ((block.x2 - block.x1 + 1) * numberOfComponents * dataSize); @@ -338,20 +342,20 @@ namespace dpx { // determine offset into image element - long offset = (line + block.y1) * imageWidth * numberOfComponents * bytes + - block.x1 * numberOfComponents * bytes + (line * eolnPad); + int64_t offset = int64_t(line + block.y1) * imageWidth * numberOfComponents * bytes + + int64_t(block.x1) * numberOfComponents * bytes + int64_t(line) * eolnPad; if (BUFTYPE == SRCTYPE) { - fd->ReadDirect(dpxHeader, element, offset, reinterpret_cast(data + (width*line)), width*bytes); + fd->ReadDirect(dpxHeader, element, offset, reinterpret_cast(data + int64_t(width)*line), int64_t(width)*bytes); } else { - fd->Read(dpxHeader, element, offset, readBuf, width*bytes); - - // convert data + fd->Read(dpxHeader, element, offset, readBuf, int64_t(width)*bytes); + + // convert data for (int i = 0; i < width; i++) - BaseTypeConverter(readBuf[i], data[width*line+i]); + BaseTypeConverter(readBuf[i], data[int64_t(width)*line+i]); } } @@ -382,17 +386,17 @@ namespace dpx for (int line = 0; line < height; line++) { // determine offset into image element - long offset = (line + block.y1) * imageWidth * numberOfComponents * 2 + - block.x1 * numberOfComponents * 2 + (line * eolnPad); + int64_t offset = int64_t(line + block.y1) * imageWidth * numberOfComponents * 2 + + int64_t(block.x1) * numberOfComponents * 2 + int64_t(line) * eolnPad; - fd->Read(dpxHeader, element, offset, readBuf, width*2); - - // convert data + fd->Read(dpxHeader, element, offset, readBuf, int64_t(width)*2); + + // convert data for (int i = 0; i < width; i++) { U16 d1 = readBuf[i]; BaseTypeConvertU12ToU16(d1, d1); - BaseTypeConverter(d1, data[width*line+i]); + BaseTypeConverter(d1, data[int64_t(width)*line+i]); } } @@ -528,7 +532,7 @@ namespace dpx { for (nc = 0; nc < numberOfComponents; nc++) { - SRC d1 = src[(y * width * numberOfComponents) + (x * numberOfComponents) + nc]; + SRC d1 = src[int64_t(y) * width * numberOfComponents + int64_t(x) * numberOfComponents + nc]; BaseTypeConverter(d1, dst[dstoff+((x-block.x1)*numberOfComponents) + nc]); } } diff --git a/testsuite/dpx/ref/out.txt b/testsuite/dpx/ref/out.txt index 7b426b100c..88458509f1 100644 --- a/testsuite/dpx/ref/out.txt +++ b/testsuite/dpx/ref/out.txt @@ -158,3 +158,6 @@ grey.dpx : 512 x 512, 1 channel, uint10 dpx oiio:subimages: 1 Comparing "grey.dpx" and "ref/grey.tif" PASS +oiiotool ERROR: read : "src/crash-badusersize.dpx": Corrupt userbuf: size claims 4160749568 but whole file size is 2054 +Full command line was: +> oiiotool src/crash-badusersize.dpx -o test.tif diff --git a/testsuite/dpx/run.py b/testsuite/dpx/run.py index e67d664483..536e705927 100755 --- a/testsuite/dpx/run.py +++ b/testsuite/dpx/run.py @@ -4,6 +4,8 @@ # SPDX-License-Identifier: Apache-2.0 # https://github.com/AcademySoftwareFoundation/OpenImageIO +redirect = " >> out.txt 2>&1 " + files = [ "dpx_nuke_10bits_rgb.dpx", "dpx_nuke_16bits_rgba.dpx" ] for f in files: command += rw_command (OIIO_TESTSUITE_IMAGEDIR, f) @@ -31,3 +33,7 @@ " -chsum:weight=0.333,0.333,0.333 -chnames Y -ch Y -o grey.dpx") command += info_command("grey.dpx", safematch=True) command += diff_command("grey.dpx", "ref/grey.tif") + + +# Regression tests +command += oiiotool("src/crash-badusersize.dpx -o test.tif", failureok=True) diff --git a/testsuite/dpx/src/crash-badusersize.dpx b/testsuite/dpx/src/crash-badusersize.dpx new file mode 100644 index 0000000000..d83ba8b911 Binary files /dev/null and b/testsuite/dpx/src/crash-badusersize.dpx differ