Bug 2563166 - CVE-2026-114691 gcc14: Integer wrap in `std [fedora-all]
Summary: CVE-2026-114691 gcc14: Integer wrap in `std [fedora-all]
Keywords:
Status: NEW
Alias: None
Product: Fedora
Classification: Fedora
Component: gcc14
Version: rawhide
Hardware: Unspecified
OS: Unspecified
medium
medium
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact:
URL:
Whiteboard: {"flaws": ["ccf7e0dc-596a-4c0b-bb6e-2...
Depends On:
Blocks: CVE-2026-114691
TreeView+ depends on / blocked
 
Reported: 2026-10-28 19:59 UTC by Marco Benatto
Modified: 2026-10-28 19:59 UTC (History)
1 user (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Type: ---
Embargoed:


Attachments (Terms of Use)

Description Marco Benatto 2026-10-28 19:59:14 UTC
Disclaimer: Community trackers are created by Red Hat Product Security team on a best effort basis. Package maintainers are required to ascertain if the flaw indeed affects their package, before starting the update process.

AI_ONLY_REPORT
package: gcc-toolset-15-gcc-15.2.1-7.el10
------
Summary: Integer wrap in `std::vector<bool>` size-to-word conversion can  
bypass expected length checks in constructor/init paths:  
attacker-influenced near-`SIZE_MAX` lengths can wrap the internal  
word-count calculation, leave `vector<bool>` with inconsistent storage and  
logical size state, and later trigger undefined behavior or process  
termination.
Requirements to exploit: An attacker must be able to influence a very large  
element count passed into a `std::vector<bool>` constructor or  
initialization path in code built against the affected `libstdc++`  
implementation, then reach a follow-on operation such as `push_back` or  
`insert`. The exact result depends on allocator and build behavior.
Component affected: `gcc-toolset-15-gcc-15.2.1-7.el10`, specifically the  
`libstdc++` `std::vector<bool>` implementation in  
`libstdc++-v3/include/bits/stl_bvector.h` (`_S_nword`, constructor/init  
paths such as `vector(size_type, ...)` and `_M_initialize`)
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:N/I:N/A:H - 6.2 (MEDIUM)
AV:L - The issue is in a local library/container implementation, and no  
package-specific network-reachable path is established by the available  
evidence.
AC:L - Once a near-wrap size reaches the unchecked constructor/init  
path, the wrap and inconsistent state follow directly without a race or  
similarly uncommon prerequisite.
PR:N - No privileges are required beyond the ability to supply the size  
that reaches the affected code path.
UI:N - No separate user interaction is required.
S:U - The impact remains within the security scope of the consuming  
process.
C:N - The available evidence does not establish a reliable  
confidentiality impact.
I:N - The available evidence does not establish a reliable integrity  
impact beyond undefined behavior.
A:H - The inconsistent container state can lead to sanitizer-detected  
failures, crashes, or process termination in affected applications.
Impact: Moderate. Under Red Hat's severity guidance, this issue is harder  
to exploit than an easy privilege-gain or remote compromise flaw because it  
requires an unusual attacker-controlled near-maximum length to reach an  
unchecked constructor/init path. Even so, the reachable memory-unsafe state  
can still cause denial of service and other undefined behavior in affected  
applications, which is more than minimal impact.
Embargo: no
Reason: The current evidence supports a local, application-specific  
denial-of-service/undefined-behavior condition with demanding input  
preconditions. The record does not currently support a strong claim of easy  
remote compromise or a broadly wormable condition.
Acknowledgement: Aisle Research
Vulnerability Details: The issue is in the packed `std::vector<bool>`  
size-to-word conversion and its unchecked constructor/init path in  
`libstdc++-v3/include/bits/stl_bvector.h`:
```cpp
static size_t
_S_nword(size_t __n)
{ return (__n + int(_S_word_bit) - 1) / int(_S_word_bit); }
...
vector(size_type __n, const bool& __value, const allocator_type& __a =  
allocator_type())
: Base(_a)
{
M_initialize(_n);
M_initialize_value(_value);
}
...
_Bit_pointer _q = this->_M_allocate(_n);
this->_M_impl._M_end_of_storage = __q + S_nword(_n);
iterator _start = iterator(std::addressof(*_q), 0);
this->_M_impl._M_start = __start;
this->_M_impl._M_finish = _start + difference_type(_n);
```
For very large `size_t` inputs, the addition inside `_S_nword` can wrap  
before division. In the affected constructor/init path, allocation and  
`_M_end_of_storage` then follow the wrapped word count, while `_M_finish`  
is advanced from the original requested element count. This can leave  
`std::vector<bool>` in an inconsistent state and later operations can  
encounter out-of-bounds behavior or other undefined behavior. By contrast,  
the available evidence indicates that `reserve` and related growth paths  
apply `max_size()` or `_M_check_len` guards, so the supported reachability  
claim here is the constructor/init path rather than `_M_reallocate` as a  
primary trigger.
Steps to reproduce:
1. Build a small test program against the affected `libstdc++`  
implementation with `-O0 -g -fsanitize=address,undefined`.
2. Use the following test case:
```cpp
#include <vector>
#include <limits>
int main() {
size_t n = std::numeric_limits<size_t>::max() - 31;
std::vector<bool> v(n, true);
v.push_back(false);
}
```
3. Run the program. On an affected build, the constructor can leave the  
container in an inconsistent state, and the subsequent `push_back` may  
trigger a sanitizer finding, crash, or other undefined-behavior symptom.  
The exact manifestation can vary by allocator and build configuration.
Mitigation: Reject externally influenced lengths long before `max_size()`  
or `SIZE_MAX` boundaries, especially for `std::vector<bool>` construction  
and initialization. Where untrusted size inputs are involved, prefer  
explicit application-level limits and avoid relying on the specialization's  
constructor/init path until a fix is applied.
Proposed Fix: A minimal fix is to add checked arithmetic in `_S_nword` and  
to apply constructor/init length validation before calling `_M_initialize`.
```diff
diff --git a/libstdc++-v3/include/bits/stl_bvector.h  
b/libstdc++-v3/include/bits/stl_bvector.h
@@
+#include <limits>
@@
static size_t
_S_nword(size_t __n)
     { return (__n + int(_S_word_bit) - 1) / int(_S_word_bit); }
+      {
+        constexpr size_t __wb = size_t(_S_word_bit);
+        if (_n > (std::numeric_limits<size_t>::max() - (_wb - 1)))
+          _throw_length_error(_N("vector<bool>: size overflow"));
+        return (_n + (_wb - 1)) / __wb;
+      }
@@
+      static size_type
+      _S_check_init_len(size_type __n, const allocator_type& __a)
+      {
+        const size_type __isize =
+          _gnu_cxx::numeric_traits<difference_type>::_max
+          - int(_S_word_bit) + 1;
+        const size_type __asize = _Bit_alloc_traits::max_size(
+          Bit_alloc_type(_a));
+        const size_type _max = (_asize <= __isize / int(_S_word_bit)
+          ? __asize * int(_S_word_bit) : __isize);
+        if (__n > __max)
+          _throw_length_error(_N("cannot create std::vector larger than  
max_size()"));
+        return __n;
+      }
@@

     : Base(_a)
+      : Base(_a)
        {

       M_initialize(_n);
+        M_initialize(_S_check_init_len(_n, __a));
          M_initialize_value(_value);
        }
@@

         M_initialize(_n);
+          M_initialize(_S_check_init_len(_n, _M_get_Bit_allocator()));
            std::copy(__first, __last, begin());
```


------
This report was generated using AI technology. Always review AI-generated  
content prior to use


Note You need to log in before you can comment on or make changes to this bug.