Firefox · SpiderMonkey
CVE-2026-74936
UAF in SpiderMonkey
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
js/src/vm/JitActivation.cppjs/src/vm/JitActivation.h
Patch
diff --git a/js/src/vm/JitActivation.cpp b/js/src/vm/JitActivation.cpp
index 5fff795afc9..4c98a2ec424 100644
--- a/js/src/vm/JitActivation.cpp
+++ b/js/src/vm/JitActivation.cpp
@@ -244,6 +244,14 @@ void js::jit::JitActivation::startWasmTrap(wasm::Trap trap,
const wasm::Code& code = wasm::GetNearestEffectiveInstance(fp)->code();
MOZ_RELEASE_ASSERT(&code == wasm::LookupCode(pc));
+ // Keep the trapping code alive across a GC. For an IndirectCallBadSig trap
+ // reached through a tail call, this code can belong to a different instance
+ // than the effective one above, whose frame has already been unwound. Nothing
+ // else then keeps alive the code segment we are about to run the trap stub
+ // in.
+ wasmTrapCode_ = wasm::LookupCode(state.pc);
+ MOZ_RELEASE_ASSERT(wasmTrapCode_);
+
setWasmExitFP(fp);
wasmTrapData_.emplace();
wasmTrapData_->resumePC =
@@ -271,6 +279,9 @@ void js::jit::JitActivation::finishWasmTrap() {
MOZ_ASSERT(hasWasmExitFP());
MOZ_ASSERT(isWasmTrapping());
wasmTrapData_.reset();
+ // Keep wasmTrapCode_ alive: we are still executing inside this code and are
+ // about to return into it, so releasing it now could free it. It is released
+ // on the next trap or when the activation is destroyed.
packedExitFP_ = nullptr;
MOZ_ASSERT(!isWasmTrapping());
}
diff --git a/js/src/vm/JitActivation.h b/js/src/vm/JitActivation.h
index 4f1b2d4c248..884ff99bf4b 100644
--- a/js/src/vm/JitActivation.h
+++ b/js/src/vm/JitActivation.h
@@ -8,6 +8,7 @@
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Atomics.h" // mozilla::Atomic, mozilla::Relaxed
#include "mozilla/Maybe.h" // mozilla::Maybe
+#include "mozilla/RefPtr.h" // RefPtr
#include <stddef.h> // size_t
#include <stdint.h> // uint8_t, uint32_t, uintptr_t
@@ -94,6 +95,12 @@ class JitActivation : public Activation {
// purposes. Wasm code can't trap reentrantly.
mozilla::Maybe<wasm::TrapData> wasmTrapData_;
+ // Keeps the trapping code alive while the trap is handled. With tail calls
+ // the trapping frame may already be unwound, so no wasm::Frame keeps it alive
+ // and a GC (e.g. while building the RuntimeError) could otherwise free the
+ // code segment we are still executing in.
+ RefPtr<const wasm::Code> wasmTrapCode_;
+
#ifdef CHECK_OSIPOINT_REGISTERS
protected:
// Used to verify that live registers don't change between a VM call and
Loading diff…
References
On This Page