summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--CVE-2023-5841.patch503
-rw-r--r--CVE-2024-31047.patch42
-rw-r--r--OpenEXR.spec134
-rw-r--r--sources1
5 files changed, 681 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..489f74b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/openexr-3.1.11.tar.gz
diff --git a/CVE-2023-5841.patch b/CVE-2023-5841.patch
new file mode 100644
index 0000000..1acad77
--- /dev/null
+++ b/CVE-2023-5841.patch
@@ -0,0 +1,503 @@
+From df4d77471f2722025011da2e699d581d1e757f6b Mon Sep 17 00:00:00 2001
+From: Kimball Thurston <kdt3rd@gmail.com>
+Date: Mon, 5 Feb 2024 08:44:21 +1300
+Subject: [PATCH] Fix CVE 2023 5841 (#1627)
+
+* enable deep file checks for core
+
+Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>
+
+* fix possible int overflow
+
+Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>
+
+* fix validation of deep sample counts
+
+Addresses CVE-2023-5841, fixing sample count check to not only check
+against 0 but previous sample as well.
+
+Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>
+
+* add clarifying comment
+
+Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>
+
+---------
+
+Signed-off-by: Kimball Thurston <kdt3rd@gmail.com>
+---
+ src/lib/OpenEXRCore/decoding.c | 40 +++---
+ src/lib/OpenEXRCore/unpack.c | 9 +-
+ src/lib/OpenEXRUtil/ImfCheckFile.cpp | 190 +++++++++++++++++++++------
+ 3 files changed, 182 insertions(+), 57 deletions(-)
+
+diff --git a/src/lib/OpenEXRCore/decoding.c b/src/lib/OpenEXRCore/decoding.c
+index e9e8f7f9b..bf5ae2105 100644
+--- a/src/lib/OpenEXRCore/decoding.c
++++ b/src/lib/OpenEXRCore/decoding.c
+@@ -289,7 +289,11 @@ default_decompress_chunk (exr_decode_pipeline_t* decode)
+ part->storage_mode == EXR_STORAGE_DEEP_TILED)
+ {
+ uint64_t sampsize =
+- (((uint64_t) decode->chunk.width) * ((uint64_t) decode->chunk.height));
++ (((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 (
+@@ -342,7 +346,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;
+
+@@ -353,38 +357,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 9ecb729cf..80990e0d2 100644
+--- a/src/lib/OpenEXRCore/unpack.c
++++ b/src/lib/OpenEXRCore/unpack.c
+@@ -1205,9 +1205,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;
+@@ -1251,12 +1252,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)
+@@ -1272,7 +1275,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;
+ }
+ }
+@@ -1310,7 +1313,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 8c4fbe84f..cdc0fa3da 100644
+--- a/src/lib/OpenEXRUtil/ImfCheckFile.cpp
++++ b/src/lib/OpenEXRUtil/ImfCheckFile.cpp
+@@ -1172,11 +1172,86 @@ 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<uint8_t>* ud = static_cast<std::vector<uint8_t>*>(
++ 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)
+@@ -1194,6 +1269,8 @@ bool readCoreScanlinePart(exr_context_t f, int part, bool reduceMemory, bool red
+ 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 };
+@@ -1202,8 +1279,8 @@ bool readCoreScanlinePart(exr_context_t f, int part, bool reduceMemory, bool red
+ rv = exr_read_scanline_chunk_info (f, part, y, &cinfo);
+ if (rv != EXR_ERR_SUCCESS)
+ {
+- if (reduceTime)
+- break;
++ frv = rv;
++ if (reduceTime) break;
+ continue;
+ }
+
+@@ -1224,59 +1301,72 @@ bool readCoreScanlinePart(exr_context_t f, int part, bool reduceMemory, bool red
+ bytes += width * (uint64_t)outc.user_bytes_per_element * (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 (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 );
++ if (doread) imgdata.resize (bytes);
++ }
+ rv = exr_decoding_choose_default_routines (f, part, &decoder);
+ if (rv != EXR_ERR_SUCCESS)
++ {
++ frv = rv;
+ break;
++ }
+ }
+ else
+ {
+ rv = exr_decoding_update (f, part, &cinfo, &decoder);
+ if (rv != EXR_ERR_SUCCESS)
+ {
+- if (reduceTime)
+- break;
++ frv = rv;
++ if (reduceTime) break;
+ continue;
+ }
+ }
+
+ 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 * (uint64_t)lines_per_chunk;
++ 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)
+ {
+- if (reduceTime)
+- break;
++ frv = rv;
++ if (reduceTime) break;
+ }
+ }
+ }
+
+ exr_decoding_destroy (f, &decoder);
+
+- return (rv != EXR_ERR_SUCCESS);
++ return (frv != EXR_ERR_SUCCESS);
+ }
+
+ ////////////////////////////////////////
+
+ 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);
+@@ -1296,6 +1386,7 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+ if (rv != EXR_ERR_SUCCESS)
+ return true;
+
++ frv = rv;
+ bool keepgoing = true;
+ for (int32_t ylevel = 0; keepgoing && ylevel < levelsy; ++ylevel )
+ {
+@@ -1305,6 +1396,7 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+ rv = exr_get_level_sizes (f, part, xlevel, ylevel, &levw, &levh);
+ if (rv != EXR_ERR_SUCCESS)
+ {
++ frv = rv;
+ if (reduceTime)
+ {
+ keepgoing = false;
+@@ -1317,6 +1409,7 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+ rv = exr_get_tile_sizes (f, part, xlevel, ylevel, &curtw, &curth);
+ if (rv != EXR_ERR_SUCCESS)
+ {
++ frv = rv;
+ if (reduceTime)
+ {
+ keepgoing = false;
+@@ -1343,6 +1436,7 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+ rv = exr_read_tile_chunk_info (f, part, tx, ty, xlevel, ylevel, &cinfo);
+ if (rv != EXR_ERR_SUCCESS)
+ {
++ frv = rv;
+ if (reduceTime)
+ {
+ keepgoing = false;
+@@ -1356,6 +1450,7 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+ rv = exr_decoding_initialize (f, part, &cinfo, &decoder);
+ if (rv != EXR_ERR_SUCCESS)
+ {
++ frv = rv;
+ keepgoing = false;
+ break;
+ }
+@@ -1372,14 +1467,23 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+ }
+
+ 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 );
+- rv = exr_decoding_choose_default_routines (f, part, &decoder);
++ if (doread) tiledata.resize (bytes);
++ }
++ rv = exr_decoding_choose_default_routines (
++ f, part, &decoder);
+ if (rv != EXR_ERR_SUCCESS)
+ {
++ frv = rv;
+ keepgoing = false;
+ break;
+ }
+@@ -1389,6 +1493,7 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+ rv = exr_decoding_update (f, part, &cinfo, &decoder);
+ if (rv != EXR_ERR_SUCCESS)
+ {
++ frv = rv;
+ if (reduceTime)
+ {
+ keepgoing = false;
+@@ -1400,19 +1505,28 @@ bool readCoreTiledPart(exr_context_t f, int part, bool reduceMemory, bool reduce
+
+ 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 * (uint64_t)outc.user_bytes_per_element * (uint64_t)curth;
++ 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;
+@@ -1448,16 +1562,14 @@ bool checkCoreFile(exr_context_t f, bool reduceMemory, bool reduceTime)
+ 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/CVE-2024-31047.patch b/CVE-2024-31047.patch
new file mode 100644
index 0000000..66b040e
--- /dev/null
+++ b/CVE-2024-31047.patch
@@ -0,0 +1,42 @@
+From 7aa89e1d09b09d9f5dbb96976ee083a331ab9d71 Mon Sep 17 00:00:00 2001
+From: xiaoxiaoafeifei <zhailiangliang@loongson.cn>
+Date: Wed, 20 Mar 2024 00:09:05 +0800
+Subject: [PATCH] prevent integer overflows in file exrmultipart.cpp (#1681)
+
+Signed-off-by: ZhaiLiangliang <zhailiangliang@loongson.cn>
+
+Origin: https://github.com/AcademySoftwareFoundation/openexr/pull/1681
+
+---
+ src/bin/exrmultipart/exrmultipart.cpp | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/src/bin/exrmultipart/exrmultipart.cpp b/src/bin/exrmultipart/exrmultipart.cpp
+index 931cebc..1c624b8 100644
+--- a/src/bin/exrmultipart/exrmultipart.cpp
++++ b/src/bin/exrmultipart/exrmultipart.cpp
+@@ -326,12 +326,17 @@ convert(vector <const char*> in,
+ }
+
+ Box2i dataWindow = infile.header(0).dataWindow();
+- int pixel_count = (dataWindow.size().y+1)*(dataWindow.size().x+1);
+- int pixel_width = dataWindow.size().x+1;
+-
++ //
++ // use int64_t for dimensions, since possible overflow int storage
++ //
++ int64_t pixel_count = (static_cast<int64_t>(dataWindow.size ().y) + 1) * (static_cast<int64_t>(dataWindow.size ().x) + 1);
++ int64_t pixel_width = static_cast<int64_t>(dataWindow.size ().x) + 1;
+
++ //
+ // offset in pixels between base of array and 0,0
+- int pixel_base = dataWindow.min.y*pixel_width+dataWindow.min.x;
++ // use int64_t for dimensions, since dataWindow.min.y * pixel_width could overflow int storage
++ //
++ int64_t pixel_base = static_cast<int64_t>(dataWindow.min.y) * pixel_width + static_cast<int64_t>(dataWindow.min.x);
+
+ vector< vector<char> > channelstore(channel_count);
+
+--
+2.43.0
+
diff --git a/OpenEXR.spec b/OpenEXR.spec
new file mode 100644
index 0000000..ba2c386
--- /dev/null
+++ b/OpenEXR.spec
@@ -0,0 +1,134 @@
+Name: OpenEXR
+Summary: A high dynamic-range (HDR) image file format for use in computer imaging applications
+Version: 3.1.11
+Release: 3
+License: BSD-3-Clause
+URL: http://www.openexr.com/
+Source0: https://github.com/AcademySoftwareFoundation/openexr/archive/v%{version}/openexr-%{version}.tar.gz
+# https://github.com/AcademySoftwareFoundation/openexr/commit/df4d77471f2722025011da2e699d581d1e757f6b
+Patch0: CVE-2023-5841.patch
+Patch1: CVE-2024-31047.patch
+BuildRequires: gcc-c++ zlib-devel pkgconfig python3-devel
+BuildRequires: cmake gcc boost-devel pkgconfig(Imath)
+
+Requires: %{name}-libs = %{version}-%{release}
+
+Provides: openexr = %{version}-%{release}
+Obsoletes: openexr < %{version}-%{release}
+
+%description
+OpenEXR is a high dynamic-range (HDR) image file format originally developed by Industrial
+Light & Magic for use in computer imaging applications.
+
+%package libs
+Summary: Libraries for %{name}
+Provides: openexr-libs = %{version}-%{release}
+Obsoletes: openexr-libs < %{version}-%{release}
+
+%description libs
+Libraries for %{name}.
+
+%package devel
+Summary: Development files for %{name}
+Provides: openexr-devel = %{version}-%{release}
+Obsoletes: openexr-devel < %{version}-%{release}
+Provides: ilmbase-devel = %{version}-%{release}
+Obsoletes: ilmbase-devel < 2.5.3
+Requires: %{name}-libs = %{version}-%{release}
+
+%description devel
+This package contains libraries and header files for development of %{name}.
+
+%prep
+%autosetup -n openexr-%{version} -p1
+
+%build
+%cmake
+%make_build
+
+%install
+%make_install
+
+%check
+%ifarch aarch64 ppc64le
+# https://github.com/AcademySoftwareFoundation/openexr/issues/1460
+EXCLUDE_REGEX='DWA[AB]Compression'
+%endif
+/usr/bin/ctest --output-on-failure --force-new-ctest-process -j${RPM_BUILD_NCPUS} --exclude-regex "$EXCLUDE_REGEX"
+
+%ldconfig_scriptlets libs
+
+%files
+%doc CHANGES.md CONTRIBUTING.md GOVERNANCE.md SECURITY.md CODE_OF_CONDUCT.md CONTRIBUTORS.md README.md
+%license LICENSE.md
+%{_bindir}/*
+%exclude %{_docdir}/%{name}-%{version}
+
+%files libs
+%{_libdir}/*.so.30*
+
+%files devel
+%{_docdir}/OpenEXR/
+%{_includedir}/OpenEXR/
+%{_libdir}/*.so
+%{_libdir}/cmake/OpenEXR/
+%{_libdir}/pkgconfig/OpenEXR.pc
+
+%changelog
+* Wed Apr 17 2024 wangkai <13474090681@163.com> - 3.1.11-3
+- Fix CVE-2024-31047
+
+* Mon Feb 26 2024 yaoxin <yao_xin001@hoperun.com> - 3.1.11-2
+- Fix CVE-2023-5841
+
+* Thu Oct 12 2023 yaoxin <yao_xin001@hoperun.com> - 3.1.11-1
+- Upgrade to 3.1.11
+
+* Wed Jul 12 2023 liyanan <thistleslyn@163.com> - 3.1.9-1
+- update to 3.1.9
+
+* Tue May 10 2022 Ge Wang <wangge20@h-partners.com> - 3.1.5-2
+- license compliance rectification
+
+* Thu Apr 28 2022 wangkai <wangkai385@h-partners.com> - 3.1.5-1
+- update to 3.1.5 for fix CVE-2022-45942
+
+* Tue Mar 29 2022 liyanan <liyanan32@huawei.com> - 3.1.3-1
+- update to 3.1.3
+
+* Wed Mar 23 2022 yaoxin <yaoxin30@huawei.com> - 2.2.0-25
+- Fix CVE-2021-20299
+
+* Fri Mar 11 2022 yaoxin <yaoxin30@huawei.com> - 2.2.0-24
+- Fix CVE-2021-20303
+
+* Wed Sep 1 2021 liwu<liwu13@huawei.com> - 2.2.0-23
+- fix CVE-2021-3605
+
+* Mon Jul 12 2021 yaoxin <yaoxin30@huawei.com> - 2.2.0-22
+- fix CVE-2020-11758 CVE-2020-11759 CVE-2020-11760 CVE-2020-11761 CVE-2020-11762 CVE-2020-11763 CVE-2020-11764 CVE-2020-11765 CVE-2020-15305 CVE-2020-15306
+
+* Sat Jul 10 2021 wangyue <wangyue92@huawei.com> - 2.2.0-21
+- fix CVE-2021-3598
+
+* Tue Jun 22 2021 houyingchao <houyingchao@huawei.com> - 2.2.0-20
+- fix CVE-2021-23215 CVE-2021-23169 CVE-2021-26260
+
+* Tue Apr 06 2021 wangyue <wangyue92@huawei.com> - 2.2.0-19
+- fix CVE-2021-3474 CVE-2021-3477 CVE-2021-3476 CVE-2021-3475 CVE-2021-20296 CVE-2021-3479 CVE-2021-20296
+
+* Wed Jan 27 2021 zhanghua <zhanghua40@huawei.com> - 2.2.0-18
+- Type:CVE
+- ID:NA
+- SUG:NA
+- DESC:fix CVE-2017-9110 CVE-2017-9111 CVE-2017-9112 CVE-2017-9113
+ CVE-2017-9114 CVE-2017-9115 CVE-2017-9116 CVE-2017-12596
+
+* Tue Feb 18 2020 hexiujun <hexiujun1@huawei.com> - 2.2.0-17
+- Type:enhancement
+- ID:NA
+- SUG:NA
+- DESC:unpack libs subpackage
+
+* Fri Oct 25 2019 huzhiyu <huzhiyu1@huawei.com> - 2.2.0-16
+- Package init
diff --git a/sources b/sources
new file mode 100644
index 0000000..ee247ac
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+f599b7aba747ee4fa7869c9941ba91d3 openexr-3.1.11.tar.gz