ScopedArgumentsTable moved out of Primitive Gigacage
72272dc
Source/JavaScriptCore/runtime/ScopedArgumentsTable.cpp
- result->m_length = length;
- result->m_arguments = ArgumentsPtr::tryCreate(length);
- if (!result->m_arguments) [[unlikely]]
+ if (!result->m_arguments.tryGrow(length)) [[unlikely]]
return nullptr;
- result->m_watchpointSets.fill(nullptr, length);
+ if (!result->m_watchpointSets.tryGrow(length)) [[unlikely]]
+ return nullptr;
+ std::ranges::fill(result->m_watchpointSets.mutableSpan(), nullptr);
...
- m_watchpointSets.resize(newLength); // mutated locked (immutable) table
- for (unsigned i = std::min(m_length, newLength); i--;) {
- result->at(i) = this->at(i);
+ for (unsigned i = std::min<uint32_t>(m_arguments.size(), newLength); i--;) {
+ result->m_arguments[i] = this->m_arguments[i];
result->m_watchpointSets[i] = this->m_watchpointSets[i];
}
Gigacage is JSC's spatial safety mitigation that confines specific heap allocations to a reserved virtual address region, so a corrupted pointer constrained to the cage cannot escape it. The Primitive cage is intended exclusively for user-payload buffers — TypedArray storage, ArrayBuffer contents, and similar. ScopeOffset is engine-internal metadata that maps a named argument's position in a function's argument list to its variable slot index inside a JSLexicalEnvironment.
This commit moves ScopedArgumentsTable::m_arguments from a CagedUniquePtr<ScopeOffset, Gigacage::Primitive> to a plain Vector<ScopeOffset>, removing engine-internal scope metadata from the Primitive Gigacage. It also removes a stale m_watchpointSets.resize(newLength) call that mutated a supposedly-locked (immutable) table instance in trySetLength.
Significance
This closes a documented cage-pivot path: any write primitive into the Primitive Gigacage (e.g., via a corrupted TypedArray backing store) could previously reach ScopeOffset metadata and turn it into an unchecked index into JSLexicalEnvironment::variables(), enabling out-of-bounds variable slot access.
Audit directions
a Aaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaa Aaaaaa Aaaaaaaa Aaaaaa Aaaa Aaaa Aaaaaaaaaa Aaaa Aaaaaa Aaaaaa Aaa Aaaaaaa Aaaaaaa Aaa Aaa Aaaaaaa Aaaaa Aaaaaaaaa Aaa Aaaaaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaa Aaaa Aa Aaaaaaa Aaa Aaaaaaaaaa Aaaaaa Aaaaa Aaaaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa
a Aaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaa Aaa Aaa Aaa Aaaaa Aaaa Aaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aa Aaaa Aaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaa Aaa Aaaaaaa Aaaa Aaaaaaaaaaaaaaaa Aaaaaaaa a Aaaaaaaaa Aa Aaaaaaaa Aaaaaaaa a Aaaa a Aaaaaaaaaa Aaaaaa Aaaaa Aaa Aaaaaaa Aaaa Aaaaa Aaaaa Aaaaaaa Aaa Aaaaaaa Aa Aaaaa Aaaaaaaaaaaa Aa Aaaaaa Aaaaaa Aaaaa Aaaaaaaaa Aaa Aaaaaaa
a Aaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaaaaa Aaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaa Aaaa Aaa Aaaaaaaaaaaa Aaaaaaaaa Aaa Aaaaa Aaaaaaaa Aaaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaa Aaaaaaaaa Aa Aaaaaaaaa Aa Aaaaa Aaaaaaaaaa Aaa Aaaaa Aaaaaaa Aaa Aaaaaaaaaaaaaaaa Aaaaaa Aaaaa Aaaa Aaaa Aaaaaaaa Aaaaaaa a Aaaa Aaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaa Aaaaaaaaaa Aaa Aaaaaa Aaaaaaa Aaa Aaa Aaaaa Aaaaaa Aaa Aaaaa
🔒Cage-mismatch pattern may recur elsewhere in JSC; JIT layout assumptions and locked-table invariants have additional audit-worthy edge cases.
Subscribe to read more