CVE-2025-43501
Overview
Background
- WTF HashTable
- The core open-addressing hash table underlying HashMap/HashSet across WebKit, sized in powers of two.
- Checked<unsigned>
- A wrapper that traps arithmetic overflow instead of wrapping, forcing overflow to be handled rather than silently producing a small value.
- Rehash / best table size
- On growth the table computes a new power-of-two size from the key count; overflow here yields an undersized allocation.
Root Cause Analysis
This fixes an unsigned integer overflow in WTF::HashTable’s size computation that could produce an undersized table allocation and subsequent out-of-bounds access. computeBestTableSize() and rehash() computed table sizes with plain unsigned arithmetic: bestTableSize = roundUpToPowerOfTwo(keyCount) followed by conditional doublings (bestTableSize *= 2), and rehash() derived newSize from oldSize. For a hash table driven to a very large key count, these unsigned multiplications/roundings can overflow 2^32 and wrap to a small value, so the table is allocated far smaller than the number of entries it must hold; reinserting entries then indexes past the allocation — an out-of-bounds read/write and heap corruption.
The fix converts the size accounting to Checked<unsigned> (newSize, oldSize, bestTableSize, and rehash’s newTableSize parameter) so any overflow in the rounding or doubling traps instead of silently wrapping, and returns std::max(bestTableSize.value(), minimumTableSize). It also adds deleteReleasedWeakBuckets(), which sweeps released weak buckets (decrementing keyCount, incrementing deletedCount) before rehash so the count feeding the size computation reflects reclaimed weak entries.
The restored invariant is that table-size math cannot silently wrap to an undersized allocation. The precise overflowing multiply is one of the bestTableSize *= 2 / roundUpToPowerOfTwo steps now wrapped in Checked<unsigned>.
Attack Path
- Grow a hash table Drive a WTF HashTable/HashMap/HashSet (reachable via DOM/JS object bookkeeping) toward an enormous key count.
- Overflow the size math computeBestTableSize/rehash’s unsigned rounding and doubling wrap past 2^32 to a small size.
- Undersized allocation The table backing store is allocated too small for the live entries.
- Out-of-bounds write Reinserting entries indexes beyond the allocation, corrupting the heap in the WebContent process.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
HashTable::computeBestTableSizeSource/WTF/wtf/HashTable.h |
modified | Uses Checked<unsigned> for bestTableSize so roundUpToPowerOfTwo and the *=2 doublings trap on overflow; returns std::max(bestTableSize.value(), minimumTableSize). |
HashTable::rehashSource/WTF/wtf/HashTable.h |
modified | Takes Checked<unsigned> newTableSize and computes newSize/oldSize as Checked<unsigned> to prevent wraparound to an undersized table. |
HashTable::deleteReleasedWeakBucketsSource/WTF/wtf/HashTable.h |
added | Sweeps released weak buckets before rehash (adjusting key/deleted counts) so the size computation is based on live entries. |
Files Changed
Source/WTF/wtf/HashTable.h
Audit Directions
- Same file: residual unsigned mathIn HashTable.h confirm all size/count arithmetic feeding allocation (tableSize, keyCount, deletedCount) is overflow-checked, including reinsert and shrink paths.
- Container size computationsGrep WTF containers (Vector, HashTable, BitVector) for roundUpToPowerOfTwo/*=2 on unsigned sizes without Checked<> before an allocation.