Sophie

Sophie

distrib > Mageia > 8 > x86_64 > by-pkgid > 530e432b82b6e746a75c4c6cd1862d1e > files > 1

openexr-2.5.7-1.3.mga8.src.rpm

From 0963ff1c4fcb3e748a9386685622747bfef00eb1 Mon Sep 17 00:00:00 2001
From: peterhillman <peterh@wetafx.co.nz>
Date: Fri, 28 Aug 2020 17:00:05 +1200
Subject: [PATCH] reduce size limit for scanline files; prevent large
 chunkoffset allocations (#824)

* reduce size limit for scanline files; protect against large chunkoffset allocations

Signed-off-by: Peter Hillman <peterh@wetafx.co.nz>

* bugfix for memory limit changes

Signed-off-by: Peter Hillman <peterh@wetafx.co.nz>

* rearrange chunkoffset test to protect bytesperline table too

Signed-off-by: Peter Hillman <peterh@wetafx.co.nz>

* remove extraneous function declaration; tidy comments

Signed-off-by: Peter Hillman <peterh@wetafx.co.nz>
---
 OpenEXR/IlmImf/ImfCompressor.cpp         | 31 +++++++++++++++++
 OpenEXR/IlmImf/ImfCompressor.h           |  8 +++++
 OpenEXR/IlmImf/ImfMisc.cpp               | 33 +-----------------
 OpenEXR/IlmImf/ImfMisc.h                 |  1 +
 OpenEXR/IlmImf/ImfMultiPartInputFile.cpp | 24 ++++++++++++-
 OpenEXR/IlmImf/ImfScanLineInputFile.cpp  | 44 +++++++++++++++++++-----
 6 files changed, 99 insertions(+), 42 deletions(-)

diff --git a/OpenEXR/IlmImf/ImfCompressor.cpp b/OpenEXR/IlmImf/ImfCompressor.cpp
index 1905a4d66..1c336a855 100644
--- a/OpenEXR/IlmImf/ImfCompressor.cpp
+++ b/OpenEXR/IlmImf/ImfCompressor.cpp
@@ -176,6 +176,37 @@ newCompressor (Compression c, size_t maxScanLineSize, const Header &hdr)
 }
 
 
+// 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");
+    }
+}
+
+
 Compressor *
 newTileCompressor (Compression c,
 		   size_t tileLineSize,
diff --git a/OpenEXR/IlmImf/ImfCompressor.h b/OpenEXR/IlmImf/ImfCompressor.h
index 958677865..a6850b5f8 100644
--- a/OpenEXR/IlmImf/ImfCompressor.h
+++ b/OpenEXR/IlmImf/ImfCompressor.h
@@ -268,6 +268,14 @@ Compressor *    newTileCompressor (Compression c,
 				   const Header &hdr);
 
 
+//-----------------------------------------------------------------
+// Return the maximum number of scanlines in each chunk
+// of a scanline image using the given compression scheme
+//-----------------------------------------------------------------
+
+IMF_EXPORT
+int              numLinesInBuffer(Compression comp);
+
 OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
 
 #endif
diff --git a/OpenEXR/IlmImf/ImfMisc.cpp b/OpenEXR/IlmImf/ImfMisc.cpp
index d2c847877..b397b9f98 100644
--- a/OpenEXR/IlmImf/ImfMisc.cpp
+++ b/OpenEXR/IlmImf/ImfMisc.cpp
@@ -1848,38 +1848,7 @@ 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)
diff --git a/OpenEXR/IlmImf/ImfMisc.h b/OpenEXR/IlmImf/ImfMisc.h
index f1cf648ab..3535ea676 100644
--- a/OpenEXR/IlmImf/ImfMisc.h
+++ b/OpenEXR/IlmImf/ImfMisc.h
@@ -475,6 +475,7 @@ bool usesLongNames (const Header &header);
 IMF_EXPORT
 int getChunkOffsetTableSize(const Header& header,bool deprecated_attribute=false);
 
+
 OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT
 
 
diff --git a/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp b/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp
index 1e0472698..689956c90 100644
--- a/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp
+++ b/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp
@@ -741,7 +741,9 @@ MultiPartInputFile::Data::getPart(int partNumber)
     return parts[partNumber];
 }
 
-
+namespace{
+static const int gLargeChunkTableSize = 1024*1024;
+}
 
 void
 MultiPartInputFile::Data::readChunkOffsetTables(bool reconstructChunkOffsetTable)
