Firefox · SpiderMonkey
CVE-2026-2797
UAF in SpiderMonkey
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
whilejs/src/gc/Sweeping.cpp |
modified | |
ifjs/src/gc/WeakMap-inl.h |
modified |
Files Changed
js/src/gc/GCRuntime.hjs/src/gc/Marking.cppjs/src/gc/Sweeping.cppjs/src/gc/WeakMap-inl.h
Patch
diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h
index bfc30f41741..b426ca29a66 100644
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -871,6 +871,7 @@ class GCRuntime {
template <class ZoneIterT>
IncrementalProgress markWeakReferences(JS::SliceBudget& budget);
+ void markIncomingSymbolEdgesFromUncollectedZones();
IncrementalProgress markWeakReferencesInCurrentGroup(JS::SliceBudget& budget);
IncrementalProgress markGrayRoots(JS::SliceBudget& budget,
gcstats::PhaseKind phase);
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index 7bc2961f878..5b7e74e843e 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2406,6 +2406,7 @@ IncrementalProgress JS::Zone::enterWeakMarkingMode(GCMarker* marker,
// all values are marked if both their map and key are marked -- though note
// that we may later leave weak marking mode, do some more marking, and then
// enter back in.
+
if (!isGCMarking()) {
return IncrementalProgress::Finished;
}
@@ -2413,8 +2414,8 @@ IncrementalProgress JS::Zone::enterWeakMarkingMode(GCMarker* marker,
for (auto r = gcEphemeronEdges().all(); !r.empty(); r.popFront()) {
Cell* src = r.front().key();
CellColor srcColor = gc::detail::GetEffectiveColor(marker, src);
- auto& edges = r.front().value();
+ auto& edges = r.front().value();
size_t numEdges = edges.length();
if (IsMarked(srcColor) && edges.length() > 0) {
marker->markEphemeronEdges(edges, AsMarkColor(srcColor));
diff --git a/js/src/gc/Sweeping.cpp b/js/src/gc/Sweeping.cpp
index 23a2cb6e35c..323520bebef 100644
--- a/js/src/gc/Sweeping.cpp
+++ b/js/src/gc/Sweeping.cpp
@@ -47,6 +47,7 @@
#include "vm/Time.h"
#include "vm/WrapperObject.h"
+#include "gc/AtomMarking-inl.h"
#include "gc/PrivateIterators-inl.h"
#include "vm/GeckoProfiler-inl.h"
#include "vm/JSObject-inl.h"
@@ -665,6 +666,8 @@ IncrementalProgress GCRuntime::markWeakReferences(
}
}
+ markIncomingSymbolEdgesFromUncollectedZones();
+
bool markedAny = true;
while (markedAny) {
if (!marker().markUntilBudgetExhausted(budget)) {
@@ -689,6 +692,33 @@ IncrementalProgress GCRuntime::markWeakReferences(
return Finished;
}
+void GCRuntime::markIncomingSymbolEdgesFromUncollectedZones() {
+ // We need to mark ephemeron edges where the source is a live symbol that is
+ // referenced from an uncollected zone and which may not have been marked in
+ // this GC. At the same time we want to avoid unnecessarily holding on to
+ // symbols in zones GCs (by marking them as referenced in the atom marking
+ // bitmap), which is why we don't just mark all such symbols at the start of
+ // GC.
+ //
+ // Atoms referenced by uncollected zones will be marked later in
+ // updateAtomsBitmap() which prevents them dying, but since this is after
+ // we've done ephemeron marking it won't mark through the ephemeron edges.
+
+ if (!atomsZone()->isGCMarking()) {
+ return;
+ }
+
+ for (auto iter = atomsZone()->gcEphemeronEdges().iter(); !iter.done();
+ iter.next()) {
+ auto* symbol = iter.get().key()->as<JS::Symbol>();
+ if (isSymbolReferencedByUncollectedZone(symbol, marker().markColor())) {
+ TraceManuallyBarrieredEdge(marker().tracer(), &symbol,
+ "incoming symbol edge");
+ MOZ_ASSERT(symbol == iter.get().key());
+ }
+ }
+}
+
IncrementalProgress GCRuntime::markWeakReferencesInCurrentGroup(
SliceBudget& budget) {
return markWeakReferences<SweepGroupZonesIter>(budget);
diff --git a/js/src/gc/WeakMap-inl.h b/js/src/gc/WeakMap-inl.h
index 2633610ad03..906217aad32 100644
--- a/js/src/gc/WeakMap-inl.h
+++ b/js/src/gc/WeakMap-inl.h
@@ -192,19 +192,6 @@ bool WeakMap<K, V, AP>::markEntry(GCMarker* marker, gc::CellColor mapColor,
gc::Cell* keyCell = gc::ToMarkable(key);
MOZ_ASSERT(keyCell);
- bool keyIsSymbol = gc::detail::IsSymbol(key.get());
- MOZ_ASSERT(keyIsSymbol == (keyCell->getTraceKind() == JS::TraceKind::Symbol));
- if (keyIsSymbol) {
- // For symbols, also check whether it it is referenced by an uncollected
- // zone, and if so mark it now. There's no need to set |marked| as this
- // would have been marked later anyway.
- auto* sym = static_cast<JS::Symbol*>(keyCell);
- if (marker->runtime()->gc.isSymbolReferencedByUncollectedZone(
- sym, marker->markColor())) {
- TraceEdge(trc, &key, "WeakMap symbol key");
- }
- }
-
bool marked = false;
CellColor markColor = AsCellColor(marker->markColor());
CellColor keyColor = gc::detail::GetEffectiveColor(marker, key.get());
Loading diff…
References
On This Page