Firefox · SpiderMonkey
CVE-2026-2766
UAF in SpiderMonkey
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
switchjs/src/jit/CacheIRCompiler.cpp |
modified | |
ifjs/src/jit/CacheIRCompiler.cpp |
modified | |
whilejs/src/jit/JitScript.cpp |
modified | |
ifjs/src/jit/JitScript.cpp |
modified | |
switchjs/src/jit/WarpOracle.cpp |
modified | |
switchjs/src/jit/WarpSnapshot.cpp |
modified |
Files Changed
js/src/jit/BaselineIC.hjs/src/jit/CacheIR.cppjs/src/jit/CacheIR.hjs/src/jit/CacheIRCloner.hjs/src/jit/CacheIRCompiler.cppjs/src/jit/CacheIROps.yamljs/src/jit/CacheIRWriter.hjs/src/jit/GenerateCacheIRFiles.pyjs/src/jit/JitScript.cppjs/src/jit/WarpOracle.cppjs/src/jit/WarpSnapshot.cpp
Patch
diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h
index 5b469b300ac..88de0e06ac7 100644
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -299,7 +299,9 @@ class ICCacheIRStub final : public ICStub {
void trace(JSTracer* trc);
bool traceWeak(JSTracer* trc);
- ICCacheIRStub* clone(JSRuntime* rt, ICStubSpace& newSpace);
+ enum class ICScriptHandling { MarkActive, AssertActive };
+ ICCacheIRStub* clone(JSRuntime* rt, ICStubSpace& newSpace,
+ ICScriptHandling icScriptHandling);
// Returns true if this stub can call JS or VM code that can trigger a GC.
bool makesGCCalls() const;
diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp
index 3ae32cdc03c..1946de33476 100644
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -242,6 +242,9 @@ uint32_t CacheIRCloner::getRawInt32Field(uint32_t stubOffset) {
const void* CacheIRCloner::getRawPointerField(uint32_t stubOffset) {
return reinterpret_cast<const void*>(readStubWord(stubOffset));
}
+const ICScript* CacheIRCloner::getICScriptField(uint32_t stubOffset) {
+ return reinterpret_cast<const ICScript*>(readStubWord(stubOffset));
+}
uint64_t CacheIRCloner::getRawInt64Field(uint32_t stubOffset) {
return static_cast<uint64_t>(readStubInt64(stubOffset));
}
diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h
index 544e3cb7605..893cc2c1801 100644
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -241,6 +241,7 @@ class StubField {
// These fields take up a single word.
RawInt32,
RawPointer,
+ ICScript,
Shape,
WeakShape,
JSObject,
@@ -314,6 +315,8 @@ inline const char* StubFieldTypeName(StubField::Type ty) {
return "RawInt32";
case StubField::Type::RawPointer:
return "RawPointer";
+ case StubField::Type::ICScript:
+ return "ICScript";
case StubField::Type::Shape:
return "Shape";
case StubField::Type::WeakShape:
diff --git a/js/src/jit/CacheIRCloner.h b/js/src/jit/CacheIRCloner.h
index 2ecf37cc2f4..6ccb58619fd 100644
--- a/js/src/jit/CacheIRCloner.h
+++ b/js/src/jit/CacheIRCloner.h
@@ -70,6 +70,7 @@ class MOZ_RAII CacheIRCloner {
JitCode* getJitCodeField(uint32_t stubOffset);
uint32_t getRawInt32Field(uint32_t stubOffset);
const void* getRawPointerField(uint32_t stubOffset);
+ const ICScript* getICScriptField(uint32_t stubOffset);
jsid getIdField(uint32_t stubOffset);
Value getValueField(uint32_t stubOffset);
Value getWeakValueField(uint32_t stubOffset);
diff --git a/js/src/jit/CacheIRCompiler.cpp b/js/src/jit/CacheIRCompiler.cpp
index 3a3825c4d9e..0a4edd05f62 100644
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1127,6 +1127,7 @@ static void InitWordStubField(StubField::Type type, void* dest,
switch (type) {
case StubField::Type::RawInt32:
case StubField::Type::RawPointer:
+ case StubField::Type::ICScript:
case StubField::Type::AllocSite:
*static_cast<uintptr_t*>(dest) = value;
break;
@@ -1188,6 +1189,7 @@ static void InitInt64StubField(StubField::Type type, void* dest,
break;
case StubField::Type::RawInt32:
case StubField::Type::RawPointer:
+ case StubField::Type::ICScript:
case StubField::Type::AllocSite:
case StubField::Type::Shape:
case StubField::Type::WeakShape:
@@ -1217,7 +1219,8 @@ void CacheIRWriter::copyStubData(uint8_t* dest) const {
}
}
-ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace) {
+ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace,
+ ICScriptHandling icScriptHandling) {
const CacheIRStubInfo* info = stubInfo();
MOZ_ASSERT(info->makesGCCalls());
@@ -1250,6 +1253,15 @@ ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace) {
InitWordStubField(type, dest, *srcField);
src += sizeof(uintptr_t);
dest += sizeof(uintptr_t);
+ if (type == StubField::Type::ICScript) {
+ auto* icScript = reinterpret_cast<ICScript*>(*srcField);
+ if (icScriptHandling == ICScriptHandling::MarkActive) {
+ icScript->setActive();
+ } else {
+ MOZ_ASSERT(icScriptHandling == ICScriptHandling::AssertActive);
+ MOZ_RELEASE_ASSERT(icScript->active());
+ }
+ }
} else {
const uint64_t* srcField = reinterpret_cast<const uint64_t*>(src);
InitInt64StubField(type, dest, *srcField);
@@ -1286,6 +1298,7 @@ void jit::TraceCacheIRStub(JSTracer* trc, T* stub,
switch (fieldType) {
case Type::RawInt32:
case Type::RawPointer:
+ case Type::ICScript:
case Type::RawInt64:
case Type::Double:
break;
@@ -1431,6 +1444,7 @@ bool jit::TraceWeakCacheIRStub(JSTracer* trc, T* stub,
return !isDead;
case Type::RawInt32:
case Type::RawPointer:
+ case Type::ICScript:
case Type::Shape:
case Type::JSObject:
case Type::Symbol:
diff --git a/js/src/jit/CacheIROps.yaml b/js/src/jit/CacheIROps.yaml
index 2c9ace66157..310b08360a7 100644
--- a/js/src/jit/CacheIROps.yaml
+++ b/js/src/jit/CacheIROps.yaml
@@ -2064,7 +2064,7 @@
receiver: ObjId
callee: ObjId
rhs: ValId
- icScript: RawPointerField
+ icScript: ICScriptField
sameRealm: BoolImm
nargsAndFlags: RawInt32Field
@@ -2257,7 +2257,7 @@
args:
callee: ObjId
argc: Int32Id
- icScript: RawPointerField
+ icScript: ICScriptField
flags: CallFlagsImm
argcFixed: UInt32Imm
@@ -2704,7 +2704,7 @@
args:
receiver: ValId
callee: ObjId
- icScript: RawPointerField
+ icScript: ICScriptField
sameRealm: BoolImm
nargsAndFlags: RawInt32Field
diff --git a/js/src/jit/CacheIRWriter.h b/js/src/jit/CacheIRWriter.h
index d0b9cc4c064..9d52f04dab8 100644
--- a/js/src/jit/CacheIRWriter.h
+++ b/js/src/jit/CacheIRWriter.h
@@ -237,6 +237,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
void writeRawPointerField(const void* ptr) {
addStubField(uintptr_t(ptr), StubField::Type::RawPointer);
}
+ void writeICScriptField(const ICScript* icScript) {
+ addStubField(uintptr_t(icScript), StubField::Type::ICScript);
+ }
void writeIdField(jsid id) {
addStubField(id.asRawBits(), StubField::Type::Id);
}
diff --git a/js/src/jit/GenerateCacheIRFiles.py b/js/src/jit/GenerateCacheIRFiles.py
index 40c3b504530..6ed6a20aae5 100644
--- a/js/src/jit/GenerateCacheIRFiles.py
+++ b/js/src/jit/GenerateCacheIRFiles.py
@@ -75,6 +75,7 @@ arg_writer_info = {
"JitCodeField": ("JitCode*", "writeJitCodeField"),
"RawInt32Field": ("uint32_t", "writeRawInt32Field"),
"RawPointerField": ("const void*", "writeRawPointerField"),
+ "ICScriptField": ("const ICScript*", "writeICScriptField"),
"IdField": ("jsid", "writeIdField"),
"ValueField": ("const Value&", "writeValueField"),
"WeakValueField": ("const Value&", "writeWeakValueField"),
@@ -181,6 +182,7 @@ arg_reader_info = {
"JitCodeField": ("uint32_t", "Offset", "reader.stubOffset()"),
"RawInt32Field": ("uint32_t", "Offset", "reader.stubOffset()"),
"RawPointerField": ("uint32_t", "Offset", "reader.stubOffset()"),
+ "ICScriptField": ("uint32_t", "Offset", "reader.stubOffset()"),
"IdField": ("uint32_t", "Offset", "reader.stubOffset()"),
"ValueField": ("uint32_t", "Offset", "reader.stubOffset()"),
"WeakValueField": ("uint32_t", "Offset", "reader.stubOffset()"),
@@ -326,6 +328,7 @@ arg_spewer_method = {
"JitCodeField": "spewField",
"RawInt32Field": "spewField",
"RawPointerField": "spewField",
+ "ICScriptField": "spewField",
"IdField": "spewField",
"ValueField": "spewField",
"WeakValueField": "spewField",
@@ -469,6 +472,7 @@ arg_length = {
"JitCodeField": 1,
"RawInt32Field": 1,
"RawPointerField": 1,
+ "ICScriptField": 1,
"RawInt64Field": 1,
"DoubleField": 1,
"IdField": 1,
diff --git a/js/src/jit/JitScript.cpp b/js/src/jit/JitScript.cpp
index dc4151e2581..55b3e0c08c2 100644
--- a/js/src/jit/JitScript.cpp
+++ b/js/src/jit/JitScript.cpp
@@ -552,7 +552,8 @@ void ICScript::purgeStubs(Zone* zone, ICStubSpace& newStubSpace) {
ICCacheIRStub* prev = nullptr;
ICStub* stub = entry.firstStub();
while (stub != fallback) {
- ICCacheIRStub* clone = stub->toCacheIRStub()->clone(rt, newStubSpace);
+ ICCacheIRStub* clone = stub->toCacheIRStub()->clone(
+ rt, newStubSpace, ICCacheIRStub::ICScriptHandling::AssertActive);
if (prev) {
prev->setNext(clone);
} else {
@@ -771,26 +772,26 @@ static void MarkActiveICScriptsAndCopyStubs(
ICCacheIRStub* stub = layout->maybeStubPtr()->toCacheIRStub();
auto lookup = alreadyClonedStubs.lookupForAdd(stub);
if (!lookup) {
- ICCacheIRStub* newStub = stub->clone(cx->runtime(), newStubSpace);
+ ICCacheIRStub* newStub =
+ stub->clone(cx->runtime(), newStubSpace,
+ ICCacheIRStub::ICScriptHandling::MarkActive);
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!alreadyClonedStubs.add(lookup, stub, newStub)) {
oomUnsafe.crash("MarkActiveICScriptsAndCopyStubs");
}
}
layout->setStubPtr(lookup->value());
-
- // If this is a trial-inlining call site, also preserve the callee
- // ICScript. Inlined constructor calls invoke CreateThisFromIC (which
- // can trigger GC) before using the inlined ICScript.
+#ifdef DEBUG
JSJitFrameIter parentFrame(frame);
++parentFrame;
BaselineFrame* blFrame = parentFrame.baselineFrame();
jsbytecode* pc;
parentFrame.baselineScriptAndPc(nullptr, &pc);
uint32_t pcOffset = blFrame->script()->pcToOffset(pc);
- if (blFrame->icScript()->hasInlinedChild(pcOffset)) {
- blFrame->icScript()->findInlinedChild(pcOffset)->setActive();
- }
+ ICScript* icScript = blFrame->icScript();
+ MOZ_ASSERT_IF(icScript->hasInlinedChild(pcOffset),
+ icScript->findInlinedChild(pcOffset)->active());
+#endif
}
break;
}
diff --git a/js/src/jit/WarpOracle.cpp b/js/src/jit/WarpOracle.cpp
index 3539425af80..b03841f81f3 100644
--- a/js/src/jit/WarpOracle.cpp
+++ b/js/src/jit/WarpOracle.cpp
@@ -1570,6 +1570,7 @@ bool WarpScriptOracle::replaceNurseryAndAllocSitePointers(
switch (fieldType) {
case StubField::Type::RawInt32:
case StubField::Type::RawPointer:
+ case StubField::Type::ICScript:
case StubField::Type::RawInt64:
case StubField::Type::Double:
break;
diff --git a/js/src/jit/WarpSnapshot.cpp b/js/src/jit/WarpSnapshot.cpp
index 8d755147761..5d807947a8c 100644
--- a/js/src/jit/WarpSnapshot.cpp
+++ b/js/src/jit/WarpSnapshot.cpp
@@ -379,6 +379,7 @@ void WarpCacheIRBase::traceData(JSTracer* trc) {
switch (fieldType) {
case StubField::Type::RawInt32:
case StubField::Type::RawPointer:
+ case StubField::Type::ICScript:
case StubField::Type::RawInt64:
case StubField::Type::Double:
break;
Loading diff…
References
On This Page