GHSA-r24r-74rc-588f on CTRL-OS 26.05
Aliases: GHSA-r24r-74rc-588f
Packages: openexr
Status: Plausible
Advisory Information
exrmultipart convert ILP32 channelstore heap buffer overflow
Summary
A malformed public EXR can trigger an ILP32 allocation-size truncation in the shipped
exrmultipart -converttool. The convert path sizesstd::vector<char> channelstorefromsamplesize * pixel_count; on ILP32 the product wraps, thenInputPart::readPixels()reads scanline bytes into the undersized buffer.This reproduces on OpenEXR v3.4.13 and on the tested current-main ILP32 build.
Affected path
src/bin/exrmultipart/exrmultipart.cpp:291: reads attacker-controlleddataWindow.exrmultipart.cpp:295: computespixel_count.exrmultipart.cpp:324-326: callschannelstore[i].resize(samplesize * pixel_count)without checking that the product fits ILP32size_t.exrmultipart.cpp:332/340: installs the undersized buffer inSliceobjects.exrmultipart.cpp:357:InputPart::readPixels()writes full scanline data into that undersized buffer.Reproduction
From this directory:
OPENEXR_ROOT=/home/br0nzu/openexr/v3.4.13 ./reproduce.shFresh verification results:
date_utc=2026-06-25T15:11:12Z root=/home/br0nzu/openexr/v3.4.13 dir=/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow onechan_sha256=45abbc95629b17d84bed6fc68aea3272000c5f9e04a7ed4138f37dee89077887 rgba_sha256=a602a4aad612f35201b60d02faa8ac1e7e899a55542127ff19a9f14fe620302a == v3413_original == bin=poc_materials/bin/exrmultipart_ilp32_original input=poc_materials/exrmultipart_onechan_w65537_h65537_3chunks_none.exr env= rc=139 stdout_bytes=177 stderr_bytes=43 output_size=524290 == v3413_asan == bin=poc_materials/bin/exrmultipart_ilp32_asan input=poc_materials/exrmultipart_onechan_w65537_h65537_3chunks_none.exr env=ASAN_OPTIONS=detect_leaks=0:halt_on_error=1:abort_on_error=1:symbolize=1 rc=134 stdout_bytes=173 stderr_bytes=6541 output_size=524290 == v3413_ubsan == bin=poc_materials/bin/exrmultipart_ilp32_ubsan input=poc_materials/exrmultipart_onechan_w65537_h65537_3chunks_none.exr env=UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_stacktrace=1:symbolize=1 rc=1 stdout_bytes=174 stderr_bytes=81 output_size=524618 == current_main_original == bin=poc_materials/bin/exrmultipart_current_main_ilp32_original input=poc_materials/exrmultipart_onechan_w65537_h65537_3chunks_none.exr env= rc=139 stdout_bytes=184 stderr_bytes=43 output_size=524290 == current_main_asan == bin=poc_materials/bin/exrmultipart_current_main_ilp32_asan input=poc_materials/exrmultipart_onechan_w65537_h65537_3chunks_none.exr env=ASAN_OPTIONS=detect_leaks=0:halt_on_error=1:abort_on_error=1:symbolize=1 rc=134 stdout_bytes=180 stderr_bytes=6564 output_size=524290 == current_main_ubsan == bin=poc_materials/bin/exrmultipart_current_main_ilp32_ubsan input=poc_materials/exrmultipart_onechan_w65537_h65537_3chunks_none.exr env=UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_stacktrace=1:symbolize=1 rc=1 stdout_bytes=181 stderr_bytes=94 output_size=524618Impact
On ILP32 builds, an attacker-controlled EXR passed to
exrmultipart -convertcan cause heap memory corruption. Confirmed impact is deterministic crash plus ASAN-confirmed heap out-of-bounds write. Practical exposure is mainly automated conversion or asset-ingestion pipelines that invokeexrmultipart -converton untrusted EXR files.Full sanitizer output
v3.4.13 ASAN
================================================================= ==730596==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf76ca802 at pc 0x5672177a bp 0xff839648 sp 0xff839220 WRITE of size 131074 at 0xf76ca802 thread T0 #0 0x56721779 in pread64 (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_ilp32_asan+0xd3779) (BuildId: 6c23b7ce3de804855d09673cc0b1f228ddcb072e) #1 0x56984c81 in default_read_func /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/internal_posix_file_impl.h:177:14 #2 0x56980106 in dispatch_read /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/context.c:51:16 #3 0x56a05d2b in read_uncompressed_direct /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:131:18 #4 0x56a06a67 in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:567:10 #5 0x5696248f in Imf_3_4::(anonymous namespace)::ScanLineProcess::run_decode(_priv_exr_context_t const*, int, Imf_3_4::FrameBuffer const*, int, int, std::vector<Imf_3_4::Slice, std::allocator<Imf_3_4::Slice>> const&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfScanLineInputFile.cpp:586:23 #6 0x5695f638 in Imf_3_4::ScanLineInputFile::Data::readPixels(Imf_3_4::FrameBuffer const&, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfScanLineInputFile.cpp:500:21 #7 0x5695ef49 in Imf_3_4::ScanLineInputFile::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfScanLineInputFile.cpp:307:12 #8 0x56952a37 in Imf_3_4::InputFile::Data::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfInputFile.cpp:458:20 #9 0x56952966 in Imf_3_4::InputFile::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfInputFile.cpp:222:12 #10 0x568200f3 in Imf_3_4::InputPart::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfInputPart.cpp:78:11 #11 0x567e7477 in convert(std::vector<char const*, std::allocator<char const*>>, std::vector<char const*, std::allocator<char const*>>, char const*, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmultipart/exrmultipart.cpp:357:12 #12 0x567f123c in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmultipart/exrmultipart.cpp:716:13 #13 0xf794ccb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #14 0xf794cd7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #15 0x56705806 in _start (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_ilp32_asan+0xb7806) (BuildId: 6c23b7ce3de804855d09673cc0b1f228ddcb072e) 0xf76ca802 is located 0 bytes after 262146-byte region [0xf768a800,0xf76ca802) allocated by thread T0 here: #0 0x567df5cb in operator new(unsigned int) (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_ilp32_asan+0x1915cb) (BuildId: 6c23b7ce3de804855d09673cc0b1f228ddcb072e) #1 0x568014ea in std::__new_allocator<char>::allocate(unsigned int, void const*) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27 #2 0x568014ea in std::allocator_traits<std::allocator<char>>::allocate(std::allocator<char>&, unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20 #3 0x568014ea in std::_Vector_base<char, std::allocator<char>>::_M_allocate(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20 #4 0x568014ea in std::vector<char, std::allocator<char>>::_M_default_append(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:663:34 #5 0x567e70b6 in std::vector<char, std::allocator<char>>::resize(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:1016:4 #6 0x567e70b6 in convert(std::vector<char const*, std::allocator<char const*>>, std::vector<char const*, std::allocator<char const*>>, char const*, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmultipart/exrmultipart.cpp:326:25 #7 0x567f123c in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmultipart/exrmultipart.cpp:716:13 #8 0xf794ccb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_ilp32_asan+0xd3779) (BuildId: 6c23b7ce3de804855d09673cc0b1f228ddcb072e) in pread64 Shadow bytes around the buggy address: 0xf76ca580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ca600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ca680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ca700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ca780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0xf76ca800:[02]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76ca880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76ca900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76ca980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76caa00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76caa80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==730596==ABORTING timeout: the monitored command dumped corecurrent main ASAN
================================================================= ==730675==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf6fc6802 at pc 0x5664dcfa bp 0xfffeb768 sp 0xfffeb340 WRITE of size 131074 at 0xf6fc6802 thread T0 #0 0x5664dcf9 in pread64 (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_current_main_ilp32_asan+0x3bcf9) (BuildId: c43007184a3f7eede2aa8da1efb540b0d2e1b0ad) #1 0xf7b25301 in default_read_func /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/internal_posix_file_impl.h:177:14 #2 0xf7b206e6 in dispatch_read /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/context.c:51:16 #3 0xf7b75cdb in read_uncompressed_direct /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/decoding.c:131:18 #4 0xf7b76a17 in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/decoding.c:567:10 #5 0xf7e6ddaf in Imf_4_0::(anonymous namespace)::ScanLineProcess::run_decode(_priv_exr_context_t const*, int, Imf_4_0::FrameBuffer const*, int, int, std::vector<Imf_4_0::Slice, std::allocator<Imf_4_0::Slice>> const&) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXR/ImfScanLineInputFile.cpp:586:23 #6 0xf7e6aff8 in Imf_4_0::ScanLineInputFile::Data::readPixels(Imf_4_0::FrameBuffer const&, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXR/ImfScanLineInputFile.cpp:500:21 #7 0xf7e6a8f9 in Imf_4_0::ScanLineInputFile::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXR/ImfScanLineInputFile.cpp:307:12 #8 0xf7dd7637 in Imf_4_0::InputFile::Data::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXR/ImfInputFile.cpp:458:20 #9 0xf7dd7566 in Imf_4_0::InputFile::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXR/ImfInputFile.cpp:222:12 #10 0xf7de0a23 in Imf_4_0::InputPart::readPixels(int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXR/ImfInputPart.cpp:78:11 #11 0x567139f7 in convert(std::vector<char const*, std::allocator<char const*>>, std::vector<char const*, std::allocator<char const*>>, char const*, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmultipart/exrmultipart.cpp:357:12 #12 0x5671d7bc in main /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmultipart/exrmultipart.cpp:716:13 #13 0xf724ecb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #14 0xf724ed7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #15 0x56631d86 in _start (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_current_main_ilp32_asan+0x1fd86) (BuildId: c43007184a3f7eede2aa8da1efb540b0d2e1b0ad) 0xf6fc6802 is located 0 bytes after 262146-byte region [0xf6f86800,0xf6fc6802) allocated by thread T0 here: #0 0x5670bb4b in operator new(unsigned int) (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_current_main_ilp32_asan+0xf9b4b) (BuildId: c43007184a3f7eede2aa8da1efb540b0d2e1b0ad) #1 0x5672da6a in std::__new_allocator<char>::allocate(unsigned int, void const*) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27 #2 0x5672da6a in std::allocator_traits<std::allocator<char>>::allocate(std::allocator<char>&, unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20 #3 0x5672da6a in std::_Vector_base<char, std::allocator<char>>::_M_allocate(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20 #4 0x5672da6a in std::vector<char, std::allocator<char>>::_M_default_append(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:663:34 #5 0x56713636 in std::vector<char, std::allocator<char>>::resize(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:1016:4 #6 0x56713636 in convert(std::vector<char const*, std::allocator<char const*>>, std::vector<char const*, std::allocator<char const*>>, char const*, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmultipart/exrmultipart.cpp:326:25 #7 0x5671d7bc in main /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmultipart/exrmultipart.cpp:716:13 #8 0xf724ecb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/br0nzu/openexr/v3.4.13/report/64. OpenEXR v3.4.13 exrmultipart convert ILP32 channelstore heap buffer overflow/poc_materials/bin/exrmultipart_current_main_ilp32_asan+0x3bcf9) (BuildId: c43007184a3f7eede2aa8da1efb540b0d2e1b0ad) in pread64 Shadow bytes around the buggy address: 0xf6fc6580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fc6600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fc6680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fc6700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fc6780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0xf6fc6800:[02]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fc6880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fc6900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fc6980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fc6a00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fc6a80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==730675==ABORTING timeout: the monitored command dumped core
Updates
2026-08-11 03:49 CEST
Metadata changes:
- Status for package
openexr: “Plausible”
2026-08-11 03:31 CEST
Metadata changes:
- Status for package
openexr: “New”