Backport of From 6bad53af7eebed507564dd5fc90320e4c6a6c0bc Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 20 Jan 2020 09:07:02 +1300 Subject: [PATCH 01/23] Force tile sizes to be less than INT_MAX bytes, in line with the maximum dimensions of data windows From df987cabc20c90803692022fd232def837cb88cc Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 20 Jan 2020 10:52:17 +1300 Subject: [PATCH 02/23] validate tiles have valid headers when raw reading tiles From 37750013830def57f19f3c3b7faaa9fc1dae81b3 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 20 Jan 2020 11:18:55 +1300 Subject: [PATCH 03/23] Sanity check for input buffer overruns in RLE uncompress From 3eda5d70aba127bae9bd6bae9956fcf024b64031 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 20 Jan 2020 14:46:54 +1300 Subject: [PATCH 04/23] fixes for DWA uncompress: sanity check unknown data reading, off-by-one error on max suffix string length From b9997d0c045fa01af3d2e46e1a74b07cc4519446 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Mon, 20 Jan 2020 15:39:10 +1300 Subject: [PATCH 06/23] prevent int overflow when calculating buffer offsets From 7a52d40ae23c148f27116cb1f6e897b9143b372c Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Tue, 21 Jan 2020 12:04:13 +1300 Subject: [PATCH 07/23] bypass SSE optimization when skipping subsampled channels From 801272c9bf8b84a66c62f1e8a4490ece81da6a56 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Tue, 21 Jan 2020 13:33:53 +1300 Subject: [PATCH 08/23] check for bad bit counts in Huff encoded data From 43cd3ad47d53356da6ae2e983e47c8313aebf72e Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Tue, 21 Jan 2020 14:53:23 +1300 Subject: [PATCH 09/23] improve bad count detection in huf decompress From ea3349896d4a8a3b523e8f3b830334a85240b1e6 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Tue, 21 Jan 2020 15:12:58 +1300 Subject: [PATCH 10/23] sanity check data reads from PIZ data From b1c34c496b62117115b1089b18a44e0031800a09 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Wed, 22 Jan 2020 09:35:46 +1300 Subject: [PATCH 11/23] fix memory leak when reading damaged PIZ files From e7c26f6ef5bf7ae8ea21ecf19963186cd1391720 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Wed, 22 Jan 2020 17:31:22 +1300 Subject: [PATCH 12/23] abort when file claims to have excessive scanline data requirements From a6408c90339bdf19f89476578d7f936b741be9b2 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Thu, 23 Jan 2020 09:40:44 +1300 Subject: [PATCH 13/23] avoid creating compression object just to compute numLinesInBuffer From 2ae5f8376b0a6c3e2bb100042f5de79503ba837a Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Thu, 23 Jan 2020 09:52:58 +1300 Subject: [PATCH 14/23] fix check for valid ruleSize From dea0ef1ee7b2f4d2aa42ffba7b442e5d8051222b Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Thu, 23 Jan 2020 12:30:11 +1300 Subject: [PATCH 15/23] fix memory leak on DeepTiledInput files: compressor for sample count table wasn't deleted From d4fbaad4efe5d0ddf325da44ecbab105ebb2954e Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Thu, 23 Jan 2020 12:33:11 +1300 Subject: [PATCH 16/23] fix memory leak in test suite From 53a06468ef5a08f4f2beb2d264a20547d7a78753 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Thu, 23 Jan 2020 14:44:48 +1300 Subject: [PATCH 17/23] fixes to memory leak when constructors throw exceptions From b673e6ad0ec6cef94d86b9586244d26088a3d792 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Fri, 24 Jan 2020 08:42:07 +1300 Subject: [PATCH 18/23] Fix cleanup when DeepScanLineInputFile constructor throws From acad98d6d3e787f36012a3737c23c42c7f43a00f Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Fri, 24 Jan 2020 13:43:47 +1300 Subject: [PATCH 21/23] missing header for ptrdiff_t From 0a1aa55ef108169c933ddaa631c1f6cb02b69050 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Tue, 28 Jan 2020 18:17:01 +1300 Subject: [PATCH 22/23] minor tweaks and typo fixes From 89ce46f38c5e658d21df9179c1641c496cab7396 Mon Sep 17 00:00:00 2001 From: Peter Hillman Date: Tue, 28 Jan 2020 18:18:01 +1300 Subject: [PATCH 23/23] force x/y Sampling to 1 for Deep Scanline Images --- openexr-2.2.1.orig/IlmImf/ImfCompositeDeepScanLine.cpp +++ openexr-2.2.1/IlmImf/ImfCompositeDeepScanLine.cpp @@ -179,7 +179,7 @@ CompositeDeepScanLine::Data::handleDeepF int start, int end) { - int width=_dataWindow.size().x+1; + ptrdiff_t width=_dataWindow.size().x+1; size_t pixelcount = width * (end-start+1); pointers.resize(_channels.size()); counts.resize(pixelcount); --- openexr-2.2.1.orig/IlmImf/ImfDeepScanLineInputFile.cpp +++ openexr-2.2.1/IlmImf/ImfDeepScanLineInputFile.cpp @@ -915,8 +915,7 @@ void DeepScanLineInputFile::initialize(c } catch (...) { - delete _data; - _data=NULL; + // Don't delete _data here, leave that to caller throw; } } @@ -932,8 +931,15 @@ DeepScanLineInputFile::DeepScanLineInput _data->memoryMapped = _data->_streamData->is->isMemoryMapped(); _data->version = part->version; - initialize(part->header); - + try + { + initialize(part->header); + } + catch(...) + { + delete _data; + throw; + } _data->lineOffsets = part->chunkOffsets; _data->partNumber = part->partNumber; @@ -945,7 +951,6 @@ DeepScanLineInputFile::DeepScanLineInput : _data (new Data (numThreads)) { - _data->_streamData = new InputStreamMutex(); _data->_deleteStream = true; OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is = 0; @@ -955,12 +960,29 @@ DeepScanLineInputFile::DeepScanLineInput readMagicNumberAndVersionField(*is, _data->version); // // Backward compatibility to read multpart file. - // + // multiPartInitialize will create _streamData if (isMultiPart(_data->version)) { compatibilityInitialize(*is); return; } + } + catch (IEX_NAMESPACE::BaseExc &e) + { + if (is) delete is; + if (_data) delete _data; + + REPLACE_EXC (e, "Cannot read image file " + "\"" << fileName << "\". " << e.what()); + throw; + } + + // + // not multiPart - allocate stream data and intialise as normal + // + try + { + _data->_streamData = new InputStreamMutex(); _data->_streamData->is = is; _data->memoryMapped = is->isMemoryMapped(); _data->header.readFrom (*_data->_streamData->is, _data->version); @@ -976,7 +998,10 @@ DeepScanLineInputFile::DeepScanLineInput catch (IEX_NAMESPACE::BaseExc &e) { if (is) delete is; - if (_data && _data->_streamData) delete _data->_streamData; + if (_data && _data->_streamData) + { + delete _data->_streamData; + } if (_data) delete _data; REPLACE_EXC (e, "Cannot read image file " @@ -986,7 +1011,10 @@ DeepScanLineInputFile::DeepScanLineInput catch (...) { if (is) delete is; - if (_data && _data->_streamData) delete _data->_streamData; + if (_data && _data->_streamData) + { + delete _data->_streamData; + } if (_data) delete _data; throw; @@ -1010,7 +1038,18 @@ DeepScanLineInputFile::DeepScanLineInput _data->version =version; - initialize (header); + try + { + initialize (header); + } + catch (...) + { + if (_data && _data->_streamData) + { + delete _data->_streamData; + } + if (_data) delete _data; + } readLineOffsets (*_data->_streamData->is, _data->lineOrder, @@ -1042,8 +1081,9 @@ DeepScanLineInputFile::~DeepScanLineInpu // if (_data->partNumber == -1 && _data->_streamData) + { delete _data->_streamData; - + } delete _data; } } --- openexr-2.2.1.orig/IlmImf/ImfDeepTiledInputFile.cpp +++ openexr-2.2.1/IlmImf/ImfDeepTiledInputFile.cpp @@ -283,6 +283,7 @@ DeepTiledInputFile::Data::Data (int numT multiPartBackwardSupport(false), numThreads(numThreads), memoryMapped(false), + sampleCountTableComp(NULL), _streamData(NULL), _deleteStream(false) { @@ -308,6 +309,8 @@ DeepTiledInputFile::Data::~Data () for (size_t i = 0; i < slices.size(); i++) delete slices[i]; + + delete sampleCountTableComp; } @@ -927,7 +930,15 @@ DeepTiledInputFile::DeepTiledInputFile ( _data (new Data (part->numThreads)) { _data->_deleteStream=false; - multiPartInitialize(part); + try + { + multiPartInitialize(part); + } + catch(...) + { + delete _data; + throw; + } } --- openexr-2.2.1.orig/IlmImf/ImfDwaCompressor.cpp +++ openexr-2.2.1/IlmImf/ImfDwaCompressor.cpp @@ -265,8 +265,9 @@ struct DwaCompressor::Classifier " (truncated rule)."); { - char suffix[Name::SIZE]; - memset (suffix, 0, Name::SIZE); + // maximum length of string plus one byte for terminating NULL + char suffix[Name::SIZE+1]; + memset (suffix, 0, Name::SIZE+1); Xdr::read (ptr, std::min(size, Name::SIZE-1), suffix); _suffix = std::string(suffix); } @@ -2409,7 +2410,7 @@ DwaCompressor::uncompress unsigned short ruleSize = 0; Xdr::read(dataPtr, ruleSize); - if (ruleSize < 0) + if (ruleSize < Xdr::size() ) throw Iex::InputExc("Error uncompressing DWA data" " (corrupt header file)."); @@ -2806,6 +2807,14 @@ DwaCompressor::uncompress if (Imath::modp (y, cd->ySampling) != 0) continue; + // + // sanity check for buffer data lying within range + // + if (cd->planarUncBufferEnd + dstScanlineSize - _planarUncBuffer[UNKNOWN] > _planarUncBufferSize[UNKNOWN] ) + { + throw Iex::InputExc("DWA data corrupt"); + } + memcpy (rowPtrs[chan][row], cd->planarUncBufferEnd, dstScanlineSize); --- openexr-2.2.1.orig/IlmImf/ImfFastHuf.cpp +++ openexr-2.2.1/IlmImf/ImfFastHuf.cpp @@ -256,14 +256,29 @@ FastHufDecoder::FastHufDecoder int symbol = *i >> 6; if (mapping[codeLen] >= _numSymbols) + { + delete[] _idToSymbol; + _idToSymbol = NULL; throw Iex::InputExc ("Huffman decode error " "(Invalid symbol in header)."); - + } _idToSymbol[mapping[codeLen]] = symbol; mapping[codeLen]++; } - buildTables(base, offset); + // + // exceptions can be thrown whilst building tables. Delete + // _idToSynmbol before re-throwing to prevent memory leak + // + try + { + buildTables(base, offset); + }catch(...) + { + delete[] _idToSymbol; + _idToSymbol = NULL; + throw; + } } --- openexr-2.2.1.orig/IlmImf/ImfHeader.cpp +++ openexr-2.2.1/IlmImf/ImfHeader.cpp @@ -914,7 +914,7 @@ Header::sanityCheck (bool isTiled, bool const TileDescription &tileDesc = tileDescription(); - if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0) + if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0 || tileDesc.xSize > INT_MAX || tileDesc.ySize > INT_MAX ) throw IEX_NAMESPACE::ArgExc ("Invalid tile size in image header."); if (maxTileWidth > 0 && --- openexr-2.2.1.orig/IlmImf/ImfHuf.cpp +++ openexr-2.2.1/IlmImf/ImfHuf.cpp @@ -1052,7 +1052,10 @@ hufUncompress (const char compressed[], unsigned short raw[], int nRaw) { - if (nCompressed == 0) + // + // nead at least 20 bytes for header + // + if (nCompressed < 20 ) { if (nRaw != 0) notEnoughData(); @@ -1070,6 +1073,12 @@ hufUncompress (const char compressed[], const char *ptr = compressed + 20; + if ( ptr + (nBits+7 )/8 > compressed+nCompressed) + { + notEnoughData(); + return; + } + // // Fast decoder needs at least 2x64-bits of compressed data, and // needs to be run-able on this platform. Otherwise, fall back --- openexr-2.2.1.orig/IlmImf/ImfMisc.cpp +++ openexr-2.2.1/IlmImf/ImfMisc.cpp @@ -114,9 +114,9 @@ bytesPerLineTable (const Header &header, c != channels.end(); ++c) { - int nBytes = pixelTypeSize (c.channel().type) * - (dataWindow.max.x - dataWindow.min.x + 1) / - c.channel().xSampling; + size_t nBytes = size_t(pixelTypeSize (c.channel().type)) * + size_t(dataWindow.max.x - dataWindow.min.x + 1) / + size_t(c.channel().xSampling); for (int y = dataWindow.min.y, i = 0; y <= dataWindow.max.y; ++y, ++i) if (modp (y, c.channel().ySampling) == 0) @@ -262,6 +262,7 @@ defaultFormat (Compressor * compressor) } +//obsolete int numLinesInBuffer (Compressor * compressor) { @@ -1838,6 +1839,39 @@ usesLongNames (const Header &header) return false; } +namespace +{ +// for a given compression type, return the number of scanlines +// compressed into a single chunk +// TODO add to API and move to ImfCompressor.cpp +int +numLinesInBuffer(Compression comp) +{ + switch(comp) + { + case NO_COMPRESSION : + case RLE_COMPRESSION: + case ZIPS_COMPRESSION: + return 1; + case ZIP_COMPRESSION: + return 16; + case PIZ_COMPRESSION: + return 32; + case PXR24_COMPRESSION: + return 16; + case B44_COMPRESSION: + case B44A_COMPRESSION: + case DWAA_COMPRESSION: + return 32; + case DWAB_COMPRESSION: + return 256; + + default: + throw IEX_NAMESPACE::ArgExc ("Unknown compression type"); + } +} +} + int getScanlineChunkOffsetTableSize(const Header& header) { @@ -1847,17 +1881,11 @@ getScanlineChunkOffsetTableSize(const He size_t maxBytesPerLine = bytesPerLineTable (header, bytesPerLine); - Compressor* compressor = newCompressor(header.compression(), - maxBytesPerLine, - header); - - int linesInBuffer = numLinesInBuffer (compressor); + int linesInBuffer = numLinesInBuffer ( header.compression() ); int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y + linesInBuffer) / linesInBuffer; - delete compressor; - return lineOffsetSize; } --- openexr-2.2.1.orig/IlmImf/ImfPizCompressor.cpp +++ openexr-2.2.1/IlmImf/ImfPizCompressor.cpp @@ -491,7 +491,9 @@ PizCompressor::uncompress (const char *i // This is the cunompress function which is used by both the tiled and // scanline decompression routines. // - + + const char* inputEnd=inPtr+inSize; + // // Special case - empty input buffer // @@ -502,6 +504,7 @@ PizCompressor::uncompress (const char *i return 0; } + // // Determine the layout of the compressed pixel data // @@ -548,6 +551,12 @@ PizCompressor::uncompress (const char *i AutoArray bitmap; memset (bitmap, 0, sizeof (unsigned char) * BITMAP_SIZE); + + if(inPtr + sizeof(unsigned short)*2 > inputEnd) + { + throw InputExc ("PIZ compressed data too short"); + } + Xdr::read (inPtr, minNonZero); Xdr::read (inPtr, maxNonZero); @@ -559,8 +568,14 @@ PizCompressor::uncompress (const char *i if (minNonZero <= maxNonZero) { - Xdr::read (inPtr, (char *) &bitmap[0] + minNonZero, - maxNonZero - minNonZero + 1); + size_t bytesToRead = maxNonZero - minNonZero + 1; + if(inPtr + bytesToRead > inputEnd) + { + throw InputExc ("PIZ compressed data too short"); + } + +Xdr::read (inPtr, (char *) &bitmap[0] + minNonZero, + bytesToRead); } AutoArray lut; @@ -569,6 +584,11 @@ PizCompressor::uncompress (const char *i // // Huffman decoding // + if(inPtr + sizeof(int)> inputEnd) + { + throw InputExc ("PIZ compressed data too short"); + } + int length; Xdr::read (inPtr, length); --- openexr-2.2.1.orig/IlmImf/ImfRle.cpp +++ openexr-2.2.1/IlmImf/ImfRle.cpp @@ -129,6 +129,11 @@ rleUncompress (int inLength, int maxLeng if (0 > (maxLength -= count)) return 0; + // check the input buffer is big enough to contain + // 'count' bytes of remaining data + if (inLength < 0) + return 0; + memcpy(out, in, count); out += count; in += count; --- openexr-2.2.1.orig/IlmImf/ImfScanLineInputFile.cpp +++ openexr-2.2.1/IlmImf/ImfScanLineInputFile.cpp @@ -1114,6 +1114,12 @@ void ScanLineInputFile::initialize(const size_t maxBytesPerLine = bytesPerLineTable (_data->header, _data->bytesPerLine); + + if(maxBytesPerLine > INT_MAX) + { + throw IEX_NAMESPACE::InputExc("maximum bytes per scanline exceeds maximum permissible size"); + } + for (size_t i = 0; i < _data->lineBuffers.size(); i++) { @@ -1148,6 +1154,8 @@ void ScanLineInputFile::initialize(const } catch (...) { + if (_data->partNumber == -1) + delete _streamData; delete _data; _data=NULL; throw; @@ -1420,6 +1428,14 @@ ScanLineInputFile::setFrameBuffer (const offset+=2; break; } + + // + // optimization mode cannot currently skip subsampled channels + // + if (i.channel().xSampling!=1 || i.channel().ySampling!=1) + { + optimizationPossible = false; + } ++i; } --- openexr-2.2.1.orig/IlmImf/ImfTiledInputFile.cpp +++ openexr-2.2.1/IlmImf/ImfTiledInputFile.cpp @@ -736,7 +736,10 @@ TiledInputFile::TiledInputFile (const ch delete _data->_streamData; } - + if (_data) + { + delete _data; + } if (is != 0) delete is; @@ -759,6 +762,10 @@ TiledInputFile::TiledInputFile (const ch if (is != 0) delete is; + if (_data) + { + delete _data; + } throw; } } @@ -846,7 +853,15 @@ TiledInputFile::TiledInputFile (InputPar { _data = new Data (part->numThreads); _data->_deleteStream=false; - multiPartInitialize(part); + try + { + multiPartInitialize(part); + } + catch(...) + { + if (_data) delete _data; + throw; + } } @@ -1307,6 +1322,11 @@ TiledInputFile::rawTileData (int &dx, in readNextTileData (_data->_streamData, _data, dx, dy, lx, ly, tileBuffer->buffer, pixelDataSize); + + if ( !isValidLevel(lx,ly) || !isValidTile (dx, dy, lx, ly) ) + throw IEX_NAMESPACE::ArgExc ("File contains an invalid tile"); + + if(isMultiPart(version())) { if (old_dx!=dx || old_dy !=dy || old_lx!=lx || old_ly!=ly) --- openexr-2.2.1.orig/IlmImfTest/testMultiPartApi.cpp +++ openexr-2.2.1/IlmImfTest/testMultiPartApi.cpp @@ -450,6 +450,21 @@ generateRandomFile (int partCount, const } } + for (size_t i = 0 ; i < parts.size() ; ++i ) + { + int partType = partTypes[i]; + + if (partType == 0) + { + delete (OutputPart*) parts[i]; + } + else + { + delete (TiledOutputPart*) parts[i]; + } + + } + delete[] tiledHalfData; delete[] tiledUintData; delete[] tiledFloatData;