@@ -751,8 +753,28 @@ MultiPartInputFile::Data::readChunkOffsetTables(bool reconstructChunkOffsetTable
     for (size_t i = 0; i < parts.size(); i++)
     {
         int chunkOffsetTableSize = getChunkOffsetTableSize(parts[i]->header);
+
+        //
+        // avoid allocating excessive memory.
+        // If the chunktablesize claims to be large,
+        // check the file is big enough to contain the table before allocating memory.
+        // Attempt to read the last entry in the table. Either the seekg() or the read()
+        // call will throw an exception if the file is too small to contain the table
+        //
+        if (chunkOffsetTableSize > gLargeChunkTableSize)
+        {
+            Int64 pos = is->tellg();
+            is->seekg(pos + (chunkOffsetTableSize-1)*sizeof(Int64));
+            Int64 temp;
+            OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*is, temp);
+            is->seekg(pos);
+
+        }
+
         parts[i]->chunkOffsets.resize(chunkOffsetTableSize);
 
+
+
         for (int j = 0; j < chunkOffsetTableSize; j++)
             OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*is, parts[i]->chunkOffsets[j]);
 
diff --git a/OpenEXR/IlmImf/ImfScanLineInputFile.cpp b/OpenEXR/IlmImf/ImfScanLineInputFile.cpp
index 1ef4eba3f..b020cb9bb 100644
--- a/OpenEXR/IlmImf/ImfScanLineInputFile.cpp
+++ b/OpenEXR/IlmImf/ImfScanLineInputFile.cpp
@@ -1100,7 +1100,7 @@ newLineBufferTask (TaskGroup *group,
  }
  
   
-
+static const int gLargeChunkTableSize = 1024*1024;
 
 } // namespace
 
@@ -1118,25 +1118,53 @@ void ScanLineInputFile::initialize(const Header& header)
         _data->minY = dataWindow.min.y;
         _data->maxY = dataWindow.max.y;
 
+        Compression comp = _data->header.compression();
+
+        _data->linesInBuffer =
+            numLinesInBuffer (comp);
+
+        int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
+                              _data->linesInBuffer) / _data->linesInBuffer;
+
+        //
+        // avoid allocating excessive memory due to large lineOffsets table size.
+        // If the chunktablesize claims to be large,
+        // check the file is big enough to contain the table before allocating memory
+        // in the bytesPerLineTable and the lineOffsets table.
+        // Attempt to read the last entry in the table. Either the seekg() or the read()
+        // call will throw an exception if the file is too small to contain the table
+        //
+        if (lineOffsetSize > gLargeChunkTableSize)
+        {
+            Int64 pos = _streamData->is->tellg();
+            _streamData->is->seekg(pos + (lineOffsetSize-1)*sizeof(Int64));
+            Int64 temp;
+            OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_streamData->is, temp);
+            _streamData->is->seekg(pos);
+
+        }
+
+
         size_t maxBytesPerLine = bytesPerLineTable (_data->header,
                                                     _data->bytesPerLine);
-        
-        if(maxBytesPerLine > INT_MAX)
+
+        if (maxBytesPerLine*numLinesInBuffer(comp) > INT_MAX)
         {
             throw IEX_NAMESPACE::InputExc("maximum bytes per scanline exceeds maximum permissible size");
         }
 
 
+        //
+        // allocate compressor objects
+        //
         for (size_t i = 0; i < _data->lineBuffers.size(); i++)
         {
-            _data->lineBuffers[i] = new LineBuffer (newCompressor
-                                                (_data->header.compression(),
+            _data->lineBuffers[i] = new LineBuffer (newCompressor(comp,
                                                  maxBytesPerLine,
                                                  _data->header));
         }
 
-        _data->linesInBuffer =
-            numLinesInBuffer (_data->lineBuffers[0]->compressor);
+
 
         _data->lineBufferSize = maxBytesPerLine * _data->linesInBuffer;
 
@@ -1153,8 +1181,6 @@ void ScanLineInputFile::initialize(const Header& header)
                                  _data->linesInBuffer,
                                  _data->offsetInLineBuffer);
 
-        int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
-                              _data->linesInBuffer) / _data->linesInBuffer;
 
         _data->lineOffsets.resize (lineOffsetSize);
 }