GHSA-r8mj-rhfc-38g4 on CTRL-OS 26.05
Aliases: GHSA-r8mj-rhfc-38g4
Packages: openexr
Status: Plausible
Advisory Information
exrmetrics ILP32 scanline channel vector heap buffer overflow
Summary
A malformed public scanline EXR can trigger an ILP32 allocation-size truncation in the shipped
exrmetrics input.exrtool.exrmetrics::initScanLine()computesnumPixelsasuint64_t, then callsstd::vector<char>::resize(numPixels * samplesize). On 32-bit builds the requested byte count is truncated to the vector's 32-bitsize_type, creating an undersized per-channel buffer.InputPart::readPixels()then decodes scanline bytes into that buffer and writes past the heap allocation.This reproduces on OpenEXR v3.4.13 and on the tested current-main ILP32 build. Confirmed impact is crash plus ASAN-confirmed heap out-of-bounds write.
Affected path
src/bin/exrmetrics/main.cpp:540: shipped CLI reachesexrmetrics(...)for public input.src/bin/exrmetrics/exrmetrics.cpp:76-80: reads publicdataWindow, computeswidth,height, andnumPixelsas 64-bit values.src/bin/exrmetrics/exrmetrics.cpp:93-97: computes channel sample size and resizespixelData[channelNumber]withnumPixels * samplesize.src/bin/exrmetrics/exrmetrics.cpp:99-107: installs the undersized vector as the channelSlicebacking store.src/bin/exrmetrics/exrmetrics.cpp:120-126: callsInputPart::readPixels()and decodes scanlines into that backing store.For the PoC,
width = height = 65537, sonumPixels * 2 = 8,590,196,738. On ILP32, this truncates to a 262,146-byte vector. Each HALF channel row is65537 * 2 = 131,074bytes; the third row crosses the truncated allocation boundary.Reproduction
From this report directory:
OPENEXR_ROOT=/home/br0nzu/openexr/v3.4.13 ./reproduce.shFresh verification summary:
date_utc=2026-06-25T19:10:57Z / 2026-06-25T19:11:41Z poc_sha256=452a1c45bce6ebcd2b8e475e3552318546caab01bc9f3d516cca8af69c061196 v3.4.13_original_rc=139 v3.4.13_original_signal=timeout: the monitored command dumped core v3.4.13_asan_rc=134 v3.4.13_asan_signal=AddressSanitizer heap-buffer-overflow WRITE of size 131074; allocation at exrmetrics.cpp:97 initScanLine() v3.4.13_ubsan_rc=134 v3.4.13_ubsan_signal=free(): invalid pointer current_main_original_rc=139 current_main_original_signal=timeout: the monitored command dumped core current_main_asan_rc=134 current_main_asan_signal=AddressSanitizer heap-buffer-overflow WRITE of size 131074; allocation at exrmetrics.cpp:97 initScanLine() current_main_ubsan_rc=134 current_main_ubsan_signal=free(): invalid pointer patch49_original_rc=139 patch49_asan_rc=134 patch49_ubsan_rc=134 patch49_result=report49 Slice::Make patch does not block this allocation-size truncation PoCFile metadata:
file poc_materials/exrmetrics_rgba_w65537_h65537_3rows.exr (incomplete): file format version: 2, flags 0x0 channels (type chlist): A, 16-bit floating-point, sampling 1 1 B, 16-bit floating-point, sampling 1 1 G, 16-bit floating-point, sampling 1 1 R, 16-bit floating-point, sampling 1 1 compression (type compression): none: no compression. dataWindow (type box2i): (0 0) - (65536 65536) displayWindow (type box2i): (0 0) - (65536 65536) lineOrder (type lineOrder): increasing y pixelAspectRatio (type float): 1 screenWindowCenter (type v2f): (0 0) screenWindowWidth (type float): 1 type (type string): "scanlineimage"Impact
An attacker who can supply EXR files to an ILP32
exrmetricsworkflow can crash the process and trigger a heap out-of-bounds write with decoded scanline data. Practical exposure is mainly automated/batch metric pipelines processing untrusted EXR files on 32-bit builds. LP64 builds do not truncate this allocation in the same way and are more likely to hit resource-exhaustion behavior for this huge declared image.PoC zip contents
Full sanitizer output
v3.4.13 ASAN
================================================================= ==1360436==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf76ae802 at pc 0x5664078a bp 0xfff54c88 sp 0xfff54860 WRITE of size 131074 at 0xf76ae802 thread T0 #0 0x56640789 in pread64 (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0xcc789) (BuildId: 94c69bf852af524443321329ad58d726ae6e8014) #1 0x5689f6c1 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 0x5689ab46 in dispatch_read /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/context.c:51:16 #3 0x5692076b in read_uncompressed_direct /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:131:18 #4 0x569214a7 in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:567:10 #5 0x5688112f 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 0x5687e2d8 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 0x5687dbe9 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 0x568716d7 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 0x56871606 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 0x56752bc3 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 0x56715570 in readScanLine(Imf_3_4::InputPart&, Imf_3_4::FrameBuffer&, std::vector<double, std::allocator<double>>&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:126:8 #12 0x5671e1f2 in initAndReadFile(Imf_3_4::MultiPartInputFile&, std::vector<Imf_3_4::Header, std::allocator<Imf_3_4::Header>> const&, int, std::vector<partData, std::allocator<partData>>&, fileMetrics&, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:680:13 #13 0x567229f2 in exrmetrics(char const*, char const*, int, Imf_3_4::Compression, float, int, bool, bool, PixelMode, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:1090:5 #14 0x56705f2d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/main.cpp:540:41 #15 0xf7930cb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #16 0xf7930d7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #17 0x56624816 in _start (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0xb0816) (BuildId: 94c69bf852af524443321329ad58d726ae6e8014) 0xf76ae802 is located 0 bytes after 262146-byte region [0xf766e800,0xf76ae802) allocated by thread T0 here: #0 0x566fe5db in operator new(unsigned int) (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0x18a5db) (BuildId: 94c69bf852af524443321329ad58d726ae6e8014) #1 0x56728cea 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 0x56728cea 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 0x56728cea 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 0x56728cea 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 0x56714bd6 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 0x56714bd6 in initScanLine(std::vector<std::vector<char, std::allocator<char>>, std::allocator<std::vector<char, std::allocator<char>>>>&, Imf_3_4::FrameBuffer&, Imf_3_4::InputPart&, Imf_3_4::Header const&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:97:34 #7 0x5671d95f in initAndReadFile(Imf_3_4::MultiPartInputFile&, std::vector<Imf_3_4::Header, std::allocator<Imf_3_4::Header>> const&, int, std::vector<partData, std::allocator<partData>>&, fileMetrics&, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:667:41 #8 0x567229f2 in exrmetrics(char const*, char const*, int, Imf_3_4::Compression, float, int, bool, bool, PixelMode, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:1090:5 #9 0x56705f2d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/main.cpp:540:41 #10 0xf7930cb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0xcc789) (BuildId: 94c69bf852af524443321329ad58d726ae6e8014) in pread64 Shadow bytes around the buggy address: 0xf76ae580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ae600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ae680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ae700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf76ae780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0xf76ae800:[02]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76ae880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76ae900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76ae980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76aea00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf76aea80: 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 ==1360436==ABORTING timeout: the monitored command dumped corev3.4.13 UBSAN-build output
free(): invalid pointer timeout: the monitored command dumped corecurrent main ASAN
================================================================= ==1370832==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf6fb3802 at pc 0x5668cf9a bp 0xffc32468 sp 0xffc32040 WRITE of size 131074 at 0xf6fb3802 thread T0 #0 0x5668cf99 in pread64 (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_current_main/bin/exrmetrics_current_main_ilp32_asan+0x3df99) (BuildId: 57838dec89f64e5b33922b4ab416dbeaabbb7ced) #1 0xf7b12301 in default_read_func /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/internal_posix_file_impl.h:177:14 #2 0xf7b0d6e6 in dispatch_read /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/context.c:51:16 #3 0xf7b62cdb in read_uncompressed_direct /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/decoding.c:131:18 #4 0xf7b63a17 in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/lib/OpenEXRCore/decoding.c:567:10 #5 0xf7e5adaf 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 0xf7e57ff8 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 0xf7e578f9 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 0xf7dc4637 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 0xf7dc4566 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 0xf7dcda23 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 0x56761d80 in readScanLine(Imf_4_0::InputPart&, Imf_4_0::FrameBuffer&, std::vector<double, std::allocator<double>>&) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/exrmetrics.cpp:126:8 #12 0x5676aa02 in initAndReadFile(Imf_4_0::MultiPartInputFile&, std::vector<Imf_4_0::Header, std::allocator<Imf_4_0::Header>> const&, int, std::vector<partData, std::allocator<partData>>&, fileMetrics&, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/exrmetrics.cpp:680:13 #13 0x5676f228 in exrmetrics(char const*, char const*, int, Imf_4_0::Compression, float, int, bool, bool, PixelMode, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/exrmetrics.cpp:1090:5 #14 0x5675273d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/main.cpp:540:41 #15 0xf723bcb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #16 0xf723bd7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #17 0x56671026 in _start (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_current_main/bin/exrmetrics_current_main_ilp32_asan+0x22026) (BuildId: 57838dec89f64e5b33922b4ab416dbeaabbb7ced) 0xf6fb3802 is located 0 bytes after 262146-byte region [0xf6f73800,0xf6fb3802) allocated by thread T0 here: #0 0x5674adeb in operator new(unsigned int) (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_current_main/bin/exrmetrics_current_main_ilp32_asan+0xfbdeb) (BuildId: 57838dec89f64e5b33922b4ab416dbeaabbb7ced) #1 0x5677555a 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 0x5677555a 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 0x5677555a 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 0x5677555a 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 0x567613e6 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 0x567613e6 in initScanLine(std::vector<std::vector<char, std::allocator<char>>, std::allocator<std::vector<char, std::allocator<char>>>>&, Imf_4_0::FrameBuffer&, Imf_4_0::InputPart&, Imf_4_0::Header const&) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/exrmetrics.cpp:97:34 #7 0x5676a16f in initAndReadFile(Imf_4_0::MultiPartInputFile&, std::vector<Imf_4_0::Header, std::allocator<Imf_4_0::Header>> const&, int, std::vector<partData, std::allocator<partData>>&, fileMetrics&, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/exrmetrics.cpp:667:41 #8 0x5676f228 in exrmetrics(char const*, char const*, int, Imf_4_0::Compression, float, int, bool, bool, PixelMode, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/exrmetrics.cpp:1090:5 #9 0x5675273d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-main/src/bin/exrmetrics/main.cpp:540:41 #10 0xf723bcb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/br0nzu/openexr/v3.4.13/report/68. OpenEXR v3.4.13 exrmetrics ILP32 scanline channel vector heap buffer overflow/repro_current_main/bin/exrmetrics_current_main_ilp32_asan+0x3df99) (BuildId: 57838dec89f64e5b33922b4ab416dbeaabbb7ced) in pread64 Shadow bytes around the buggy address: 0xf6fb3580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fb3600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fb3680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fb3700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf6fb3780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0xf6fb3800:[02]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fb3880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fb3900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fb3980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fb3a00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf6fb3a80: 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 ==1370832==ABORTING timeout: the monitored command dumped corecurrent main UBSAN-build output
free(): invalid pointer 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”