GHSA-pgc2-hppj-q623 on CTRL-OS 26.05
Aliases: GHSA-pgc2-hppj-q623
Packages: openexr
Status: Plausible
Advisory Information
Summary
A malformed tiled EXR with a positive
65537 x 65537dataWindow can make the shippedexrmetricstool corrupt heap memory on ILP32 builds. IninitTiled(),numPixels * samplesizeis computed as a large 64-bit value but is passed tostd::vector<char>::resize(size_type), which truncates on 32-bit builds before tiled decode writes into it. Fresh validation also reproduced the same behavior on current main.Details
For RGBA HALF tiles, each channel needs
65537 * 65537 * 2bytes. On ILP32 the vector allocation truncates to 262,146 bytes per channel, whileTiledInputPart::readTiles()decodes attacker-controlled tile bytes into that undersized channel buffer.This PoC uses only a crafted EXR file through the shipped command-line tool.
PoC
From
/home/br0nzu/openexr/v3.4.13:./report/69.\ OpenEXR\ v3.4.13\ exrmetrics\ ILP32\ tiled\ channel\ vector\ heap\ buffer\ overflow/reproduce.shPoC input:
poc_materials/exrmetrics_tiled_w65537_h65537_tw65537_th4.exrValidation evidence
v3.4.13: original rc=139, ASAN rc=134, UBSAN rc=139. current-main: original rc=139, ASAN rc=134, UBSAN rc=139.
Current-main and patch-overlap logs are saved under
logs/fresh_current_main_ilp32_*andvalidation_summary.txtin this directory.Original crash stderr:
timeout: the monitored command dumped coreFull ASAN output
================================================================= ==2540514==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf75ee802 at pc 0x5664678a bp 0xffd85148 sp 0xffd84d20 WRITE of size 131074 at 0xf75ee802 thread T0 #0 0x56646789 in pread64 (/home/br0nzu/openexr/v3.4.13/report/69. OpenEXR v3.4.13 exrmetrics ILP32 tiled channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0xcc789) (BuildId: 676a5c8917ae2e87249d3288cbe81298456a53a1) #1 0x568a56c1 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 0x568a0b46 in dispatch_read /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/context.c:51:16 #3 0x5692676b in read_uncompressed_direct /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:131:18 #4 0x569274a7 in exr_decoding_run /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXRCore/decoding.c:567:10 #5 0x567bf1e5 in Imf_3_4::(anonymous namespace)::TileProcess::run_decode(_priv_exr_context_t const*, int, Imf_3_4::FrameBuffer const*, 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/ImfTiledInputFile.cpp:913:28 #6 0x567b7ecc in Imf_3_4::TiledInputFile::Data::readTiles(int, int, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfTiledInputFile.cpp:825:20 #7 0x567b73e0 in Imf_3_4::TiledInputFile::readTiles(int, int, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfTiledInputFile.cpp:313:16 #8 0x567c30df in Imf_3_4::TiledInputPart::readTiles(int, int, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfTiledInputPart.cpp:166:11 #9 0x5671d3c3 in readTiled(Imf_3_4::TiledInputPart&, std::vector<Imf_3_4::FrameBuffer, std::allocator<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:253:20 #10 0x56724457 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:701:13 #11 0x567289f2 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 #12 0x5670bf2d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/main.cpp:540:41 #13 0xf7971cb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #14 0xf7971d7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) #15 0x5662a816 in _start (/home/br0nzu/openexr/v3.4.13/report/69. OpenEXR v3.4.13 exrmetrics ILP32 tiled channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0xb0816) (BuildId: 676a5c8917ae2e87249d3288cbe81298456a53a1) 0xf75ee802 is located 0 bytes after 262146-byte region [0xf75ae800,0xf75ee802) allocated by thread T0 here: #0 0x567045db in operator new(unsigned int) (/home/br0nzu/openexr/v3.4.13/report/69. OpenEXR v3.4.13 exrmetrics ILP32 tiled channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0x18a5db) (BuildId: 676a5c8917ae2e87249d3288cbe81298456a53a1) #1 0x5672ecea 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 0x5672ecea 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 0x5672ecea 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 0x5672ecea 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 0x5671c725 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 0x5671c725 in initTiled(std::vector<std::vector<std::vector<char, std::allocator<char>>, std::allocator<std::vector<char, std::allocator<char>>>>, std::allocator<std::vector<std::vector<char, std::allocator<char>>, std::allocator<std::vector<char, std::allocator<char>>>>>>&, std::vector<Imf_3_4::FrameBuffer, std::allocator<Imf_3_4::FrameBuffer>>&, Imf_3_4::TiledInputPart&, Imf_3_4::Header const&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:208:58 #7 0x56723ae1 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:688:41 #8 0x567289f2 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 0x5670bf2d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/main.cpp:540:41 #10 0xf7971cb8 (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/br0nzu/openexr/v3.4.13/report/69. OpenEXR v3.4.13 exrmetrics ILP32 tiled channel vector heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0xcc789) (BuildId: 676a5c8917ae2e87249d3288cbe81298456a53a1) in pread64 Shadow bytes around the buggy address: 0xf75ee580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf75ee600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf75ee680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf75ee700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0xf75ee780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0xf75ee800:[02]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf75ee880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf75ee900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf75ee980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf75eea00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0xf75eea80: 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 ==2540514==ABORTING timeout: the monitored command dumped coreFull UBSAN output
timeout: the monitored command dumped coreImpact
Impact is ILP32-specific. Workflows that run ILP32
exrmetricson untrusted tiled EXR files can be crashed and can write decoded tile bytes past a heap allocation.
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”