Skip to content

GHSA-xc77-xm9h-qxm4 on CTRL-OS 26.05

Aliases: GHSA-xc77-xm9h-qxm4

Packages: openexr

Status: Plausible

Advisory Information

poc.zip

Summary

A malformed deep tiled EXR with a positive 65537 x 65537 dataWindow can make the shipped exrmetrics tool corrupt heap memory on ILP32 builds. initAndReadDeepTiled() computes numPixels as 64-bit but passes it to std::vector<int>::resize(size_type) for the deep tiled sample-count table, which truncates on 32-bit builds. Fresh validation also reproduced the same behavior on current main.

Details

The truncated sampleCount vector is registered as the sample-count slice. DeepTiledInputPart::readPixelSampleCounts() then copies tile sample-count data for the declared image into that undersized vector, producing an out-of-bounds heap write.

This PoC uses only a crafted EXR file through the shipped command-line tool.

PoC

From /home/br0nzu/openexr/v3.4.13:

./report/71.\ OpenEXR\ v3.4.13\ exrmetrics\ ILP32\ deep\ tiled\ sampleCount\ heap\ buffer\ overflow/reproduce.sh

PoC input: poc_materials/exrmetrics_deep_tiled_w65537_h65537_tw65537_th4.exr

Validation evidence

v3.4.13: original rc=139, ASAN rc=134, UBSAN rc=134. current-main: original rc=139, ASAN rc=134, UBSAN rc=134.

Current-main and patch-overlap logs are saved under logs/fresh_current_main_ilp32_* and validation_summary.txt in this directory.

Original crash stderr:

timeout: the monitored command dumped core

Full ASAN output

=================================================================
==2995361==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf72fe804 at pc 0x566c5f42 bp 0xffdb9068 sp 0xffdb8c40
WRITE of size 262148 at 0xf72fe804 thread T0
    #0 0x566c5f41 in __asan_memcpy (/home/br0nzu/openexr/v3.4.13/report/71. OpenEXR v3.4.13 exrmetrics ILP32 deep tiled sampleCount heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0x145f41) (BuildId: 6bc8ac4c4e2527ef7300f003242cf56d2d5d03eb)
    #1 0x56831b0e in Imf_3_4::(anonymous namespace)::TileProcess::copy_sample_count(Imf_3_4::DeepFrameBuffer const*, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:1238:13
    #2 0x56831b0e in Imf_3_4::(anonymous namespace)::TileProcess::run_decode(_priv_exr_context_t const*, int, Imf_3_4::DeepFrameBuffer const*, std::vector<Imf_3_4::DeepSlice, std::allocator<Imf_3_4::DeepSlice>> const&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:1072:5
    #3 0x56829aec in Imf_3_4::DeepTiledInputFile::Data::readTiles(int, int, int, int, int, int, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:968:20
    #4 0x5682e6ac in Imf_3_4::DeepTiledInputFile::readPixelSampleCounts(int, int, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:690:16
    #5 0x567477bf in Imf_3_4::DeepTiledInputPart::readPixelSampleCounts(int, int, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputPart.cpp:200:11
    #6 0x56726f86 in initAndReadDeepTiled(std::vector<int, std::allocator<int>>&, std::vector<std::vector<char, std::allocator<char>>, std::allocator<std::vector<char, std::allocator<char>>>>&, std::vector<std::vector<char*, std::allocator<char*>>, std::allocator<std::vector<char*, std::allocator<char*>>>>&, Imf_3_4::DeepFrameBuffer&, Imf_3_4::DeepTiledInputPart&, std::vector<int, std::allocator<int>> const*, Imf_3_4::Header const&, std::vector<double, std::allocator<double>>&, std::vector<double, std::allocator<double>>&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:533:12
    #7 0x567297e9 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:735:41
    #8 0x5672e9f2 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 0x56711f2d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/main.cpp:540:41
    #10 0xf78e7cb8  (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947)
    #11 0xf78e7d7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947)
    #12 0x56630816 in _start (/home/br0nzu/openexr/v3.4.13/report/71. OpenEXR v3.4.13 exrmetrics ILP32 deep tiled sampleCount heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0xb0816) (BuildId: 6bc8ac4c4e2527ef7300f003242cf56d2d5d03eb)

