diff -Nru openexr-2.5.3/CHANGES.md openexr-2.5.4/CHANGES.md --- openexr-2.5.3/CHANGES.md 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/CHANGES.md 2020-12-30 23:09:11.000000000 +0000 @@ -1,5 +1,6 @@ # OpenEXR Release Notes +* [Version 2.5.4](#version-254-december-31-2020) December 31, 2020 * [Version 2.5.3](#version-253-august-12-2020) August 12, 2020 * [Version 2.5.2](#version-252-june-15-2020) June 15, 2020 * [Version 2.5.1](#version-251-may-11-2020) May 11, 2020 @@ -37,6 +38,63 @@ * [Version 1.0.1](#version-101) * [Version 1.0](#version-10) +## Version 2.5.4 (December 31, 2020) + +Patch release with various bug/sanitizer/security fixes, primarily +related to reading corrupted input files. + +Specific OSS-fuzz issues include: + +* OSS-fuzz [#24854](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24854) Segv on unknown address in Imf_2_5::hufUncompress +* OSS-fuzz [#24831](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24831) Undefined-shift in Imf_2_5::FastHufDecoder::FastHufDecoder +* OSS-fuzz [#24969](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24969) Invalid-enum-value in Imf_2_5::TypedAttribute::writeValueTo +* OSS-fuzz [#25297](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25297) Integer-overflow in Imf_2_5::calculateNumTiles +* OSS-fuzz [#24787](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=24787) Undefined-shift in Imf_2_5::unpack14 +* OSS-fuzz [#25326](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25326) Out-of-memory in openexr_scanlines_fuzzer +* OSS-fuzz [#25399](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25399) Heap-buffer-overflow in Imf_2_5::FastHufDecoder::FastHufDecoder +* OSS-fuzz [#25415](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25415) Abrt in __cxxabiv1::failed_throw +* OSS-fuzz [#25370](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25370) Out-of-memory in openexr_exrenvmap_fuzzer +* OSS-fuzz [#25501](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25501) Out-of-memory in openexr_scanlines_fuzzer +* OSS-fuzz [#25505](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25505) Heap-buffer-overflow in Imf_2_5::copyIntoFrameBuffer +* OSS-fuzz [#25562](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25562) Integer-overflow in Imf_2_5::hufUncompress +* OSS-fuzz [#25740](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25740) Null-dereference READ in Imf_2_5::Header::operator +* OSS-fuzz [#25743](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25743) Null-dereference in Imf_2_5::MultiPartInputFile::header +* OSS-fuzz [#25913](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25913) Out-of-memory in openexr_exrenvmap_fuzzer +* OSS-fuzz [#26229](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=26229) Undefined-shift in Imf_2_5::hufDecode +* OSS-fuzz [#26658](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=26658) Out-of-memory in openexr_scanlines_fuzzer +* OSS-fuzz [#26956](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=26956) Heap-buffer-overflow in Imf_2_5::DeepTiledInputFile::readPixelSampleCounts +* OSS-fuzz [#27409](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=27409) Out-of-memory in openexr_exrcheck_fuzzer +* OSS-fuzz [#25892](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25892) Divide-by-zero in Imf_2_5::calculateNumTiles +* OSS-fuzz [#25894](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25894) Floating-point-exception in Imf_2_5::precalculateTileInfo + +### Merged Pull Requests + +* [#817](https://github.com/AcademySoftwareFoundation/openexr/pull/817): double-check unpackedBuffer created in DWA uncompress (OSS-fuzz 24854) +* [#818](https://github.com/AcademySoftwareFoundation/openexr/pull/818): compute Huf codelengths using 64 bit to prevent shift overrflow (OSS-fuzz 24831) +* [#820](https://github.com/AcademySoftwareFoundation/openexr/pull/820): suppress sanitizer warnings when writing invalid enums (OSS-fuzz 24969) +* [#825](https://github.com/AcademySoftwareFoundation/openexr/pull/825): Avoid overflow in calculateNumTiles when size=MAX_INT (OSS-fuzz 25297) +* [#826](https://github.com/AcademySoftwareFoundation/openexr/pull/826): restrict maximum tile size to INT_MAX byte limit (OSS-fuzz 25297) +* [#832](https://github.com/AcademySoftwareFoundation/openexr/pull/832): ignore unused bits in B44 mode detection (OSS-fuzz 24787) +* [#827](https://github.com/AcademySoftwareFoundation/openexr/pull/827): lighter weight reading of Luma-only images via RgbaInputFile (OSS-fuzz 25326) +* [#829](https://github.com/AcademySoftwareFoundation/openexr/pull/829): fix buffer overflow check in PIZ decompression (OSS-fuzz 25399, OSS-fuzz 25415) +* [#830](https://github.com/AcademySoftwareFoundation/openexr/pull/830): refactor channel filling in InputFile API with tiled source (OSS-fuzz 25370 , OSS-fuzz 25501) +* [#831](https://github.com/AcademySoftwareFoundation/openexr/pull/ #831): Use Int64 in dataWindowForTile to prevent integer overflow (OSS-fuzz 25505) +* [#836](https://github.com/AcademySoftwareFoundation/openexr/pull/836): prevent overflow in hufUncompress if nBits is large (OSS-fuzz 25562) +* [#840](https://github.com/AcademySoftwareFoundation/openexr/pull/840): add sanity check for reading multipart files with no parts (OSS-fuzz 25740 , OSS-fuzz 25743) +* [#841](https://github.com/AcademySoftwareFoundation/openexr/pull/841): more elegant exception handling in exrmaketiled (ZhiWei Sun from Topsec Alpha Lab) +* [#843](https://github.com/AcademySoftwareFoundation/openexr/pull/843): reduce B44 _tmpBufferSize (was allocating two bytes per byte) (OSS-fuzz 25913) +* [#844](https://github.com/AcademySoftwareFoundation/openexr/pull/844): check EXRAllocAligned succeeded to allocate ScanlineInputFile lineBuffers (ZhiWei Sun from Topsec Alpha Lab) +* [#845](https://github.com/AcademySoftwareFoundation/openexr/pull/845): test channels are DCT compressed before DWA decompression (ZhiWei Sun from Topsec Alpha Lab) +* [#849](https://github.com/AcademySoftwareFoundation/openexr/pull/849): check for valid Huf code lengths (OSS-fuzz 26229) +* [#860](https://github.com/AcademySoftwareFoundation/openexr/pull/860): check 1 part files with 'nonimage' bit have type attribute (OSS-fuzz 26658) +* [#861](https://github.com/AcademySoftwareFoundation/openexr/pull/861): Fix overflow computing deeptile sample table size (OSS-fuzz 26956) +* [#863](https://github.com/AcademySoftwareFoundation/openexr/pull/863): re-order shift/compare in FastHuf to prevent undefined shift overflow (OSS-fuzz 27409) +* Also, partial fixes from [#842](https://github.com/AcademySoftwareFoundation/openexr/pull/842) which do not change the ABI: (OSS-fuzz 25892 , OSS-fuzz 25894) + +### Commits \[ git log v2.5.3...v2.5.4\] + +* [0c2b46f6](https://github.com/AcademySoftwareFoundation/openexr/commit/0c2b46f630a3b5f2f561c2849d047ee39f899179) Cherry-pick PRs from master branch which fix issues reported by fuzz tests (#875) ([peterhillman](@peterh@wetafx.co.nz) 2020-12-31) + ## Version 2.5.3 (August 12, 2020) Patch release with various bug/security fixes and build/install fixes, plus a performance optimization: @@ -641,9 +699,11 @@ This version fixes the following security vulnerabilities: -* [CVE-2018-18444](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-18444) [Issue #351](https://github.com/openexr/openexr/issues/351) Out of Memory -* [CVE-2018-18443](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-18443) [Issue #350](https://github.com/openexr/openexr/issues/350) heap-buffer-overflow -* [CVE-2017-12596](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-12596) [Issue #238](https://github.com/openexr/openexr/issues/238) heap-based buffer overflow in exrmaketiled +* [CVE-2020-16589](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-16589) A head-based buffer overflow exists in Academy Software Foundation OpenEXR 2.3.0 in writeTileData in ImfTiledOutputFile.cpp that can cause a denial of service via a crafted EXR file. +* [CVE-2020-16588](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-16588) A Null Pointer Deference issue exists in Academy Software Foundation OpenEXR 2.3.0 in generatePreview in makePreview.cpp that can cause a denial of service via a crafted EXR file. +* [CVE-2020-16587](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-16587) A heap-based buffer overflow vulnerability exists in Academy Software Foundation OpenEXR 2.3.0 in chunkOffsetReconstruction in ImfMultiPartInputFile.cpp that can cause a denial of service via a crafted EXR file. +* [CVE-2018-18444](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-18444) makeMultiView.cpp in exrmultiview in OpenEXR 2.3.0 has an out-of-bounds write, leading to an assertion failure or possibly unspecified other impact. +* [CVE-2018-18443](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-18443) OpenEXR 2.3.0 has a memory leak in ThreadPool in IlmBase/IlmThread/IlmThreadPool.cpp, as demonstrated by exrmultiview. ### Closed Issues diff -Nru openexr-2.5.3/debian/changelog openexr-2.5.4/debian/changelog --- openexr-2.5.3/debian/changelog 2020-08-21 20:56:55.000000000 +0000 +++ openexr-2.5.4/debian/changelog 2021-01-21 22:24:00.000000000 +0000 @@ -1,3 +1,13 @@ +openexr (2.5.4-1) unstable; urgency=medium + + * New upstream release + * debian/watch: parameters updated + * debian/control: + - S-V bump 4.5.0 -> 4.5.1 (no changes needed) + - set minimal ilmbase lib to v2.5.4 + + -- Matteo F. Vescovi Thu, 21 Jan 2021 23:24:00 +0100 + openexr (2.5.3-2) unstable; urgency=medium * Upload to unstable (Closes: #959444) diff -Nru openexr-2.5.3/debian/control openexr-2.5.4/debian/control --- openexr-2.5.3/debian/control 2020-08-06 18:16:01.000000000 +0000 +++ openexr-2.5.4/debian/control 2021-01-21 22:21:55.000000000 +0000 @@ -12,10 +12,10 @@ debhelper-compat (= 13), dh-buildinfo, dpkg-dev (>= 1.18.0), - libilmbase-dev (>= 2.5.2), + libilmbase-dev (>= 2.5.4), pkg-config, zlib1g-dev -Standards-Version: 4.5.0 +Standards-Version: 4.5.1 Rules-Requires-Root: no Homepage: http://www.openexr.com Vcs-Git: https://salsa.debian.org/debian-phototools-team/openexr.git diff -Nru openexr-2.5.3/debian/watch openexr-2.5.4/debian/watch --- openexr-2.5.3/debian/watch 2020-02-11 21:24:14.000000000 +0000 +++ openexr-2.5.4/debian/watch 2021-01-21 22:14:38.000000000 +0000 @@ -1,4 +1,4 @@ version=4 -opts="pgpsigurlmangle=s/archive\/(\d\S+)\.tar\.gz/releases\/download\/$1\/$1\.tar\.gz\.asc/, \ -filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/openexr_$1\.tar\.gz/" \ +opts="filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/openexr-$1\.tar\.gz/, \ +pgpsigurlmangle=s/archive\/(\d\S+)\.tar\.gz/releases\/download\/$1\/$1\.tar\.gz\.asc" \ https://github.com/AcademySoftwareFoundation/openexr/tags .*/v?(\d\S+)\.tar\.gz diff -Nru openexr-2.5.3/IlmBase/configure.ac openexr-2.5.4/IlmBase/configure.ac --- openexr-2.5.3/IlmBase/configure.ac 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/IlmBase/configure.ac 2020-12-30 23:09:11.000000000 +0000 @@ -4,11 +4,11 @@ dnl dnl Process this file with autoconf to produce a configure script. -AC_INIT(IlmBase, 2.5.3) +AC_INIT(IlmBase, 2.5.4) AC_SUBST(ILMBASE_VERSION_MAJOR, 2) AC_SUBST(ILMBASE_VERSION_MINOR, 5) -AC_SUBST(ILMBASE_VERSION_PATCH, 3) +AC_SUBST(ILMBASE_VERSION_PATCH, 4) AC_SUBST(ILMBASE_VERSION, ${ILMBASE_VERSION_MAJOR}.${ILMBASE_VERSION_MINOR}.${ILMBASE_VERSION_PATCH}) AC_SUBST(ILMBASE_VERSION_API, ${ILMBASE_VERSION_MAJOR}_${ILMBASE_VERSION_MINOR}) @@ -22,7 +22,7 @@ LIBTOOL_CURRENT=25 -LIBTOOL_REVISION=2 +LIBTOOL_REVISION=3 LIBTOOL_AGE=0 LIBTOOL_VERSION=$LIBTOOL_CURRENT:$LIBTOOL_REVISION:$LIBTOOL_AGE AC_SUBST(LIBTOOL_VERSION) diff -Nru openexr-2.5.3/OpenEXR/configure.ac openexr-2.5.4/OpenEXR/configure.ac --- openexr-2.5.3/OpenEXR/configure.ac 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/configure.ac 2020-12-30 23:09:11.000000000 +0000 @@ -5,12 +5,12 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT(OpenEXR, 2.5.3) +AC_INIT(OpenEXR, 2.5.4) AC_CONFIG_MACRO_DIR([m4]) AC_SUBST(OPENEXR_VERSION_MAJOR, 2) AC_SUBST(OPENEXR_VERSION_MINOR, 5) -AC_SUBST(OPENEXR_VERSION_PATCH, 3) +AC_SUBST(OPENEXR_VERSION_PATCH, 4) AC_SUBST(OPENEXR_VERSION, ${OPENEXR_VERSION_MAJOR}.${OPENEXR_VERSION_MINOR}.${OPENEXR_VERSION_PATCH}) AC_SUBST(OPENEXR_VERSION_API, ${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}) @@ -24,7 +24,7 @@ LIBTOOL_CURRENT=25 -LIBTOOL_REVISION=2 +LIBTOOL_REVISION=3 LIBTOOL_AGE=0 LIBTOOL_VERSION=$LIBTOOL_CURRENT:$LIBTOOL_REVISION:$LIBTOOL_AGE AC_SUBST(LIBTOOL_VERSION) diff -Nru openexr-2.5.3/OpenEXR/exrmaketiled/main.cpp openexr-2.5.4/OpenEXR/exrmaketiled/main.cpp --- openexr-2.5.3/OpenEXR/exrmaketiled/main.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/exrmaketiled/main.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -393,31 +393,32 @@ int exitStatus = 0; - // - // check input - // + try { - MultiPartInputFile input (inFile); - int parts = input.parts(); + // + // check input + // + { + MultiPartInputFile input (inFile); + int parts = input.parts(); - if (partnum < 0 || partnum >= parts){ - cerr << "ERROR: you asked for part " << partnum << " in " << inFile; - cerr << ", which only has " << parts << " parts\n"; - exit(1); - } + if (partnum < 0 || partnum >= parts){ + cerr << "ERROR: you asked for part " << partnum << " in " << inFile; + cerr << ", which only has " << parts << " parts\n"; + exit(1); + } + + Header h = input.header (partnum); + if (h.type() == DEEPTILE || h.type() == DEEPSCANLINE) + { + cerr << "Cannot make tile for deep data" << endl; + exit(1); + } - Header h = input.header (partnum); - if (h.type() == DEEPTILE || h.type() == DEEPSCANLINE) - { - cerr << "Cannot make tile for deep data" << endl; - exit(1); } - } - try - { makeTiled (inFile, outFile, partnum, mode, roundingMode, compression, tileSizeX, tileSizeY, diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfB44Compressor.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfB44Compressor.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfB44Compressor.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfB44Compressor.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -381,26 +381,26 @@ s[ 0] = (b[0] << 8) | b[1]; unsigned short shift = (b[ 2] >> 2); - unsigned short bias = (0x20 << shift); + unsigned short bias = (0x20u << shift); - s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias; - s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias; - s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias; + s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3fu) << shift) - bias; + s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3fu) << shift) - bias; + s[12] = s[ 8] + ((b[ 4] & 0x3fu) << shift) - bias; - s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias; - s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias; - s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias; - s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias; + s[ 1] = s[ 0] + ((unsigned int) (b[ 5] >> 2) << shift) - bias; + s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3fu) << shift) - bias; + s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3fu) << shift) - bias; + s[13] = s[12] + ((b[ 7] & 0x3fu) << shift) - bias; - s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias; - s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias; - s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias; - s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias; + s[ 2] = s[ 1] + ((unsigned int)(b[ 8] >> 2) << shift) - bias; + s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3fu) << shift) - bias; + s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3fu) << shift) - bias; + s[14] = s[13] + ((b[10] & 0x3fu) << shift) - bias; - s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias; - s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias; - s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias; - s[15] = s[14] + ((b[13] & 0x3f) << shift) - bias; + s[ 3] = s[ 2] + ((unsigned int)(b[11] >> 2) << shift) - bias; + s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3fu) << shift) - bias; + s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3fu) << shift) - bias; + s[15] = s[14] + ((b[13] & 0x3fu) << shift) - bias; for (int i = 0; i < 16; ++i) { @@ -494,7 +494,7 @@ // _tmpBuffer = new unsigned short - [checkArraySize (uiMult (maxScanLineSize, numScanLines), + [checkArraySize (uiMult (maxScanLineSize / sizeof(unsigned short), numScanLines), sizeof (unsigned short))]; const ChannelList &channels = header().channels(); @@ -951,7 +951,10 @@ if (inSize < 3) notEnoughData(); - if (((const unsigned char *)inPtr)[2] == 0xfc) + // + // If shift exponent is 63, call unpack14 (ignoring unused bits) + // + if (((const unsigned char *)inPtr)[2] >= (13<<2) ) { unpack3 ((const unsigned char *)inPtr, s); inPtr += 3; diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfDeepImageStateAttribute.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -58,6 +58,12 @@ void DeepImageStateAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const +#if defined (__clang__) + // _value may be an invalid value, which the clang sanitizer reports + // as undefined behavior, even though the value is acceptable in this + // context. + __attribute__((no_sanitize ("undefined"))) +#endif { unsigned char tmp = _value; Xdr::write (os, tmp); diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfDeepScanLineInputFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -721,10 +721,12 @@ int width = (_ifd->maxX - _ifd->minX + 1); + ptrdiff_t base = reinterpret_cast(&_ifd->sampleCount[0][0]); + base -= sizeof(unsigned int)*_ifd->minX; + base -= sizeof(unsigned int)*static_cast(_ifd->minY) * static_cast(width); + copyIntoDeepFrameBuffer (readPtr, slice.base, - (char*) (&_ifd->sampleCount[0][0] - - _ifd->minX - - _ifd->minY * width), + reinterpret_cast(base), sizeof(unsigned int) * 1, sizeof(unsigned int) * width, y, _ifd->minX, _ifd->maxX, diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfDeepTiledInputFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -990,8 +990,8 @@ for (size_t i = 0; i < _data->tileBuffers.size(); i++) _data->tileBuffers[i] = new TileBuffer (); - _data->maxSampleCountTableSize = _data->tileDesc.ySize * - _data->tileDesc.xSize * + _data->maxSampleCountTableSize = static_cast(_data->tileDesc.ySize) * + static_cast(_data->tileDesc.xSize) * sizeof(int); _data->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize); diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfDwaCompressor.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfDwaCompressor.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfDwaCompressor.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfDwaCompressor.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -2535,7 +2535,7 @@ if (acCompressedSize > 0) { - if (totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize) + if ( !_packedAcBuffer || totalAcUncompressedCount*sizeof(unsigned short) > _packedAcBufferSize) { throw IEX_NAMESPACE::InputExc("Error uncompressing DWA data" "(corrupt header)."); @@ -2681,6 +2681,10 @@ int gChan = _cscSets[csc].idx[1]; int bChan = _cscSets[csc].idx[2]; + if (_channelData[rChan].compression != LOSSY_DCT || _channelData[gChan].compression != LOSSY_DCT || _channelData[bChan].compression != LOSSY_DCT) + { + throw IEX_NAMESPACE::BaseExc("Bad DWA compression type detected"); + } LossyDctDecoderCsc decoder (rowPtrs[rChan], diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfEnvmapAttribute.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -57,6 +57,12 @@ template <> void EnvmapAttribute::writeValueTo (OPENEXR_IMF_INTERNAL_NAMESPACE::OStream &os, int version) const +#if defined (__clang__) + // _value may be an invalid value, which the clang sanitizer reports + // as undefined behavior, even though the value is acceptable in this + // context. + __attribute__((no_sanitize ("undefined"))) +#endif { unsigned char tmp = _value; Xdr::write (os, tmp); diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfFastHuf.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfFastHuf.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfFastHuf.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfFastHuf.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -127,7 +127,7 @@ for (Int64 symbol = static_cast(minSymbol); symbol <= static_cast(maxSymbol); symbol++) { - if (currByte - table > numBytes) + if (currByte - table >= numBytes) { throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table " "(Truncated table data)."); @@ -144,7 +144,7 @@ if (codeLen == (Int64) LONG_ZEROCODE_RUN) { - if (currByte - table > numBytes) + if (currByte - table >= numBytes) { throw IEX_NAMESPACE::InputExc ("Error decoding Huffman table " "(Truncated table data)."); @@ -205,7 +205,7 @@ for (int l = _minCodeLength; l <= _maxCodeLength; ++l) { countTmp[l] = (double)codeCount[l] * - (double)(2 << (_maxCodeLength-l)); + (double)(2ll << (_maxCodeLength-l)); } for (int l = _minCodeLength; l <= _maxCodeLength; ++l) @@ -215,7 +215,7 @@ for (int k =l + 1; k <= _maxCodeLength; ++k) tmp += countTmp[k]; - tmp /= (double)(2 << (_maxCodeLength - l)); + tmp /= (double)(2ll << (_maxCodeLength - l)); base[l] = (Int64)ceil (tmp); } @@ -538,18 +538,24 @@ buffer |= bufferBack >> (64 - numBits); } - - bufferBack = bufferBack << numBits; - bufferBackNumBits -= numBits; - // - // We can have cases where the previous shift of bufferBack is << 64 - - // in which case no shift occurs. The bit count math still works though, - // so if we don't have any bits left, zero out bufferBack. + + // + // We can have cases where the previous shift of bufferBack is << 64 - + // this is an undefined operation but tends to create just zeroes. + // so if we won't have any bits left, zero out bufferBack insetad of computing the shift // - if (bufferBackNumBits == 0) + if (bufferBackNumBits <= numBits) + { bufferBack = 0; + }else + { + bufferBack = bufferBack << numBits; + } + bufferBackNumBits -= numBits; + + } // diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfHuf.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfHuf.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfHuf.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfHuf.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -910,6 +910,11 @@ // lc -= pl.len; + + if ( lc < 0 ) + { + invalidCode(); // code length too long + } getCode (pl.lit, rlc, c, lc, in, out, outb, oe); } else @@ -967,6 +972,10 @@ if (pl.len) { lc -= pl.len; + if ( lc < 0 ) + { + invalidCode(); // code length too long + } getCode (pl.lit, rlc, c, lc, in, out, outb, oe); } else @@ -1093,7 +1102,9 @@ const char *ptr = compressed + 20; - if ( ptr + (nBits+7 )/8 > compressed+nCompressed) + uint64_t nBytes = (static_cast(nBits)+7) / 8 ; + + if ( ptr + nBytes > compressed+nCompressed) { notEnoughData(); return; diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfInputFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfInputFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfInputFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfInputFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -278,9 +278,14 @@ // // We don't have any valid buffered info, so we need to read in // from the file. + // if no channels are being read that are present in file, cachedBuffer will be empty // - ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j); + if (ifd->cachedBuffer && ifd->cachedBuffer->begin() != ifd->cachedBuffer->end()) + { + ifd->tFile->readTiles (0, ifd->tFile->numXTiles (0) - 1, j, j); + } + ifd->cachedTileY = j; } @@ -289,55 +294,133 @@ // framebuffer. // - for (FrameBuffer::ConstIterator k = ifd->cachedBuffer->begin(); - k != ifd->cachedBuffer->end(); + for (FrameBuffer::ConstIterator k = ifd->tFileBuffer.begin(); + k != ifd->tFileBuffer.end(); ++k) { - Slice fromSlice = k.slice(); // slice to write from - Slice toSlice = ifd->tFileBuffer[k.name()]; // slice to write to - char *fromPtr, *toPtr; - int size = pixelTypeSize (toSlice.type); - int xStart = levelRange.min.x; - int yStart = minYThisRow; + Slice toSlice = k.slice(); // slice to read from + char* toPtr; + + int xStart = levelRange.min.x; + int yStart = minYThisRow; - while (modp (xStart, toSlice.xSampling) != 0) - ++xStart; + while (modp (xStart, toSlice.xSampling) != 0) + ++xStart; - while (modp (yStart, toSlice.ySampling) != 0) - ++yStart; + while (modp (yStart, toSlice.ySampling) != 0) + ++yStart; - for (int y = yStart; - y <= maxYThisRow; - y += toSlice.ySampling) + FrameBuffer::ConstIterator c = ifd->cachedBuffer->find(k.name()); + + + if( c!=ifd->cachedBuffer->end()) { - // - // Set the pointers to the start of the y scanline in - // this row of tiles - // - - fromPtr = fromSlice.base + - (y - tileRange.min.y) * fromSlice.yStride + - xStart * fromSlice.xStride; - - toPtr = toSlice.base + - divp (y, toSlice.ySampling) * toSlice.yStride + - divp (xStart, toSlice.xSampling) * toSlice.xStride; - - // - // Copy all pixels for the scanline in this row of tiles - // - - for (int x = xStart; - x <= levelRange.max.x; - x += toSlice.xSampling) + // + // output channel was read from source image: copy to output slice + // + Slice fromSlice = c.slice(); // slice to write to + + int size = pixelTypeSize (toSlice.type); + char* fromPtr; + + for (int y = yStart; + y <= maxYThisRow; + y += toSlice.ySampling) { - for (int i = 0; i < size; ++i) - toPtr[i] = fromPtr[i]; + // + // Set the pointers to the start of the y scanline in + // this row of tiles + // + + fromPtr = fromSlice.base + + (y - tileRange.min.y) * fromSlice.yStride + + xStart * fromSlice.xStride; + + toPtr = toSlice.base + + divp (y, toSlice.ySampling) * toSlice.yStride + + divp (xStart, toSlice.xSampling) * toSlice.xStride; + + // + // Copy all pixels for the scanline in this row of tiles + // + + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + for (int i = 0; i < size; ++i) + toPtr[i] = fromPtr[i]; + + fromPtr += fromSlice.xStride * toSlice.xSampling; + toPtr += toSlice.xStride; + } + } + } + else + { + + // + // channel wasn't present in source file: fill output slice + // + for (int y = yStart; + y <= maxYThisRow; + y += toSlice.ySampling) + { + + toPtr = toSlice.base + + divp (y, toSlice.ySampling) * toSlice.yStride + + divp (xStart, toSlice.xSampling) * toSlice.xStride; + + // + // Copy all pixels for the scanline in this row of tiles + // + + switch ( toSlice.type) + { + case UINT: + { + unsigned int fill = toSlice.fillValue; + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + * reinterpret_cast(toPtr) = fill; + toPtr += toSlice.xStride; + } + break; + } + case HALF : + { + half fill = toSlice.fillValue; + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + * reinterpret_cast(toPtr) = fill; + toPtr += toSlice.xStride; + } + break; + } + case FLOAT : + { + float fill = toSlice.fillValue; + for (int x = xStart; + x <= levelRange.max.x; + x += toSlice.xSampling) + { + * reinterpret_cast(toPtr) = fill; + toPtr += toSlice.xStride; + } + break; + } + case NUM_PIXELTYPES : + { + break; + } - fromPtr += fromSlice.xStride * toSlice.xSampling; - toPtr += toSlice.xStride; + } } } } @@ -373,6 +456,14 @@ _data->_streamData->is = is; _data->header.readFrom (*_data->_streamData->is, _data->version); + if(isNonImage(_data->version)) + { + if(!_data->header.hasType()) + { + throw(IEX_NAMESPACE::InputExc("Non-image files must have a 'type' attribute")); + } + } + // fix type attribute in single part regular image types // (may be wrong if an old version of OpenEXR converts // a tiled image to scanline or vice versa) @@ -441,6 +532,14 @@ _data->_streamData->is = &is; _data->header.readFrom (*_data->_streamData->is, _data->version); + if(isNonImage(_data->version)) + { + if(!_data->header.hasType()) + { + throw(IEX_NAMESPACE::InputExc("Non-image files must have a 'type' attribute")); + } + } + // fix type attribute in single part regular image types // (may be wrong if an old version of OpenEXR converts // a tiled image to scanline or vice versa) @@ -703,60 +802,67 @@ { Slice s = k.slice(); - switch (s.type) - { - case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: - - _data->cachedBuffer->insert - (k.name(), - Slice (UINT, - (char *)(new unsigned int[tileRowSize] - - _data->offset), - sizeof (unsigned int), - sizeof (unsigned int) * - _data->tFile->levelWidth(0), - 1, 1, - s.fillValue, - false, true)); - break; - - case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: - - _data->cachedBuffer->insert - (k.name(), - Slice (HALF, - (char *)(new half[tileRowSize] - - _data->offset), - sizeof (half), - sizeof (half) * - _data->tFile->levelWidth(0), - 1, 1, - s.fillValue, - false, true)); - break; - - case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: - - _data->cachedBuffer->insert - (k.name(), - Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, - (char *)(new float[tileRowSize] - - _data->offset), - sizeof(float), - sizeof(float) * - _data->tFile->levelWidth(0), - 1, 1, - s.fillValue, - false, true)); - break; + // + // omit adding channels that are not listed - 'fill' channels are added later + // + if ( _data->header.channels().find(k.name()) != _data->header.channels().end() ) + { + switch (s.type) + { + case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: + + _data->cachedBuffer->insert + (k.name(), + Slice (UINT, + (char *)(new unsigned int[tileRowSize] - + _data->offset), + sizeof (unsigned int), + sizeof (unsigned int) * + _data->tFile->levelWidth(0), + 1, 1, + s.fillValue, + false, true)); + break; + + case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF: + + _data->cachedBuffer->insert + (k.name(), + Slice (HALF, + (char *)(new half[tileRowSize] - + _data->offset), + sizeof (half), + sizeof (half) * + _data->tFile->levelWidth(0), + 1, 1, + s.fillValue, + false, true)); + break; + + case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT: + + _data->cachedBuffer->insert + (k.name(), + Slice (OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT, + (char *)(new float[tileRowSize] - + _data->offset), + sizeof(float), + sizeof(float) * + _data->tFile->levelWidth(0), + 1, 1, + s.fillValue, + false, true)); + break; - default: + default: - throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type."); - } + throw IEX_NAMESPACE::ArgExc ("Unknown pixel data type."); + } + } } _data->tFile->setFrameBuffer (*_data->cachedBuffer); + } _data->tFileBuffer = frameBuffer; diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfMultiPartInputFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -340,6 +340,11 @@ // Perform usual check on headers. // + if ( _data->_headers.size() == 0) + { + throw IEX_NAMESPACE::ArgExc ("Files must contain at least one header"); + } + for (size_t i = 0; i < _data->_headers.size(); i++) { // diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfPizCompressor.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfPizCompressor.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfPizCompressor.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfPizCompressor.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -594,7 +594,7 @@ int length; Xdr::read (inPtr, length); - if (length > inSize) + if (inPtr + length > inputEnd || length<0 ) { throw InputExc ("Error in header for PIZ-compressed data " "(invalid array length)."); diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfRgbaFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfRgbaFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfRgbaFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfRgbaFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -1180,7 +1180,7 @@ { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1192,7 +1192,7 @@ { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1207,7 +1207,7 @@ { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1222,7 +1222,7 @@ { RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); } @@ -1249,27 +1249,42 @@ FrameBuffer fb; - fb.insert (_channelNamePrefix + "R", - Slice (HALF, - (char *) &base[0].r, - xs, ys, - 1, 1, // xSampling, ySampling - 0.0)); // fillValue + if( channels() & WRITE_Y ) + { + fb.insert (_channelNamePrefix + "Y", + Slice (HALF, + (char *) &base[0].r, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue + } + else + { + + + fb.insert (_channelNamePrefix + "R", + Slice (HALF, + (char *) &base[0].r, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue - fb.insert (_channelNamePrefix + "G", - Slice (HALF, - (char *) &base[0].g, - xs, ys, - 1, 1, // xSampling, ySampling - 0.0)); // fillValue - fb.insert (_channelNamePrefix + "B", - Slice (HALF, - (char *) &base[0].b, - xs, ys, - 1, 1, // xSampling, ySampling - 0.0)); // fillValue + fb.insert (_channelNamePrefix + "G", + Slice (HALF, + (char *) &base[0].g, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue + + fb.insert (_channelNamePrefix + "B", + Slice (HALF, + (char *) &base[0].b, + xs, ys, + 1, 1, // xSampling, ySampling + 0.0)); // fillValue + } fb.insert (_channelNamePrefix + "A", Slice (HALF, (char *) &base[0].a, @@ -1292,7 +1307,7 @@ RgbaChannels rgbaChannels = channels(); - if (rgbaChannels & (WRITE_Y | WRITE_C)) + if (rgbaChannels & WRITE_C) _fromYca = new FromYca (*_inputFile, rgbaChannels); FrameBuffer fb; @@ -1311,6 +1326,28 @@ else { _inputFile->readPixels (scanLine1, scanLine2); + + if (channels() & WRITE_Y) + { + // + // Luma channel has been written into red channel + // Duplicate into green and blue channel to create gray image + // + const Slice* s = _inputFile->frameBuffer().findSlice(_channelNamePrefix + "Y"); + Box2i dataWindow = _inputFile->header().dataWindow(); + + for( int scanLine = scanLine1 ; scanLine <= scanLine2 ; scanLine++ ) + { + char* rowBase = s->base + scanLine*s->yStride; + for(int x = dataWindow.min.x ; x <= dataWindow.max.x ; ++x ) + { + Rgba* pixel = reinterpret_cast(rowBase+x*s->xStride); + pixel->g = pixel->r; + pixel->b = pixel->r; + } + + } + } } } diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfScanLineInputFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfScanLineInputFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfScanLineInputFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfScanLineInputFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -1145,6 +1145,10 @@ for (size_t i = 0; i < _data->lineBuffers.size(); i++) { _data->lineBuffers[i]->buffer = (char *) EXRAllocAligned(_data->lineBufferSize*sizeof(char),16); + if (!_data->lineBuffers[i]->buffer) + { + throw IEX_NAMESPACE::LogicExc("Failed to allocate memory for scanline buffers"); + } } } _data->nextLineBufferMinY = _data->minY - 1; diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfTiledInputFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfTiledInputFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfTiledInputFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfTiledInputFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -958,7 +958,10 @@ { if (!isTiled (_data->version)) throw IEX_NAMESPACE::ArgExc ("Expected a tiled file but the file is not tiled."); - + + if (isNonImage (_data->version)) + throw IEX_NAMESPACE::ArgExc ("File is not a regular tiled image."); + } else { @@ -1000,6 +1003,16 @@ _data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize; // + // OpenEXR has a limit of INT_MAX compressed bytes per tile + // disallow uncompressed tile sizes above INT_MAX too to guarantee file is written + // + if( _data->tileBufferSize > INT_MAX ) + { + throw IEX_NAMESPACE::ArgExc ("Tile size too large for OpenEXR format"); + } + + + // // Create all the TileBuffers and allocate their internal buffers // diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfTiledMisc.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfTiledMisc.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfTiledMisc.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfTiledMisc.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -97,13 +97,14 @@ V2i tileMin = V2i (minX + dx * tileDesc.xSize, minY + dy * tileDesc.ySize); - V2i tileMax = tileMin + V2i (tileDesc.xSize - 1, tileDesc.ySize - 1); + int64_t tileMaxX = int64_t(tileMin[0]) + tileDesc.xSize - 1; + int64_t tileMaxY = int64_t(tileMin[1]) + tileDesc.ySize - 1; V2i levelMax = dataWindowForLevel (tileDesc, minX, maxX, minY, maxY, lx, ly).max; - tileMax = V2i (std::min (tileMax[0], levelMax[0]), - std::min (tileMax[1], levelMax[1])); + V2i tileMax = V2i (std::min (tileMaxX, int64_t(levelMax[0])), + std::min (tileMaxY, int64_t(levelMax[1]))); return Box2i (tileMin, tileMax); } @@ -301,10 +302,8 @@ { for (int i = 0; i < numLevels; i++) { - int l = levelSize (min, max, i, rmode); - if (l > std::numeric_limits::max() - size + 1) - throw IEX_NAMESPACE::ArgExc ("Invalid size."); - + // use 64 bits to avoid int overflow if size is large. + Int64 l = levelSize (min, max, i, rmode); numTiles[i] = (l + size - 1) / size; } } diff -Nru openexr-2.5.3/OpenEXR/IlmImf/ImfTiledOutputFile.cpp openexr-2.5.4/OpenEXR/IlmImf/ImfTiledOutputFile.cpp --- openexr-2.5.3/OpenEXR/IlmImf/ImfTiledOutputFile.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImf/ImfTiledOutputFile.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -1035,6 +1035,17 @@ _data->tileBufferSize = _data->maxBytesPerTileLine * _data->tileDesc.ySize; + // + // OpenEXR has a limit of INT_MAX compressed bytes per tile + // disallow uncompressed tile sizes above INT_MAX too to guarantee file is written + // + if( _data->tileBufferSize > INT_MAX ) + { + throw IEX_NAMESPACE::ArgExc ("Tile size too large for OpenEXR format"); + } + + + // // Create all the TileBuffers and allocate their internal buffers // diff -Nru openexr-2.5.3/OpenEXR/IlmImfTest/testHuf.cpp openexr-2.5.4/OpenEXR/IlmImfTest/testHuf.cpp --- openexr-2.5.3/OpenEXR/IlmImfTest/testHuf.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImfTest/testHuf.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -245,70 +245,86 @@ IMATH_NAMESPACE::Rand48 rand48 (0); - const int N = 1000000; - Array raw (N); + // + // FastHufDecoder is used for more than 128 bits, so first test with fewer than 128 bits, + // then test FastHufDecoder + // + for (int pass = 0 ; pass < 2 ; ++pass) + { + + int N = pass==0 ? 12 : 1000000; + Array raw (N); + + fill1 (raw, N, 1, rand48); // test various symbol distributions + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill1 (raw, N, 10, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill1 (raw, N, 100, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill1 (raw, N, 1000, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + fill2 (raw, N, 1, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill2 (raw, N, 10, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill2 (raw, N, 100, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill2 (raw, N, 1000, rand48); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + fill3 (raw, N, 0); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill3 (raw, N, 1); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill3 (raw, N, USHRT_MAX - 1); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + fill3 (raw, N, USHRT_MAX); + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + if (pass==1) + { + fill4 (raw, USHRT_MAX + 1); + compressVerify(raw, USHRT_MAX + 1, HUF_COMPRESS_DEK_HASH_FOR_FILL4_USHRT_MAX_PLUS_ONE); + + compressUncompress (raw, USHRT_MAX + 1); + compressUncompressSubset (raw, USHRT_MAX + 1); + fill4 (raw, N); + compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL4_N); + } + compressUncompress (raw, N); + compressUncompressSubset (raw, N); + + fill4 (raw, 0); + compressUncompress (raw, 0); // test small input data sets + fill4 (raw, 1); + compressUncompress (raw, 1); + fill4 (raw, 2); + compressUncompress (raw, 2); + fill4 (raw, 3); + compressUncompress (raw, 3); + + fill5 (raw, N); // test run-length coding of code table + if (pass==1) + { + compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL5_N); + } + compressUncompress (raw, N); + compressUncompressSubset (raw, N); - fill1 (raw, N, 1, rand48); // test various symbol distributions - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill1 (raw, N, 10, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill1 (raw, N, 100, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill1 (raw, N, 1000, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill2 (raw, N, 1, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill2 (raw, N, 10, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill2 (raw, N, 100, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill2 (raw, N, 1000, rand48); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill3 (raw, N, 0); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill3 (raw, N, 1); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill3 (raw, N, USHRT_MAX - 1); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - fill3 (raw, N, USHRT_MAX); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill4 (raw, USHRT_MAX + 1); - compressVerify(raw, USHRT_MAX + 1, HUF_COMPRESS_DEK_HASH_FOR_FILL4_USHRT_MAX_PLUS_ONE); - compressUncompress (raw, USHRT_MAX + 1); - compressUncompressSubset (raw, USHRT_MAX + 1); - fill4 (raw, N); - compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL4_N); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); - - fill4 (raw, 0); - compressUncompress (raw, 0); // test small input data sets - fill4 (raw, 1); - compressUncompress (raw, 1); - fill4 (raw, 2); - compressUncompress (raw, 2); - fill4 (raw, 3); - compressUncompress (raw, 3); - - fill5 (raw, N); // test run-length coding of code table - compressVerify(raw, N, HUF_COMPRESS_DEK_HASH_FOR_FILL5_N); - compressUncompress (raw, N); - compressUncompressSubset (raw, N); + } cout << "ok\n" << endl; } diff -Nru openexr-2.5.3/OpenEXR/IlmImfTest/testScanLineApi.cpp openexr-2.5.4/OpenEXR/IlmImfTest/testScanLineApi.cpp --- openexr-2.5.3/OpenEXR/IlmImfTest/testScanLineApi.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImfTest/testScanLineApi.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -93,7 +93,9 @@ int yOffset, Compression comp, LevelMode mode, - LevelRoundingMode rmode) + LevelRoundingMode rmode, + bool fillChannel + ) { // // Write the pixel data in pi1, ph1 and ph2 to a tiled @@ -263,6 +265,16 @@ Array2D ph2 (h, w); Array2D pf2 (h, w); + Array2D fi2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D fh2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D ff2 (fillChannel ? h : 1 , fillChannel ? w : 1); + + + const unsigned int fillInt = 12; + const half fillHalf = 4.5; + const float fillFloat = M_PI; + + FrameBuffer fb; fb.insert ("I", // name @@ -286,6 +298,30 @@ sizeof (pf2[0][0]) * w) // yStride ); + if(fillChannel) + { + fb.insert ("FI", // name + Slice (IMF::UINT, // type + (char *) &fi2[-dwy][-dwx],// base + sizeof (fi2[0][0]), // xStride + sizeof (fi2[0][0]) * w,1,1,fillInt) // yStride + ); + + fb.insert ("FH", // name + Slice (IMF::HALF, // type + (char *) &fh2[-dwy][-dwx],// base + sizeof (fh2[0][0]), // xStride + sizeof (fh2[0][0]) * w,1,1,fillHalf) // yStride + ); + + fb.insert ("FF", // name + Slice (IMF::FLOAT, // type + (char *) &ff2[-dwy][-dwx],// base + sizeof (ff2[0][0]), // xStride + sizeof (ff2[0][0]) * w,1,1,fillFloat) // yStride + ); + } + in.setFrameBuffer (fb); for (int y = dw.min.y; y <= dw.max.y; ++y) in.readPixels (y); @@ -323,6 +359,13 @@ assert (pi1[y][x] == pi2[y][x]); assert (ph1[y][x] == ph2[y][x]); assert (pf1[y][x] == pf2[y][x]); + + if (fillChannel) + { + assert(fi2[y][x] == fillInt); + assert(fh2[y][x] == fillHalf); + assert(ff2[y][x] == fillFloat); + } } } } @@ -342,6 +385,10 @@ Array2D ph2 (h, w); Array2D pf2 (h, w); + Array2D fi2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D fh2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D ff2 (fillChannel ? h : 1 , fillChannel ? w : 1); + FrameBuffer fb; fb.insert ("I", // name @@ -364,6 +411,34 @@ sizeof (pf2[0][0]), // xStride sizeof (pf2[0][0]) * w) // yStride ); + const unsigned int fillInt = 21; + const half fillHalf = 42; + const float fillFloat = 2.8; + + if (fillChannel) + { + fb.insert ("FI", // name + Slice (IMF::UINT, // type + (char *) &fi2[-dwy][-dwx],// base + sizeof (fi2[0][0]), // xStride + sizeof (fi2[0][0]) * w,1,1,fillInt) // yStride + ); + + fb.insert ("FH", // name + Slice (IMF::HALF, // type + (char *) &fh2[-dwy][-dwx],// base + sizeof (fh2[0][0]), // xStride + sizeof (fh2[0][0]) * w,1,1,fillHalf) // yStride + ); + + fb.insert ("FF", // name + Slice (IMF::FLOAT, // type + (char *) &ff2[-dwy][-dwx],// base + sizeof (ff2[0][0]), // xStride + sizeof (ff2[0][0]) * w,1,1,fillFloat) // yStride + ); + + } in.setFrameBuffer (fb); for (int y = dw.max.y; y >= dw.min.y; --y) @@ -402,6 +477,12 @@ assert (pi1[y][x] == pi2[y][x]); assert (ph1[y][x] == ph2[y][x]); assert (pf1[y][x] == pf2[y][x]); + if (fillChannel) + { + assert(fi2[y][x] == fillInt); + assert(fh2[y][x] == fillHalf); + assert(ff2[y][x] == fillFloat); + } } } } @@ -422,6 +503,17 @@ Array2D ph2 (h, w); Array2D pf2 (h, w); + + Array2D fi2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D fh2 (fillChannel ? h : 1 , fillChannel ? w : 1); + Array2D ff2 (fillChannel ? h : 1 , fillChannel ? w : 1); + + + const unsigned int fillInt = 81; + const half fillHalf = 0.5; + const float fillFloat = 7.8; + + for (int y = dw.min.y; y <= dw.max.y; ++y) { FrameBuffer fb; @@ -447,6 +539,31 @@ 0) // yStride ); + if (fillChannel) + { + fb.insert ("FI", // name + Slice (IMF::UINT, // type + (char *) &fi2[y - dwy][-dwx], // base + sizeof (fi2[0][0]), // xStride + 0,1,1,fillInt) // yStride + ); + + fb.insert ("FH", // name + Slice (IMF::HALF, // type + (char *) &fh2[y - dwy][-dwx], // base + sizeof (fh2[0][0]), // xStride + 0,1,1,fillHalf) // yStride + ); + + fb.insert ("FF", // name + Slice (IMF::FLOAT, // type + (char *) &ff2[y - dwy][-dwx], // base + sizeof (ff2[0][0]), // xStride + 0,1,1,fillFloat) // yStride + ); + + } + in.setFrameBuffer (fb); in.readPixels (y); } @@ -484,7 +601,14 @@ assert (pi1[y][x] == pi2[y][x]); assert (ph1[y][x] == ph2[y][x]); assert (pf1[y][x] == pf2[y][x]); + if (fillChannel) + { + assert (fi2[y][x] == fillInt); + assert (fh2[y][x] == fillHalf); + assert (ff2[y][x] == fillFloat); + } } + } } @@ -509,11 +633,13 @@ std::string filename = tempDir + "imf_test_scanline_api.exr"; writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, - xSize, ySize, dx, dy, comp, ONE_LEVEL, rmode); + xSize, ySize, dx, dy, comp, ONE_LEVEL, rmode , false); + writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, + xSize, ySize, dx, dy, comp, MIPMAP_LEVELS, rmode , false ); writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, - xSize, ySize, dx, dy, comp, MIPMAP_LEVELS, rmode); + xSize, ySize, dx, dy, comp, RIPMAP_LEVELS, rmode , false); writeRead (pi, ph, pf, filename.c_str(), lorder, W, H, - xSize, ySize, dx, dy, comp, RIPMAP_LEVELS, rmode); + xSize, ySize, dx, dy, comp, ONE_LEVEL, rmode , true); } } // namespace diff -Nru openexr-2.5.3/OpenEXR/IlmImfTest/testYca.cpp openexr-2.5.4/OpenEXR/IlmImfTest/testYca.cpp --- openexr-2.5.3/OpenEXR/IlmImfTest/testYca.cpp 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/OpenEXR/IlmImfTest/testYca.cpp 2020-12-30 23:09:11.000000000 +0000 @@ -195,6 +195,7 @@ else { assert (p1.g == p2.g); + assert (p1.b == p2.b); } if (channels & WRITE_A) diff -Nru openexr-2.5.3/PyIlmBase/configure.ac openexr-2.5.4/PyIlmBase/configure.ac --- openexr-2.5.3/PyIlmBase/configure.ac 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/PyIlmBase/configure.ac 2020-12-30 23:09:11.000000000 +0000 @@ -4,8 +4,8 @@ dnl dnl Process this file with autoconf to produce a configure script. -AC_INIT(PyIlmBase, 2.5.3) -AC_SUBST(PYILMBASE_VERSION, 2.5.3) +AC_INIT(PyIlmBase, 2.5.4) +AC_SUBST(PYILMBASE_VERSION, 2.5.4) AC_CANONICAL_HOST AC_CONFIG_SRCDIR(PyIex/iexmodule.cpp) AC_CONFIG_HEADERS([config/PyIlmBaseConfig.h]) @@ -17,7 +17,7 @@ LIBTOOL_CURRENT=25 -LIBTOOL_REVISION=2 +LIBTOOL_REVISION=3 LIBTOOL_AGE=0 LIBTOOL_VERSION=$LIBTOOL_CURRENT:$LIBTOOL_REVISION:$LIBTOOL_AGE AC_SUBST(LIBTOOL_VERSION) diff -Nru openexr-2.5.3/SECURITY.md openexr-2.5.4/SECURITY.md --- openexr-2.5.3/SECURITY.md 2020-08-12 23:12:07.000000000 +0000 +++ openexr-2.5.4/SECURITY.md 2020-12-30 23:09:11.000000000 +0000 @@ -16,6 +16,9 @@ These vulnerabilities are present in the given versions: +* [CVE-2020-16589](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-16589) 2.0.0, 2.0.1, 2.1.0, 2.2.0, 2.2.1, 2.3.0 +* [CVE-2020-16588](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-16588) 2.0.0, 2.0.1, 2.1.0, 2.2.0, 2.2.1, 2.3.0 +* [CVE-2020-16587](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-16587) 2.0.0, 2.0.1, 2.1.0, 2.2.0, 2.2.1, 2.3.0 * [CVE-2020-15306](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15306) 2.0.0, 2.0.1, 2.1.0, 2.2.0, 2.2.1, 2.3.0, 2.4.0, 2.4.1, 2.5.0, 2.5.1 * [CVE-2020-15305](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15305) 2.0.0, 2.0.1, 2.1.0, 2.2.0, 2.2.1, 2.3.0, 2.4.0, 2.4.1, 2.5.0, 2.5.1 * [CVE-2020-15304](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15304) 2.0.0, 2.0.1, 2.1.0, 2.2.0, 2.2.1, 2.3.0, 2.4.0, 2.4.1, 2.5.0, 2.5.1