← All issues

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.

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.

🔒

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