High firefox UAF 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionJIT miscompilation, use-after-free in the JavaScript Engine: JIT component
ComponentSpiderMonkey
Bug ClassUAF
Tracker2012608
Fix commit598b58ebea71 (firefox) +24/-23
CISA KEVNot listed
CreditedEvyatar Ben Asher, Keane Lucas, Nicholas Carlini, Newton Cheng, Daniel Freeman, Alex Gaynor, and Joel Weinberger using Claude from Anthropic
Disclosed2026-02-24

Changed Functions

FunctionChangeNotes
if
js/src/jit/BaselineCacheIRCompiler.cpp
modified

Files Changed

  • js/src/jit/BaselineCacheIRCompiler.cpp
  • js/src/jit/BaselineCacheIRCompiler.h
diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp
index 98b2bd29296..a1ca8a84f3d 100644
--- a/js/src/jit/BaselineCacheIRCompiler.cpp
+++ b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -2456,19 +2456,23 @@ bool BaselineCacheIRCompiler::updateArgc(CallFlags flags, Register argcReg,
   return true;
 }
 
-void BaselineCacheIRCompiler::pushArguments(Register argcReg,
-                                            Register calleeReg,
-                                            Register scratch, Register scratch2,
-                                            CallFlags flags, uint32_t argcFixed,
-                                            bool isJitCall) {
+void BaselineCacheIRCompiler::pushArguments(
+    Register argcReg, Register calleeReg, Register scratch, Register scratch2,
+    Register scratch3, CallFlags flags, uint32_t argcFixed, bool isJitCall) {
+  bool isConstructing = flags.isConstructing();
   if (isJitCall) {
+    if (isConstructing) {
+      createThis(argcReg, calleeReg, scratch, scratch2, scratch3, flags,
+                 /* isBoundFunction = */ false);
+    }
+
     // If we're calling jitcode, we have to align the stack and ensure that
     // enough arguments are being passed, filling in any missing arguments
     // with `undefined`. `newTarget` should be pushed after alignment padding
     // but before the `undefined` values, so we also handle it here.
     prepareForArguments(argcReg, calleeReg, scratch, scratch2, flags,
                         argcFixed);
-  } else if (flags.isConstructing()) {
+  } else if (isConstructing) {
     // If we're not calling jitcode, push newTarget now so that the shared
     // paths below can assume it's already pushed.
     pushNewTarget();
@@ -2477,11 +2481,10 @@ void BaselineCacheIRCompiler::pushArguments(Register argcReg,
   switch (flags.getArgFormat()) {
     case CallFlags::Standard:
       pushStandardArguments(argcReg, scratch, scratch2, argcFixed, isJitCall,
-                            flags.isConstructing());
+                            isConstructing);
       break;
     case CallFlags::Spread:
-      pushArrayArguments(argcReg, scratch, scratch2, isJitCall,
-                         flags.isConstructing());
+      pushArrayArguments(argcReg, scratch, scratch2, isJitCall, isConstructing);
       break;
     case CallFlags::FunCall:
       pushFunCallArguments(argcReg, calleeReg, scratch, scratch2, argcFixed,
@@ -2500,6 +2503,12 @@ void BaselineCacheIRCompiler::pushArguments(Register argcReg,
     default:
       MOZ_CRASH("Invalid arg format");
   }
+
+  if (isJitCall) {
+    // Note that we use Push, not push, so that callJit will align the stack
+    // properly on ARM.
+    masm.PushCalleeToken(calleeReg, isConstructing);
+  }
 }
 
 void BaselineCacheIRCompiler::prepareForArguments(
@@ -2928,8 +2937,8 @@ bool BaselineCacheIRCompiler::emitCallNativeShared(
     masm.switchToObjectRealm(calleeReg, scratch);
   }
 
-  pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
-                /*isJitCall =*/false);
+  pushArguments(argcReg, calleeReg, scratch, scratch2, InvalidReg, flags,
+                argcFixed, /*isJitCall =*/false);
 
   // Native functions have the signature:
   //
@@ -3349,17 +3358,9 @@ bool BaselineCacheIRCompiler::emitCallScriptedFunctionShared(
     stubFrame.pushInlinedICScript(masm, stubAddress(*icScriptOffset));
   }
 
-  if (isConstructing) {
-    createThis(argcReg, calleeReg, scratch, scratch2, scratch3, flags,
-               /* isBoundFunction = */ false);
-  }
-
-  pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
-                /*isJitCall =*/true);
+  pushArguments(argcReg, calleeReg, scratch, scratch2, scratch3, flags,
+                argcFixed, /*isJitCall =*/true);
 
-  // Note that we use Push, not push, so that callJit will align the stack
-  // properly on ARM.
-  masm.PushCalleeToken(calleeReg, isConstructing);
   masm.PushFrameDescriptorForJitCall(FrameType::BaselineStub, argcReg, scratch,
                                      isInlined);
 
diff --git a/js/src/jit/BaselineCacheIRCompiler.h b/js/src/jit/BaselineCacheIRCompiler.h
index 1fb4b001b6e..748ea3ec5be 100644
--- a/js/src/jit/BaselineCacheIRCompiler.h
+++ b/js/src/jit/BaselineCacheIRCompiler.h
@@ -83,8 +83,8 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler {
   void loadStackObject(ArgumentKind kind, CallFlags flags, Register argcReg,
                        Register dest);
   void pushArguments(Register argcReg, Register calleeReg, Register scratch,
-                     Register scratch2, CallFlags flags, uint32_t argcFixed,
-                     bool isJitCall);
+                     Register scratch2, Register scratch3, CallFlags flags,
+                     uint32_t argcFixed, bool isJitCall);
   void prepareForArguments(Register argcReg, Register calleeReg,
                            Register scratch, Register scratch2, CallFlags flags,
                            uint32_t argcFixed);
Loading diff…