From f8967db72e3ad04771dae1e2734be90d78b6b9d127de5e7125058da430688f28 Mon Sep 17 00:00:00 2001 From: Petr Gajdos Date: Wed, 7 Feb 2024 10:50:22 +0000 Subject: [PATCH 1/2] Accepting request 1144872 from home:pgajdos - version update to 3.2.1 ## Version 3.2.0 (August 30, 2023) * Zip compression via ``libdeflate`` * New camdkit/camdkit-enabled standard attributes * Updated SO versioning policy * Python bindings & PyPI wheel * Miscellaneous improvements ## Version 3.2.1 (September 27, 2023) * Fix for linking statically against an external ``libdeflate`` * Fix a compile error with ``OPENEXR_VERSION_HEX`` * Fix various compiler warnings * Pkg-config generation is now on by default for all systems, including Windows - modified sources % baselibs.conf - added patches fix CVE-2023-5841 [bsc#1219498], heap-based buffer overflow in generic_unpack_deep() + openexr-CVE-2023-5841.patch OBS-URL: https://build.opensuse.org/request/show/1144872 OBS-URL: https://build.opensuse.org/package/show/graphics/openexr?expand=0&rev=105 --- baselibs.conf | 10 +- openexr-CVE-2023-5841.patch | 466 ++++++++++++++++++++++++++++++++++++ openexr.changes | 21 ++ openexr.spec | 32 +-- v3.1.11.tar.gz | 3 - v3.2.1.tar.gz | 3 + 6 files changed, 513 insertions(+), 22 deletions(-) create mode 100644 openexr-CVE-2023-5841.patch delete mode 100644 v3.1.11.tar.gz create mode 100644 v3.2.1.tar.gz diff --git a/baselibs.conf b/baselibs.conf index 533e803..1278a5a 100644 --- a/baselibs.conf +++ b/baselibs.conf @@ -1,5 +1,5 @@ -libOpenEXR-3_1-30 -libOpenEXRCore-3_1-30 -libOpenEXRUtil-3_1-30 -libIlmThread-3_1-30 -libIex-3_1-30 +libOpenEXR-3_2-31 +libOpenEXRCore-3_2-31 +libOpenEXRUtil-3_2-31 +libIlmThread-3_2-31 +libIex-3_2-31 diff --git a/openexr-CVE-2023-5841.patch b/openexr-CVE-2023-5841.patch new file mode 100644 index 0000000..b7939ee --- /dev/null +++ b/openexr-CVE-2023-5841.patch @@ -0,0 +1,466 @@ +diff --git a/src/lib/OpenEXRCore/decoding.c b/src/lib/OpenEXRCore/decoding.c +index 322cbd896..710d8a6db 100644 +--- a/src/lib/OpenEXRCore/decoding.c ++++ b/src/lib/OpenEXRCore/decoding.c +@@ -288,6 +288,9 @@ default_decompress_chunk (exr_decode_pipeline_t* decode) + uint64_t sampsize = + (((uint64_t) decode->chunk.width) * + ((uint64_t) decode->chunk.height)); ++ ++ if ((decode->decode_flags & EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) ++ sampsize += 1; + sampsize *= sizeof (int32_t); + + rv = decompress_data ( +@@ -340,7 +343,7 @@ unpack_sample_table ( + exr_result_t rv = EXR_ERR_SUCCESS; + int32_t w = decode->chunk.width; + int32_t h = decode->chunk.height; +- int32_t totsamp = 0; ++ uint64_t totsamp = 0; + int32_t* samptable = decode->sample_count_table; + size_t combSampSize = 0; + +@@ -351,38 +354,44 @@ unpack_sample_table ( + { + for (int32_t y = 0; y < h; ++y) + { ++ int32_t *cursampline = samptable + y * w; + int32_t prevsamp = 0; + for (int32_t x = 0; x < w; ++x) + { + int32_t nsamps = +- (int32_t) one_to_native32 ((uint32_t) samptable[y * w + x]); +- if (nsamps < 0) return EXR_ERR_INVALID_SAMPLE_DATA; +- samptable[y * w + x] = nsamps - prevsamp; +- prevsamp = nsamps; ++ (int32_t) one_to_native32 ((uint32_t) cursampline[x]); ++ if (nsamps < prevsamp) return EXR_ERR_INVALID_SAMPLE_DATA; ++ ++ cursampline[x] = nsamps - prevsamp; ++ prevsamp = nsamps; + } +- totsamp += prevsamp; ++ totsamp += (uint64_t)prevsamp; + } +- samptable[w * h] = totsamp; ++ if (totsamp >= (uint64_t)INT32_MAX) ++ return EXR_ERR_INVALID_SAMPLE_DATA; ++ samptable[w * h] = (int32_t)totsamp; + } + else + { + for (int32_t y = 0; y < h; ++y) + { ++ int32_t *cursampline = samptable + y * w; + int32_t prevsamp = 0; + for (int32_t x = 0; x < w; ++x) + { + int32_t nsamps = +- (int32_t) one_to_native32 ((uint32_t) samptable[y * w + x]); +- if (nsamps < 0) return EXR_ERR_INVALID_SAMPLE_DATA; +- samptable[y * w + x] = nsamps; +- prevsamp = nsamps; ++ (int32_t) one_to_native32 ((uint32_t) cursampline[x]); ++ if (nsamps < prevsamp) return EXR_ERR_INVALID_SAMPLE_DATA; ++ ++ cursampline[x] = nsamps; ++ prevsamp = nsamps; + } +- totsamp += prevsamp; ++ ++ totsamp += (uint64_t)prevsamp; + } + } + +- if (totsamp < 0 || +- (((uint64_t) totsamp) * combSampSize) > decode->chunk.unpacked_size) ++ if ((totsamp * combSampSize) > decode->chunk.unpacked_size) + { + rv = pctxt->report_error ( + pctxt, EXR_ERR_INVALID_SAMPLE_DATA, "Corrupt sample count table"); +diff --git a/src/lib/OpenEXRCore/unpack.c b/src/lib/OpenEXRCore/unpack.c +index b88c98974..1324508c5 100644 +--- a/src/lib/OpenEXRCore/unpack.c ++++ b/src/lib/OpenEXRCore/unpack.c +@@ -1196,9 +1196,10 @@ generic_unpack_deep_pointers (exr_decode_pipeline_t* decode) + if (outpix) + { + uint8_t* cdata = outpix; ++ + UNPACK_SAMPLES (samps) + } +- srcbuffer += bpc * samps; ++ srcbuffer += ((size_t) bpc) * ((size_t) samps); + } + } + sampbuffer += w; +@@ -1242,12 +1243,14 @@ generic_unpack_deep (exr_decode_pipeline_t* decode) + } + else + prevsamps = sampbuffer[w - 1]; ++ + srcbuffer += ((size_t) bpc) * ((size_t) prevsamps); + + if (incr_tot) totsamps += (size_t) prevsamps; + + continue; + } ++ + cdata += totsamps * ((size_t) ubpc); + + for (int x = 0; x < w; ++x) +@@ -1263,7 +1266,7 @@ generic_unpack_deep (exr_decode_pipeline_t* decode) + + UNPACK_SAMPLES (samps) + +- srcbuffer += bpc * samps; ++ srcbuffer += ((size_t) bpc) * ((size_t) samps); + if (incr_tot) totsamps += (size_t) samps; + } + } +@@ -1301,7 +1304,7 @@ internal_exr_match_decode ( + + if (isdeep) + { +- if ((decode->decode_flags & EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) ++ if ((decode->decode_flags & EXR_DECODE_NON_IMAGE_DATA_AS_POINTERS)) + return &generic_unpack_deep_pointers; + return &generic_unpack_deep; + } +diff --git a/src/lib/OpenEXRUtil/ImfCheckFile.cpp b/src/lib/OpenEXRUtil/ImfCheckFile.cpp +index 82f318a92..4d45dad69 100644 +--- a/src/lib/OpenEXRUtil/ImfCheckFile.cpp ++++ b/src/lib/OpenEXRUtil/ImfCheckFile.cpp +@@ -1200,13 +1200,88 @@ runChecks (T& source, bool reduceMemory, bool reduceTime) + return threw; + } + ++// This is not entirely needed in that the chunk info has the ++// total unpacked_size field which can be used for allocation ++// but this adds an additional point to use when debugging issues. ++static exr_result_t ++realloc_deepdata(exr_decode_pipeline_t* decode) ++{ ++ int32_t w = decode->chunk.width; ++ int32_t h = decode->chunk.height; ++ uint64_t totsamps = 0, bytes = 0; ++ const int32_t *sampbuffer = decode->sample_count_table; ++ std::vector* ud = static_cast*>( ++ decode->decoding_user_data); ++ ++ if ( ! ud ) ++ { ++ for (int c = 0; c < decode->channel_count; c++) ++ { ++ exr_coding_channel_info_t& outc = decode->channels[c]; ++ outc.decode_to_ptr = NULL; ++ outc.user_pixel_stride = outc.user_bytes_per_element; ++ outc.user_line_stride = 0; ++ } ++ return EXR_ERR_SUCCESS; ++ } ++ ++ if ((decode->decode_flags & ++ EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) ++ { ++ for (int32_t y = 0; y < h; ++y) ++ { ++ for (int x = 0; x < w; ++x) ++ totsamps += sampbuffer[x]; ++ sampbuffer += w; ++ } ++ } ++ else ++ { ++ for (int32_t y = 0; y < h; ++y) ++ totsamps += sampbuffer[y*w + w - 1]; ++ } ++ ++ for (int c = 0; c < decode->channel_count; c++) ++ { ++ exr_coding_channel_info_t& outc = decode->channels[c]; ++ bytes += totsamps * outc.user_bytes_per_element; ++ } ++ ++ if (bytes >= gMaxBytesPerDeepScanline * h) ++ { ++ for (int c = 0; c < decode->channel_count; c++) ++ { ++ exr_coding_channel_info_t& outc = decode->channels[c]; ++ outc.decode_to_ptr = NULL; ++ outc.user_pixel_stride = outc.user_bytes_per_element; ++ outc.user_line_stride = 0; ++ } ++ return EXR_ERR_SUCCESS; ++ } ++ ++ if (ud->size () < bytes) ++ ud->resize (bytes); ++ ++ uint8_t* dptr = &((*ud)[0]); ++ for (int c = 0; c < decode->channel_count; c++) ++ { ++ exr_coding_channel_info_t& outc = decode->channels[c]; ++ outc.decode_to_ptr = dptr; ++ outc.user_pixel_stride = outc.user_bytes_per_element; ++ outc.user_line_stride = 0; ++ ++ dptr += totsamps * (uint64_t) outc.user_bytes_per_element; ++ } ++ return EXR_ERR_SUCCESS; ++} ++ + //////////////////////////////////////// + + bool + readCoreScanlinePart ( + exr_context_t f, int part, bool reduceMemory, bool reduceTime) + { +- exr_result_t rv; ++ exr_result_t rv, frv; + exr_attr_box2i_t datawin; + rv = exr_get_data_window (f, part, &datawin); + if (rv != EXR_ERR_SUCCESS) return true; +@@ -1224,6 +1299,8 @@ readCoreScanlinePart ( + rv = exr_get_scanlines_per_chunk (f, part, &lines_per_chunk); + if (rv != EXR_ERR_SUCCESS) return true; + ++ frv = rv; ++ + for (uint64_t chunk = 0; chunk < height; chunk += lines_per_chunk) + { + exr_chunk_info_t cinfo = {0}; +@@ -1232,6 +1309,7 @@ readCoreScanlinePart ( + rv = exr_read_scanline_chunk_info (f, part, y, &cinfo); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) break; + continue; + } +@@ -1253,19 +1331,32 @@ readCoreScanlinePart ( + (uint64_t) lines_per_chunk; + } + +- // TODO: check we are supposed to multiple by lines per chunk above + doread = true; +- if (reduceMemory && bytes >= gMaxBytesPerScanline) doread = false; + +- if (doread) imgdata.resize (bytes); ++ if (cinfo.type == EXR_STORAGE_DEEP_SCANLINE) ++ { ++ decoder.decoding_user_data = &imgdata; ++ decoder.realloc_nonimage_data_fn = &realloc_deepdata; ++ } ++ else ++ { ++ if (reduceMemory && bytes >= gMaxBytesPerScanline) doread = false; ++ ++ if (doread) imgdata.resize (bytes); ++ } + rv = exr_decoding_choose_default_routines (f, part, &decoder); +- if (rv != EXR_ERR_SUCCESS) break; ++ if (rv != EXR_ERR_SUCCESS) ++ { ++ frv = rv; ++ break; ++ } + } + else + { + rv = exr_decoding_update (f, part, &cinfo, &decoder); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) break; + continue; + } +@@ -1273,20 +1364,25 @@ readCoreScanlinePart ( + + if (doread) + { +- uint8_t* dptr = &(imgdata[0]); +- for (int c = 0; c < decoder.channel_count; c++) ++ if (cinfo.type != EXR_STORAGE_DEEP_SCANLINE) + { +- exr_coding_channel_info_t& outc = decoder.channels[c]; +- outc.decode_to_ptr = dptr; +- outc.user_pixel_stride = outc.user_bytes_per_element; +- outc.user_line_stride = outc.user_pixel_stride * width; +- dptr += width * (uint64_t) outc.user_bytes_per_element * ++ uint8_t* dptr = &(imgdata[0]); ++ for (int c = 0; c < decoder.channel_count; c++) ++ { ++ exr_coding_channel_info_t& outc = decoder.channels[c]; ++ outc.decode_to_ptr = dptr; ++ outc.user_pixel_stride = outc.user_bytes_per_element; ++ outc.user_line_stride = outc.user_pixel_stride * width; ++ ++ dptr += width * (uint64_t) outc.user_bytes_per_element * + (uint64_t) lines_per_chunk; ++ } + } + + rv = exr_decoding_run (f, part, &decoder); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) break; + } + } +@@ -1294,7 +1390,7 @@ readCoreScanlinePart ( + + exr_decoding_destroy (f, &decoder); + +- return (rv != EXR_ERR_SUCCESS); ++ return (frv != EXR_ERR_SUCCESS); + } + + //////////////////////////////////////// +@@ -1303,7 +1399,7 @@ bool + readCoreTiledPart ( + exr_context_t f, int part, bool reduceMemory, bool reduceTime) + { +- exr_result_t rv; ++ exr_result_t rv, frv; + + exr_attr_box2i_t datawin; + rv = exr_get_data_window (f, part, &datawin); +@@ -1321,6 +1417,7 @@ readCoreTiledPart ( + rv = exr_get_tile_levels (f, part, &levelsx, &levelsy); + if (rv != EXR_ERR_SUCCESS) return true; + ++ frv = rv; + bool keepgoing = true; + for (int32_t ylevel = 0; keepgoing && ylevel < levelsy; ++ylevel) + { +@@ -1330,6 +1427,7 @@ readCoreTiledPart ( + rv = exr_get_level_sizes (f, part, xlevel, ylevel, &levw, &levh); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) + { + keepgoing = false; +@@ -1342,6 +1440,7 @@ readCoreTiledPart ( + rv = exr_get_tile_sizes (f, part, xlevel, ylevel, &curtw, &curth); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) + { + keepgoing = false; +@@ -1371,6 +1470,7 @@ readCoreTiledPart ( + f, part, tx, ty, xlevel, ylevel, &cinfo); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) + { + keepgoing = false; +@@ -1385,6 +1485,7 @@ readCoreTiledPart ( + exr_decoding_initialize (f, part, &cinfo, &decoder); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + keepgoing = false; + break; + } +@@ -1406,14 +1507,23 @@ readCoreTiledPart ( + } + + doread = true; +- if (reduceMemory && bytes >= gMaxTileBytes) +- doread = false; ++ if (cinfo.type == EXR_STORAGE_DEEP_TILED) ++ { ++ decoder.decoding_user_data = &tiledata; ++ decoder.realloc_nonimage_data_fn = &realloc_deepdata; ++ } ++ else ++ { ++ if (reduceMemory && bytes >= gMaxTileBytes) ++ doread = false; + +- if (doread) tiledata.resize (bytes); ++ if (doread) tiledata.resize (bytes); ++ } + rv = exr_decoding_choose_default_routines ( + f, part, &decoder); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + keepgoing = false; + break; + } +@@ -1423,6 +1533,7 @@ readCoreTiledPart ( + rv = exr_decoding_update (f, part, &cinfo, &decoder); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) + { + keepgoing = false; +@@ -1434,24 +1545,28 @@ readCoreTiledPart ( + + if (doread) + { +- uint8_t* dptr = &(tiledata[0]); +- for (int c = 0; c < decoder.channel_count; c++) ++ if (cinfo.type != EXR_STORAGE_DEEP_TILED) + { +- exr_coding_channel_info_t& outc = +- decoder.channels[c]; +- outc.decode_to_ptr = dptr; +- outc.user_pixel_stride = +- outc.user_bytes_per_element; +- outc.user_line_stride = +- outc.user_pixel_stride * curtw; +- dptr += (uint64_t) curtw * ++ uint8_t* dptr = &(tiledata[0]); ++ for (int c = 0; c < decoder.channel_count; c++) ++ { ++ exr_coding_channel_info_t& outc = ++ decoder.channels[c]; ++ outc.decode_to_ptr = dptr; ++ outc.user_pixel_stride = ++ outc.user_bytes_per_element; ++ outc.user_line_stride = ++ outc.user_pixel_stride * curtw; ++ dptr += (uint64_t) curtw * + (uint64_t) outc.user_bytes_per_element * + (uint64_t) curth; ++ } + } + + rv = exr_decoding_run (f, part, &decoder); + if (rv != EXR_ERR_SUCCESS) + { ++ frv = rv; + if (reduceTime) + { + keepgoing = false; +@@ -1486,17 +1601,14 @@ checkCoreFile (exr_context_t f, bool reduceMemory, bool reduceTime) + rv = exr_get_storage (f, p, &store); + if (rv != EXR_ERR_SUCCESS) return true; + +- // TODO: Need to fill this in +- if (store == EXR_STORAGE_DEEP_SCANLINE || +- store == EXR_STORAGE_DEEP_TILED) +- continue; +- +- if (store == EXR_STORAGE_SCANLINE) ++ if (store == EXR_STORAGE_SCANLINE || ++ store == EXR_STORAGE_DEEP_SCANLINE) + { + if (readCoreScanlinePart (f, p, reduceMemory, reduceTime)) + return true; + } +- else if (store == EXR_STORAGE_TILED) ++ else if (store == EXR_STORAGE_TILED || ++ store == EXR_STORAGE_DEEP_TILED) + { + if (readCoreTiledPart (f, p, reduceMemory, reduceTime)) return true; + } + diff --git a/openexr.changes b/openexr.changes index c24cc8d..3e50cd3 100644 --- a/openexr.changes +++ b/openexr.changes @@ -1,3 +1,24 @@ +------------------------------------------------------------------- +Wed Feb 7 10:31:23 UTC 2024 - pgajdos@suse.com + +- version update to 3.2.1 + ## Version 3.2.0 (August 30, 2023) + * Zip compression via ``libdeflate`` + * New camdkit/camdkit-enabled standard attributes + * Updated SO versioning policy + * Python bindings & PyPI wheel + * Miscellaneous improvements + ## Version 3.2.1 (September 27, 2023) + * Fix for linking statically against an external ``libdeflate`` + * Fix a compile error with ``OPENEXR_VERSION_HEX`` + * Fix various compiler warnings + * Pkg-config generation is now on by default for all systems, including Windows +- modified sources + % baselibs.conf +- added patches + fix CVE-2023-5841 [bsc#1219498], heap-based buffer overflow in generic_unpack_deep() + + openexr-CVE-2023-5841.patch + ------------------------------------------------------------------- Thu Aug 24 13:21:39 UTC 2023 - pgajdos@suse.com diff --git a/openexr.spec b/openexr.spec index f27ff9a..195608a 100644 --- a/openexr.spec +++ b/openexr.spec @@ -1,7 +1,7 @@ # # spec file for package openexr # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2024 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,10 +19,10 @@ %define prjname openexr # perhaps you want to build against corresponding Imath build %define debug_build 0 -%define sonum 30 -%global so_suffix -3_1 +%define sonum 31 +%global so_suffix -3_2 Name: openexr -Version: 3.1.11 +Version: 3.2.1 Release: 0 Summary: Utilities for working with HDR images in OpenEXR format License: BSD-3-Clause @@ -30,11 +30,14 @@ Group: Development/Libraries/C and C++ URL: https://www.openexr.com/ Source0: https://github.com/openexr/openexr/archive/v%{version}.tar.gz Source2: baselibs.conf +# CVE-2023-5841 [bsc#1219498], heap-based buffer overflow in generic_unpack_deep() +Patch0: openexr-CVE-2023-5841.patch BuildRequires: cmake >= 3.12 BuildRequires: freeglut-devel BuildRequires: gcc-c++ BuildRequires: pkgconfig BuildRequires: pkgconfig(Imath) +BuildRequires: pkgconfig(libdeflate) BuildRequires: pkgconfig(zlib) Obsoletes: OpenEXR <= 1.6.1 Provides: OpenEXR = %{version} @@ -136,6 +139,7 @@ License: BSD-3-Clause Group: Documentation/Other Obsoletes: OpenEXR-doc <= 1.6.1 Provides: OpenEXR-doc = %{version} +BuildArch: noarch %description doc OpenEXR is a high dynamic-range (HDR) image file format developed by @@ -159,6 +163,16 @@ export CXXFLAGS="%{optflags} -O0" %cmake_install %check +# bin tests download test data from internet +EXCLUDE_REGEX='OpenEXR.bin' +%ifarch ppc64le +# bsc#1205885 +EXCLUDE_REGEX="$EXCLUDE_REGEX|testMultiTiledPartThreading" +%endif +%ifarch aarch64 +# https://github.com/AcademySoftwareFoundation/openexr/issues/1460 +EXCLUDE_REGEX="$EXCLUDE_REGEX|DWA[AB]Compression" +%endif # test failure on LE: https://github.com/AcademySoftwareFoundation/openexr/issues/1460 %ifnarch i586 ppc ppc64 s390 s390x export LD_LIBRARY_PATH="%{buildroot}/%{_libdir}" @@ -166,19 +180,9 @@ export LD_LIBRARY_PATH="%{buildroot}/%{_libdir}" %if 0%{?suse_version} < 1550 # HACK - older versions of the ctest macro do not allow passing additional parameters %global __ctest %{__ctest} --timeout 3600 -%ctest -%else -%ifarch ppc64le -# bsc#1205885 -EXCLUDE_REGEX='testMultiTiledPartThreading' -%endif -%ifarch aarch64 -# https://github.com/AcademySoftwareFoundation/openexr/issues/1460 -EXCLUDE_REGEX='DWA[AB]Compression' %endif %ctest --exclude-regex "$EXCLUDE_REGEX" --timeout 3600 %endif -%endif %post -n libIex%{so_suffix}-%{sonum} -p /sbin/ldconfig %postun -n libIex%{so_suffix}-%{sonum} -p /sbin/ldconfig diff --git a/v3.1.11.tar.gz b/v3.1.11.tar.gz deleted file mode 100644 index c1f6bba..0000000 --- a/v3.1.11.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:06b4a20d0791b5ec0f804c855d320a0615ce8445124f293616a086e093f1f1e1 -size 20539852 diff --git a/v3.2.1.tar.gz b/v3.2.1.tar.gz new file mode 100644 index 0000000..93d2ca6 --- /dev/null +++ b/v3.2.1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61e175aa2203399fb3c8c2288752fbea3c2637680d50b6e306ea5f8ffdd46a9b +size 18824332 From 8deaa0ac78bc75c2341bbe40d61e9948b14b10f1ffecda7781348a2ee8bbb8b5 Mon Sep 17 00:00:00 2001 From: Petr Gajdos Date: Wed, 14 Feb 2024 14:35:59 +0000 Subject: [PATCH 2/2] - version update to 3.2.2 [bsc#1219498] * [CVE-2023-5841](https://takeonme.org/cves/CVE-2023-5841.html). Note that this bug is present in the C++ API (since v3.1.0), although it is in a routine that is predominantly used for development and testing. It is not likely to appear in production code. * OSS-fuzz [66491](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66491) Out-of-memory in openexr_exrcorecheck_fuzzer * OSS-fuzz [66489](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66489) Null-dereference in `Imf_3_3::realloc_deepdata` - deleted patches - openexr-CVE-2023-5841.patch (upstreamed) OBS-URL: https://build.opensuse.org/package/show/graphics/openexr?expand=0&rev=106 --- openexr-CVE-2023-5841.patch | 466 ------------------------------------ openexr.changes | 15 ++ openexr.spec | 4 +- v3.2.1.tar.gz | 3 - v3.2.2.tar.gz | 3 + 5 files changed, 19 insertions(+), 472 deletions(-) delete mode 100644 openexr-CVE-2023-5841.patch delete mode 100644 v3.2.1.tar.gz create mode 100644 v3.2.2.tar.gz diff --git a/openexr-CVE-2023-5841.patch b/openexr-CVE-2023-5841.patch deleted file mode 100644 index b7939ee..0000000 --- a/openexr-CVE-2023-5841.patch +++ /dev/null @@ -1,466 +0,0 @@ -diff --git a/src/lib/OpenEXRCore/decoding.c b/src/lib/OpenEXRCore/decoding.c -index 322cbd896..710d8a6db 100644 ---- a/src/lib/OpenEXRCore/decoding.c -+++ b/src/lib/OpenEXRCore/decoding.c -@@ -288,6 +288,9 @@ default_decompress_chunk (exr_decode_pipeline_t* decode) - uint64_t sampsize = - (((uint64_t) decode->chunk.width) * - ((uint64_t) decode->chunk.height)); -+ -+ if ((decode->decode_flags & EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) -+ sampsize += 1; - sampsize *= sizeof (int32_t); - - rv = decompress_data ( -@@ -340,7 +343,7 @@ unpack_sample_table ( - exr_result_t rv = EXR_ERR_SUCCESS; - int32_t w = decode->chunk.width; - int32_t h = decode->chunk.height; -- int32_t totsamp = 0; -+ uint64_t totsamp = 0; - int32_t* samptable = decode->sample_count_table; - size_t combSampSize = 0; - -@@ -351,38 +354,44 @@ unpack_sample_table ( - { - for (int32_t y = 0; y < h; ++y) - { -+ int32_t *cursampline = samptable + y * w; - int32_t prevsamp = 0; - for (int32_t x = 0; x < w; ++x) - { - int32_t nsamps = -- (int32_t) one_to_native32 ((uint32_t) samptable[y * w + x]); -- if (nsamps < 0) return EXR_ERR_INVALID_SAMPLE_DATA; -- samptable[y * w + x] = nsamps - prevsamp; -- prevsamp = nsamps; -+ (int32_t) one_to_native32 ((uint32_t) cursampline[x]); -+ if (nsamps < prevsamp) return EXR_ERR_INVALID_SAMPLE_DATA; -+ -+ cursampline[x] = nsamps - prevsamp; -+ prevsamp = nsamps; - } -- totsamp += prevsamp; -+ totsamp += (uint64_t)prevsamp; - } -- samptable[w * h] = totsamp; -+ if (totsamp >= (uint64_t)INT32_MAX) -+ return EXR_ERR_INVALID_SAMPLE_DATA; -+ samptable[w * h] = (int32_t)totsamp; - } - else - { - for (int32_t y = 0; y < h; ++y) - { -+ int32_t *cursampline = samptable + y * w; - int32_t prevsamp = 0; - for (int32_t x = 0; x < w; ++x) - { - int32_t nsamps = -- (int32_t) one_to_native32 ((uint32_t) samptable[y * w + x]); -- if (nsamps < 0) return EXR_ERR_INVALID_SAMPLE_DATA; -- samptable[y * w + x] = nsamps; -- prevsamp = nsamps; -+ (int32_t) one_to_native32 ((uint32_t) cursampline[x]); -+ if (nsamps < prevsamp) return EXR_ERR_INVALID_SAMPLE_DATA; -+ -+ cursampline[x] = nsamps; -+ prevsamp = nsamps; - } -- totsamp += prevsamp; -+ -+ totsamp += (uint64_t)prevsamp; - } - } - -- if (totsamp < 0 || -- (((uint64_t) totsamp) * combSampSize) > decode->chunk.unpacked_size) -+ if ((totsamp * combSampSize) > decode->chunk.unpacked_size) - { - rv = pctxt->report_error ( - pctxt, EXR_ERR_INVALID_SAMPLE_DATA, "Corrupt sample count table"); -diff --git a/src/lib/OpenEXRCore/unpack.c b/src/lib/OpenEXRCore/unpack.c -index b88c98974..1324508c5 100644 ---- a/src/lib/OpenEXRCore/unpack.c -+++ b/src/lib/OpenEXRCore/unpack.c -@@ -1196,9 +1196,10 @@ generic_unpack_deep_pointers (exr_decode_pipeline_t* decode) - if (outpix) - { - uint8_t* cdata = outpix; -+ - UNPACK_SAMPLES (samps) - } -- srcbuffer += bpc * samps; -+ srcbuffer += ((size_t) bpc) * ((size_t) samps); - } - } - sampbuffer += w; -@@ -1242,12 +1243,14 @@ generic_unpack_deep (exr_decode_pipeline_t* decode) - } - else - prevsamps = sampbuffer[w - 1]; -+ - srcbuffer += ((size_t) bpc) * ((size_t) prevsamps); - - if (incr_tot) totsamps += (size_t) prevsamps; - - continue; - } -+ - cdata += totsamps * ((size_t) ubpc); - - for (int x = 0; x < w; ++x) -@@ -1263,7 +1266,7 @@ generic_unpack_deep (exr_decode_pipeline_t* decode) - - UNPACK_SAMPLES (samps) - -- srcbuffer += bpc * samps; -+ srcbuffer += ((size_t) bpc) * ((size_t) samps); - if (incr_tot) totsamps += (size_t) samps; - } - } -@@ -1301,7 +1304,7 @@ internal_exr_match_decode ( - - if (isdeep) - { -- if ((decode->decode_flags & EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) -+ if ((decode->decode_flags & EXR_DECODE_NON_IMAGE_DATA_AS_POINTERS)) - return &generic_unpack_deep_pointers; - return &generic_unpack_deep; - } -diff --git a/src/lib/OpenEXRUtil/ImfCheckFile.cpp b/src/lib/OpenEXRUtil/ImfCheckFile.cpp -index 82f318a92..4d45dad69 100644 ---- a/src/lib/OpenEXRUtil/ImfCheckFile.cpp -+++ b/src/lib/OpenEXRUtil/ImfCheckFile.cpp -@@ -1200,13 +1200,88 @@ runChecks (T& source, bool reduceMemory, bool reduceTime) - return threw; - } - -+// This is not entirely needed in that the chunk info has the -+// total unpacked_size field which can be used for allocation -+// but this adds an additional point to use when debugging issues. -+static exr_result_t -+realloc_deepdata(exr_decode_pipeline_t* decode) -+{ -+ int32_t w = decode->chunk.width; -+ int32_t h = decode->chunk.height; -+ uint64_t totsamps = 0, bytes = 0; -+ const int32_t *sampbuffer = decode->sample_count_table; -+ std::vector* ud = static_cast*>( -+ decode->decoding_user_data); -+ -+ if ( ! ud ) -+ { -+ for (int c = 0; c < decode->channel_count; c++) -+ { -+ exr_coding_channel_info_t& outc = decode->channels[c]; -+ outc.decode_to_ptr = NULL; -+ outc.user_pixel_stride = outc.user_bytes_per_element; -+ outc.user_line_stride = 0; -+ } -+ return EXR_ERR_SUCCESS; -+ } -+ -+ if ((decode->decode_flags & -+ EXR_DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL)) -+ { -+ for (int32_t y = 0; y < h; ++y) -+ { -+ for (int x = 0; x < w; ++x) -+ totsamps += sampbuffer[x]; -+ sampbuffer += w; -+ } -+ } -+ else -+ { -+ for (int32_t y = 0; y < h; ++y) -+ totsamps += sampbuffer[y*w + w - 1]; -+ } -+ -+ for (int c = 0; c < decode->channel_count; c++) -+ { -+ exr_coding_channel_info_t& outc = decode->channels[c]; -+ bytes += totsamps * outc.user_bytes_per_element; -+ } -+ -+ if (bytes >= gMaxBytesPerDeepScanline * h) -+ { -+ for (int c = 0; c < decode->channel_count; c++) -+ { -+ exr_coding_channel_info_t& outc = decode->channels[c]; -+ outc.decode_to_ptr = NULL; -+ outc.user_pixel_stride = outc.user_bytes_per_element; -+ outc.user_line_stride = 0; -+ } -+ return EXR_ERR_SUCCESS; -+ } -+ -+ if (ud->size () < bytes) -+ ud->resize (bytes); -+ -+ uint8_t* dptr = &((*ud)[0]); -+ for (int c = 0; c < decode->channel_count; c++) -+ { -+ exr_coding_channel_info_t& outc = decode->channels[c]; -+ outc.decode_to_ptr = dptr; -+ outc.user_pixel_stride = outc.user_bytes_per_element; -+ outc.user_line_stride = 0; -+ -+ dptr += totsamps * (uint64_t) outc.user_bytes_per_element; -+ } -+ return EXR_ERR_SUCCESS; -+} -+ - //////////////////////////////////////// - - bool - readCoreScanlinePart ( - exr_context_t f, int part, bool reduceMemory, bool reduceTime) - { -- exr_result_t rv; -+ exr_result_t rv, frv; - exr_attr_box2i_t datawin; - rv = exr_get_data_window (f, part, &datawin); - if (rv != EXR_ERR_SUCCESS) return true; -@@ -1224,6 +1299,8 @@ readCoreScanlinePart ( - rv = exr_get_scanlines_per_chunk (f, part, &lines_per_chunk); - if (rv != EXR_ERR_SUCCESS) return true; - -+ frv = rv; -+ - for (uint64_t chunk = 0; chunk < height; chunk += lines_per_chunk) - { - exr_chunk_info_t cinfo = {0}; -@@ -1232,6 +1309,7 @@ readCoreScanlinePart ( - rv = exr_read_scanline_chunk_info (f, part, y, &cinfo); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) break; - continue; - } -@@ -1253,19 +1331,32 @@ readCoreScanlinePart ( - (uint64_t) lines_per_chunk; - } - -- // TODO: check we are supposed to multiple by lines per chunk above - doread = true; -- if (reduceMemory && bytes >= gMaxBytesPerScanline) doread = false; - -- if (doread) imgdata.resize (bytes); -+ if (cinfo.type == EXR_STORAGE_DEEP_SCANLINE) -+ { -+ decoder.decoding_user_data = &imgdata; -+ decoder.realloc_nonimage_data_fn = &realloc_deepdata; -+ } -+ else -+ { -+ if (reduceMemory && bytes >= gMaxBytesPerScanline) doread = false; -+ -+ if (doread) imgdata.resize (bytes); -+ } - rv = exr_decoding_choose_default_routines (f, part, &decoder); -- if (rv != EXR_ERR_SUCCESS) break; -+ if (rv != EXR_ERR_SUCCESS) -+ { -+ frv = rv; -+ break; -+ } - } - else - { - rv = exr_decoding_update (f, part, &cinfo, &decoder); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) break; - continue; - } -@@ -1273,20 +1364,25 @@ readCoreScanlinePart ( - - if (doread) - { -- uint8_t* dptr = &(imgdata[0]); -- for (int c = 0; c < decoder.channel_count; c++) -+ if (cinfo.type != EXR_STORAGE_DEEP_SCANLINE) - { -- exr_coding_channel_info_t& outc = decoder.channels[c]; -- outc.decode_to_ptr = dptr; -- outc.user_pixel_stride = outc.user_bytes_per_element; -- outc.user_line_stride = outc.user_pixel_stride * width; -- dptr += width * (uint64_t) outc.user_bytes_per_element * -+ uint8_t* dptr = &(imgdata[0]); -+ for (int c = 0; c < decoder.channel_count; c++) -+ { -+ exr_coding_channel_info_t& outc = decoder.channels[c]; -+ outc.decode_to_ptr = dptr; -+ outc.user_pixel_stride = outc.user_bytes_per_element; -+ outc.user_line_stride = outc.user_pixel_stride * width; -+ -+ dptr += width * (uint64_t) outc.user_bytes_per_element * - (uint64_t) lines_per_chunk; -+ } - } - - rv = exr_decoding_run (f, part, &decoder); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) break; - } - } -@@ -1294,7 +1390,7 @@ readCoreScanlinePart ( - - exr_decoding_destroy (f, &decoder); - -- return (rv != EXR_ERR_SUCCESS); -+ return (frv != EXR_ERR_SUCCESS); - } - - //////////////////////////////////////// -@@ -1303,7 +1399,7 @@ bool - readCoreTiledPart ( - exr_context_t f, int part, bool reduceMemory, bool reduceTime) - { -- exr_result_t rv; -+ exr_result_t rv, frv; - - exr_attr_box2i_t datawin; - rv = exr_get_data_window (f, part, &datawin); -@@ -1321,6 +1417,7 @@ readCoreTiledPart ( - rv = exr_get_tile_levels (f, part, &levelsx, &levelsy); - if (rv != EXR_ERR_SUCCESS) return true; - -+ frv = rv; - bool keepgoing = true; - for (int32_t ylevel = 0; keepgoing && ylevel < levelsy; ++ylevel) - { -@@ -1330,6 +1427,7 @@ readCoreTiledPart ( - rv = exr_get_level_sizes (f, part, xlevel, ylevel, &levw, &levh); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) - { - keepgoing = false; -@@ -1342,6 +1440,7 @@ readCoreTiledPart ( - rv = exr_get_tile_sizes (f, part, xlevel, ylevel, &curtw, &curth); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) - { - keepgoing = false; -@@ -1371,6 +1470,7 @@ readCoreTiledPart ( - f, part, tx, ty, xlevel, ylevel, &cinfo); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) - { - keepgoing = false; -@@ -1385,6 +1485,7 @@ readCoreTiledPart ( - exr_decoding_initialize (f, part, &cinfo, &decoder); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - keepgoing = false; - break; - } -@@ -1406,14 +1507,23 @@ readCoreTiledPart ( - } - - doread = true; -- if (reduceMemory && bytes >= gMaxTileBytes) -- doread = false; -+ if (cinfo.type == EXR_STORAGE_DEEP_TILED) -+ { -+ decoder.decoding_user_data = &tiledata; -+ decoder.realloc_nonimage_data_fn = &realloc_deepdata; -+ } -+ else -+ { -+ if (reduceMemory && bytes >= gMaxTileBytes) -+ doread = false; - -- if (doread) tiledata.resize (bytes); -+ if (doread) tiledata.resize (bytes); -+ } - rv = exr_decoding_choose_default_routines ( - f, part, &decoder); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - keepgoing = false; - break; - } -@@ -1423,6 +1533,7 @@ readCoreTiledPart ( - rv = exr_decoding_update (f, part, &cinfo, &decoder); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) - { - keepgoing = false; -@@ -1434,24 +1545,28 @@ readCoreTiledPart ( - - if (doread) - { -- uint8_t* dptr = &(tiledata[0]); -- for (int c = 0; c < decoder.channel_count; c++) -+ if (cinfo.type != EXR_STORAGE_DEEP_TILED) - { -- exr_coding_channel_info_t& outc = -- decoder.channels[c]; -- outc.decode_to_ptr = dptr; -- outc.user_pixel_stride = -- outc.user_bytes_per_element; -- outc.user_line_stride = -- outc.user_pixel_stride * curtw; -- dptr += (uint64_t) curtw * -+ uint8_t* dptr = &(tiledata[0]); -+ for (int c = 0; c < decoder.channel_count; c++) -+ { -+ exr_coding_channel_info_t& outc = -+ decoder.channels[c]; -+ outc.decode_to_ptr = dptr; -+ outc.user_pixel_stride = -+ outc.user_bytes_per_element; -+ outc.user_line_stride = -+ outc.user_pixel_stride * curtw; -+ dptr += (uint64_t) curtw * - (uint64_t) outc.user_bytes_per_element * - (uint64_t) curth; -+ } - } - - rv = exr_decoding_run (f, part, &decoder); - if (rv != EXR_ERR_SUCCESS) - { -+ frv = rv; - if (reduceTime) - { - keepgoing = false; -@@ -1486,17 +1601,14 @@ checkCoreFile (exr_context_t f, bool reduceMemory, bool reduceTime) - rv = exr_get_storage (f, p, &store); - if (rv != EXR_ERR_SUCCESS) return true; - -- // TODO: Need to fill this in -- if (store == EXR_STORAGE_DEEP_SCANLINE || -- store == EXR_STORAGE_DEEP_TILED) -- continue; -- -- if (store == EXR_STORAGE_SCANLINE) -+ if (store == EXR_STORAGE_SCANLINE || -+ store == EXR_STORAGE_DEEP_SCANLINE) - { - if (readCoreScanlinePart (f, p, reduceMemory, reduceTime)) - return true; - } -- else if (store == EXR_STORAGE_TILED) -+ else if (store == EXR_STORAGE_TILED || -+ store == EXR_STORAGE_DEEP_TILED) - { - if (readCoreTiledPart (f, p, reduceMemory, reduceTime)) return true; - } - diff --git a/openexr.changes b/openexr.changes index 3e50cd3..36899dd 100644 --- a/openexr.changes +++ b/openexr.changes @@ -1,3 +1,18 @@ +------------------------------------------------------------------- +Wed Feb 14 14:32:50 UTC 2024 - pgajdos@suse.com + +- version update to 3.2.2 [bsc#1219498] + * [CVE-2023-5841](https://takeonme.org/cves/CVE-2023-5841.html). + Note that this bug is present in the C++ API (since v3.1.0), although + it is in a routine that is predominantly used for development and + testing. It is not likely to appear in production code. + * OSS-fuzz [66491](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66491) + Out-of-memory in openexr_exrcorecheck_fuzzer + * OSS-fuzz [66489](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=66489) + Null-dereference in `Imf_3_3::realloc_deepdata` +- deleted patches + - openexr-CVE-2023-5841.patch (upstreamed) + ------------------------------------------------------------------- Wed Feb 7 10:31:23 UTC 2024 - pgajdos@suse.com diff --git a/openexr.spec b/openexr.spec index 195608a..409b934 100644 --- a/openexr.spec +++ b/openexr.spec @@ -22,7 +22,7 @@ %define sonum 31 %global so_suffix -3_2 Name: openexr -Version: 3.2.1 +Version: 3.2.2 Release: 0 Summary: Utilities for working with HDR images in OpenEXR format License: BSD-3-Clause @@ -30,8 +30,6 @@ Group: Development/Libraries/C and C++ URL: https://www.openexr.com/ Source0: https://github.com/openexr/openexr/archive/v%{version}.tar.gz Source2: baselibs.conf -# CVE-2023-5841 [bsc#1219498], heap-based buffer overflow in generic_unpack_deep() -Patch0: openexr-CVE-2023-5841.patch BuildRequires: cmake >= 3.12 BuildRequires: freeglut-devel BuildRequires: gcc-c++ diff --git a/v3.2.1.tar.gz b/v3.2.1.tar.gz deleted file mode 100644 index 93d2ca6..0000000 --- a/v3.2.1.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:61e175aa2203399fb3c8c2288752fbea3c2637680d50b6e306ea5f8ffdd46a9b -size 18824332 diff --git a/v3.2.2.tar.gz b/v3.2.2.tar.gz new file mode 100644 index 0000000..cf0e9ca --- /dev/null +++ b/v3.2.2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65de6459c245a4977ce4d7777e70b30d7ef48ec38e0cfb10205706ca50a8bf2e +size 18825996