-
Notifications
You must be signed in to change notification settings - Fork 481
Open
Description
Description
We discovered a Heap-use-after-free (UAF) vulnerability in OpenColorIO (OCIO). The crash occurs specifically when processing invalid regular expressions within the FileRules section of a YAML configuration.
The issue manifests in OpenColorIO::ThrowInvalidRegex, where the application attempts to read a string (via strlen) from a memory region that was just freed by the internal state management of std::regex.
Environment
- OS: Linux x86_64
- Complier: Clang with -fsanitize=address
- Build Configure: Release
- Affected Version:
master branch
Vulnerability Details
- Target: OpenColorIO (v2.5 dev)
- Vulnerability Type: Heap-use-after-free (READ of size 1)
- Severity: High (Denial of Service / Potential Memory Corruption)
- Source File: src/OpenColorIO/FileRules.cpp
- Function: OpenColorIO_v2_5dev::(anonymous namespace)::ThrowInvalidRegex
- Line Number: 55
- Root Cause Analysis:
- The application parses a YAML config containing a FileRule with a pattern.
- ValidateRegularExpression calls BuildRegularExpression (Frame #-5), which eventually invokes the std::regex compiler.
- During regex compilation (std::basic_regex::_M_compile), the internal NFA state vector reallocates memory (_M_realloc_insert), freeing the old buffer (as seen in the "freed by thread T0" stack trace).
- Crucially, when an error is detected or an exception is thrown during this process, the code enters ThrowInvalidRegex (Frame #-3).
- Inside ThrowInvalidRegex (Line 55), the code attempts to construct a std::string (Frame #-2) from a pointer. The ASAN report indicates this pointer points to the memory region that was just freed by the regex engine's reallocation.
- This suggests that ThrowInvalidRegex is accessing a dangling pointer, possibly referring to a part of the regex pattern or an internal error message string that became invalid after the vector resizing.
Reproduce
- Compile the ocio test harness with AddressSanitizer enabled (-fsanitize=address -g)
- Run the harness with the attached repro input:
./harness < repro
ASAN report
==13647==ERROR: AddressSanitizer: heap-use-after-free on address 0x5080000011fc at pc 0x55874bd813c7 bp 0x7ffde69ad190 sp 0x7ffde69ac958
READ of size 1 at 0x5080000011fc thread T0
#0 0x55874bd813c6 in strlen (/src/OpenColorIO/build/harness_ocio+0x453c6) (BuildId: 83a4ad1aabb1626c20201cde350ca93bff741638)
#1 0x7fed531598ca in std::char_traits<char>::length(char const*) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/char_traits.h:399:9
#2 0x7fed531598ca in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>::basic_string<std::allocator<char>>(char const*, std::allocator<char> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/basic_string.h:648:30
#3 0x7fed53a62f08 in OpenColorIO_v2_5dev::(anonymous namespace)::ThrowInvalidRegex(char const*, char const*) /src/OpenColorIO/src/OpenColorIO/FileRules.cpp:55:26
...
#10 0x7fed53b8ba69 in OpenColorIO_v2_5dev::(anonymous namespace)::load(YAML::Node const&, std::shared_ptr<OpenColorIO_v2_5dev::Config>&, char const*) /src/OpenColorIO/src/OpenColorIO/OCIOYaml.cpp:4605:21
#11 0x7fed53b7de5d in OpenColorIO_v2_5dev::OCIOYaml::Read(std::istream&, std::shared_ptr<OpenColorIO_v2_5dev::Config>&, char const*) /src/OpenColorIO/src/OpenColorIO/OCIOYaml.cpp:5418:9
#12 0x7fed53454034 in OpenColorIO_v2_5dev::Config::Impl::Read(std::istream&, char const*) /src/OpenColorIO/src/OpenColorIO/Config.cpp:5543:5
#13 0x7fed5344cfa6 in OpenColorIO_v2_5dev::Config::CreateFromStream(std::istream&) /src/OpenColorIO/src/OpenColorIO/Config.cpp:1211:12
#14 0x55874be4d405 in main /src/OpenColorIO/harness_ocio.cpp:33:49
#15 0x7fed529da1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#16 0x7fed529da28a in __libc_start_main csu/../csu/libc-start.c:360:3
#17 0x55874bd694d4 in _start (/src/OpenColorIO/build/harness_ocio+0x2d4d4) (BuildId: 83a4ad1aabb1626c20201cde350ca93bff741638)
0x5080000011fc is located 92 bytes inside of 96-byte region [0x5080000011a0,0x508000001200)
freed by thread T0 here:
#0 0x55874be4b606 in operator delete(void*, unsigned long) (/src/OpenColorIO/build/harness_ocio+0x10f606) (BuildId: 83a4ad1aabb1626c20201cde350ca93bff741638)
#1 0x7fed5338e6e8 in std::__new_allocator<std::__detail::_State<char>>::deallocate(std::__detail::_State<char>*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:172:2
#2 0x7fed5338e6e8 in std::allocator_traits<std::allocator<std::__detail::_State<char>>>::deallocate(std::allocator<std::__detail::_State<char>>&, std::__detail::_State<char>*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:517:13
#3 0x7fed5338e6e8 in std::_Vector_base<std::__detail::_State<char>, std::allocator<std::__detail::_State<char>>>::_M_deallocate(std::__detail::_State<char>*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:390:4
#4 0x7fed5338e6e8 in void std::vector<std::__detail::_State<char>, std::allocator<std::__detail::_State<char>>>::_M_realloc_insert<std::__detail::_State<char>>(__gnu_cxx::__normal_iterator<std::__detail::_State<char>*, std::vector<std::__detail::_State<char>, std::allocator<std::__detail::_State<char>>>>, std::__detail::_State<char>&&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:519:7
#5 0x7fed5338cd75 in std::__detail::_State<char>& std::vector<std::__detail::_State<char>, std::allocator<std::__detail::_State<char>>>::emplace_back<std::__detail::_State<char>>(std::__detail::_State<char>&&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:123:4
#6 0x7fed5338cd75 in std::vector<std::__detail::_State<char>, std::allocator<std::__detail::_State<char>>>::push_back(std::__detail::_State<char>&&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:1299:9
#7 0x7fed5338cd75 in std::__detail::_NFA<std::__cxx11::regex_traits<char>>::_M_insert_state(std::__detail::_State<char>) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/regex_automaton.h:328:8
...
#26 0x7fed53b8ba69 in OpenColorIO_v2_5dev::(anonymous namespace)::load(YAML::Node const&, std::shared_ptr<OpenColorIO_v2_5dev::FileRules>&, bool&) /src/OpenColorIO/src/OpenColorIO/OCIOYaml.cpp:4180:21
#27 0x7fed53b8ba69 in OpenColorIO_v2_5dev::(anonymous namespace)::load(YAML::Node const&, std::shared_ptr<OpenColorIO_v2_5dev::Config>&, char const*) /src/OpenColorIO/src/OpenColorIO/OCIOYaml.cpp:4605:21
#28 0x7fed53b7de5d in OpenColorIO_v2_5dev::OCIOYaml::Read(std::istream&, std::shared_ptr<OpenColorIO_v2_5dev::Config>&, char const*) /src/OpenColorIO/src/OpenColorIO/OCIOYaml.cpp:5418:9
#29 0x7fed53454034 in OpenColorIO_v2_5dev::Config::Impl::Read(std::istream&, char const*) /src/OpenColorIO/src/OpenColorIO/Config.cpp:5543:5
#30 0x7fed5344cfa6 in OpenColorIO_v2_5dev::Config::CreateFromStream(std::istream&) /src/OpenColorIO/src/OpenColorIO/Config.cpp:1211:12
#31 0x55874be4d405 in main /src/OpenColorIO/harness_ocio.cpp:33:49
#32 0x7fed529da1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#33 0x7fed529da28a in __libc_start_main csu/../csu/libc-start.c:360:3
#34 0x55874bd694d4 in _start (/src/OpenColorIO/build/harness_ocio+0x2d4d4) (BuildId: 83a4ad1aabb1626c20201cde350ca93bff741638)
previously allocated by thread T0 here:
#0 0x55874be4a981 in operator new(unsigned long) (/src/OpenColorIO/build/harness_ocio+0x10e981) (BuildId: 83a4ad1aabb1626c20201cde350ca93bff741638)
#1 0x7fed5338db6c in std::__new_allocator<std::__detail::_State<char>>::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/new_allocator.h:151:27
#2 0x7fed5338db6c in std::allocator_traits<std::allocator<std::__detail::_State<char>>>::allocate(std::allocator<std::__detail::_State<char>>&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/alloc_traits.h:482:20
#3 0x7fed5338db6c in std::_Vector_base<std::__detail::_State<char>, std::allocator<std::__detail::_State<char>>>::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/stl_vector.h:381:20
...
#22 0x7fed53b8ba69 in OpenColorIO_v2_5dev::(anonymous namespace)::load(YAML::Node const&, std::shared_ptr<OpenColorIO_v2_5dev::Config>&, char const*) /src/OpenColorIO/src/OpenColorIO/OCIOYaml.cpp:4605:21
#23 0x7fed53b7de5d in OpenColorIO_v2_5dev::OCIOYaml::Read(std::istream&, std::shared_ptr<OpenColorIO_v2_5dev::Config>&, char const*) /src/OpenColorIO/src/OpenColorIO/OCIOYaml.cpp:5418:9
#24 0x7fed53454034 in OpenColorIO_v2_5dev::Config::Impl::Read(std::istream&, char const*) /src/OpenColorIO/src/OpenColorIO/Config.cpp:5543:5
#25 0x7fed5344cfa6 in OpenColorIO_v2_5dev::Config::CreateFromStream(std::istream&) /src/OpenColorIO/src/OpenColorIO/Config.cpp:1211:12
#26 0x55874be4d405 in main /src/OpenColorIO/harness_ocio.cpp:33:49
#27 0x7fed529da1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#28 0x7fed529da28a in __libc_start_main csu/../csu/libc-start.c:360:3
#29 0x55874bd694d4 in _start (/src/OpenColorIO/build/harness_ocio+0x2d4d4) (BuildId: 83a4ad1aabb1626c20201cde350ca93bff741638)
SUMMARY: AddressSanitizer: heap-use-after-free (/src/OpenColorIO/build/harness_ocio+0x453c6) (BuildId: 83a4ad1aabb1626c20201cde350ca93bff741638) in strlen
Shadow bytes around the buggy address:
0x508000000f00: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
0x508000000f80: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
0x508000001000: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
0x508000001080: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 05 fa
0x508000001100: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 05 fa
=>0x508000001180: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd[fd]
0x508000001200: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
0x508000001280: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
0x508000001300: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 05 fa
0x508000001380: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x508000001400: 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
==13647==ABORTING
Metadata
Metadata
Assignees
Labels
No labels