Fedora Account System
Red Hat Associate
Red Hat Customer
AI_ONLY_REPORT package: gcc-toolset-15-gcc-15.2.1-7.el10 ------ Summary: `__gnu_pbds::detail::binary_heap::erase_if` use-after-free and stale-pointer free in reallocation path: calling `erase_if` on a `binary_heap_tag`-backed pb_ds priority queue can leave the internal entry-array pointer dangling, leading to heap use-after-free during `make_heap()` and a later stale-pointer free during cleanup. Requirements to exploit: An attacker needs a path to make an application built from this SRPM instantiate `__gnu_pbds::priority_queue<..., binary_heap_tag>` and call `erase_if`; once that public API path is exercised, subsequent heap operations or object teardown can act on freed storage. Component affected: `gcc-toolset-15-gcc-15.2.1-7.el10`, `libstdc++-v3/include/ext/pb_ds/detail/binary_heap_/erase_fn_imps.hpp`, `__gnu_pbds::detail::binary_heap::erase_if` Version affected: `gcc-toolset-15-gcc-15.2.1-7.el10` Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H - 7.8 (HIGH) AV:L - Exploitation requires reaching this local library API in a process using the affected pb_ds container path. AC:L - Once `binary_heap_tag` and `erase_if` are in use, the vulnerable sequence is straightforward to trigger. PR:N - No privileges are required beyond reaching the affected call path in the target process. UI:N - No separate user interaction is required. S:U - The resulting corruption stays within the security scope of the calling process. C:L - In-process memory misuse could expose some data, but broader disclosure is not established here. I:L - Heap corruption can alter in-process state, but arbitrary code execution is not demonstrated by the available evidence. A:H - Use-after-free and stale-pointer free conditions are likely to crash or seriously destabilize the affected process. Impact: Moderate. This is a real memory-corruption flaw with likely process-level availability impact and some in-process integrity or confidentiality risk, but exploitability is limited to consumers that opt into the pb_ds `binary_heap_tag` backend and invoke `erase_if` on that path. Under Red Hat's severity guidance, that narrower, non-default reachability fits Moderate more closely than Important or Critical. Embargo: no Reason: The issue is local and API-specific, with no evidence of default remote exposure in the shipped package. Public coordination without extended embargo is proportionate unless a broadly exposed consumer of this path is identified. Acknowledgement: Aisle Research Vulnerability Details: The pb_ds binary heap backend reallocates the entry array inside `erase_if`, but does not update `m_a_entries` to the new allocation before continuing. The vulnerable block is: ```cpp const size_type new_size = resize_policy::get_new_size_for_arbitrary(left); entry_pointer new_entries = s_entry_allocator.allocate(new_size); std::copy(m_a_entries, m_a_entries + left, new_entries); s_entry_allocator.deallocate(m_a_entries, m_actual_size); m_actual_size = new_size; resize_policy::notify_arbitrary(m_actual_size); ``` After that, `erase_if` rebuilds the heap: ```cpp m_size = left; make_heap(); ``` `make_heap()` uses `m_a_entries` directly: ```cpp entry_pointer end = m_a_entries + m_size; std::make_heap(m_a_entries, end, m_cmp); ``` Because `m_a_entries = new_entries;` is missing, `make_heap()` operates on freed storage after successful reallocation. Later cleanup may deallocate the stale `m_a_entries` again, leading to an invalid free or double-free condition. Nearby reallocation paths in the same component do update `m_a_entries`, which supports that this omission is unintended. Steps to reproduce: 1. Build a small C++ test with AddressSanitizer enabled and use pb_ds `priority_queue` with `binary_heap_tag`. 2. Insert enough elements to force dynamic storage growth. 3. Call `erase_if` with a predicate that removes entries. 4. Continue heap activity, or allow the object to destruct. 5. Observe invalid memory behavior, typically a use-after-free during heap repair and potentially an invalid free during teardown. Minimal PoC: ```cpp #include <ext/pb_ds/priority_queue.hpp> using namespace __gnu_pbds; int main() { priority_queue<int, std::less<int>, binary_heap_tag> q; for (int i = 0; i < 1000; ++i) q.push; q.erase_if([](const int& v) { return (v % 2) == 0; }); q.push(42); q.pop(); } ``` Mitigation: Until a fixed package is available, avoid calling `erase_if` on `__gnu_pbds::priority_queue` instances that use `binary_heap_tag` in code built from this SRPM. If predicate-based removal is required, use an alternative container or backend, or rebuild with the patch below applied. Proposed Fix: Store the replacement entry array in `m_a_entries` before freeing the old array, and copy from the saved old pointer. ```diff diff --git a/libstdc++-v3/include/ext/pb_ds/detail/binary_heap_/erase_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/binary_heap_/erase_fn_imps.hpp @@ -118,9 +118,11 @@ PB_DS_CLASS_C_DEC::erase_if(Pred pred) const size_type new_size = resize_policy::get_new_size_for_arbitrary(left); + entry_pointer old_entries = m_a_entries; entry_pointer new_entries = s_entry_allocator.allocate(new_size); std::copy(m_a_entries, m_a_entries + left, new_entries); s_entry_allocator.deallocate(m_a_entries, m_actual_size); + std::copy(old_entries, old_entries + left, new_entries); + m_a_entries = new_entries; + s_entry_allocator.deallocate(old_entries, m_actual_size); m_actual_size = new_size; resize_policy::notify_arbitrary(m_actual_size); ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use
Upstream has been fixed.