0xf72fe804 is located 0 bytes after 524292-byte region [0xf727e800,0xf72fe804)
allocated by thread T0 here:
    #0 0x5670a5db in operator new(unsigned int) (/home/br0nzu/openexr/v3.4.13/report/71. OpenEXR v3.4.13 exrmetrics ILP32 deep tiled sampleCount heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0x18a5db) (BuildId: 6bc8ac4c4e2527ef7300f003242cf56d2d5d03eb)
    #1 0x56736070 in std::__new_allocator<int>::allocate(unsigned int, void const*) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27
    #2 0x56736070 in std::allocator_traits<std::allocator<int>>::allocate(std::allocator<int>&, unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20
    #3 0x56736070 in std::_Vector_base<int, std::allocator<int>>::_M_allocate(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20
    #4 0x56736070 in std::vector<int, std::allocator<int>>::_M_default_append(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:663:34
    #5 0x56726abe in std::vector<int, std::allocator<int>>::resize(unsigned int) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:1016:4
    #6 0x56726abe in initAndReadDeepTiled(std::vector<int, std::allocator<int>>&, std::vector<std::vector<char, std::allocator<char>>, std::allocator<std::vector<char, std::allocator<char>>>>&, std::vector<std::vector<char*, std::allocator<char*>>, std::allocator<std::vector<char*, std::allocator<char*>>>>&, Imf_3_4::DeepFrameBuffer&, Imf_3_4::DeepTiledInputPart&, std::vector<int, std::allocator<int>> const*, Imf_3_4::Header const&, std::vector<double, std::allocator<double>>&, std::vector<double, std::allocator<double>>&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:496:17
    #7 0x567297e9 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:735:41
    #8 0x5672e9f2 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 0x56711f2d in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/main.cpp:540:41
    #10 0xf78e7cb8  (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/br0nzu/openexr/v3.4.13/report/71. OpenEXR v3.4.13 exrmetrics ILP32 deep tiled sampleCount heap buffer overflow/repro_build/bin/exrmetrics_ilp32_asan+0x145f41) (BuildId: 6bc8ac4c4e2527ef7300f003242cf56d2d5d03eb) in __asan_memcpy
Shadow bytes around the buggy address:
  0xf72fe580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xf72fe600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xf72fe680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xf72fe700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xf72fe780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0xf72fe800:[04]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf72fe880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf72fe900: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf72fe980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf72fea00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf72fea80: 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
==2995361==ABORTING
timeout: the monitored command dumped core

Full UBSAN output

UndefinedBehaviorSanitizer:DEADLYSIGNAL
==2995365==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0xf790800c (pc 0xf7a7c430 bp 0xffd27198 sp 0xffd27028 T2995365)
==2995365==The signal is caused by a WRITE memory access.
    #0 0xf7a7c430  (/lib/i386-linux-gnu/libc.so.6+0x187430) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947)
    #1 0x56768cc7 in Imf_3_4::(anonymous namespace)::TileProcess::copy_sample_count(Imf_3_4::DeepFrameBuffer const*, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:1238:13
    #2 0x56768cc7 in Imf_3_4::(anonymous namespace)::TileProcess::run_decode(_priv_exr_context_t const*, int, Imf_3_4::DeepFrameBuffer const*, std::vector<Imf_3_4::DeepSlice, std::allocator<Imf_3_4::DeepSlice>> const&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:1072:5
    #3 0x5676433b in Imf_3_4::DeepTiledInputFile::Data::readTiles(int, int, int, int, int, int, bool) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:968:20
    #4 0x56766e37 in Imf_3_4::DeepTiledInputFile::readPixelSampleCounts(int, int, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputFile.cpp:690:16
    #5 0x566a188b in Imf_3_4::DeepTiledInputPart::readPixelSampleCounts(int, int, int, int, int, int) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/lib/OpenEXR/ImfDeepTiledInputPart.cpp:200:11
    #6 0x566902a8 in initAndReadDeepTiled(std::vector<int, std::allocator<int>>&, std::vector<std::vector<char, std::allocator<char>>, std::allocator<std::vector<char, std::allocator<char>>>>&, std::vector<std::vector<char*, std::allocator<char*>>, std::allocator<std::vector<char*, std::allocator<char*>>>>&, Imf_3_4::DeepFrameBuffer&, Imf_3_4::DeepTiledInputPart&, std::vector<int, std::allocator<int>> const*, Imf_3_4::Header const&, std::vector<double, std::allocator<double>>&, std::vector<double, std::allocator<double>>&) /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/exrmetrics.cpp:533:12
    #7 0x56691211 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:735:41
    #8 0x56693cf2 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 0x5668671b in main /home/br0nzu/openexr/v3.4.13/sources/openexr-3.4.13/src/bin/exrmetrics/main.cpp:540:41
    #10 0xf7919cb8  (/lib/i386-linux-gnu/libc.so.6+0x24cb8) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947)
    #11 0xf7919d7b in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x24d7b) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947)
    #12 0x56651cf6 in _start (/home/br0nzu/openexr/v3.4.13/report/71. OpenEXR v3.4.13 exrmetrics ILP32 deep tiled sampleCount heap buffer overflow/repro_build/bin/exrmetrics_ilp32_ubsan+0xefcf6) (BuildId: 309dd5e8b16594ca535230814439dc758b3e8668)

UndefinedBehaviorSanitizer can not provide additional info.
SUMMARY: UndefinedBehaviorSanitizer: SEGV (/lib/i386-linux-gnu/libc.so.6+0x187430) (BuildId: 0f6a23454651f08cb9b65ff6544d658177b59947) 
==2995365==ABORTING
timeout: the monitored command dumped core

Impact

Impact is ILP32-specific. Workflows that run ILP32 exrmetrics on untrusted deep tiled EXR files can be crashed and can write sample-count data 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