Medium CVSS 9.8 webkit Logic Error 🔧 Commit mapped

Overview

Medium
Severity
9.8
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected Safari crash
ComponentJSC JIT
Bug ClassLogic Error
Tracker285892
Fix commit71951f425f93 (WebKit/WebKit)
CWECWE-400
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGary Kwong, and an anonymous researcher
Disclosed2025-03-31

Background

JIT operation call-frame tracer
JITOperationPrologueCallFrameTracer sets the VM’s current top call frame for the duration of a runtime operation invoked from JIT code.
Direct eval operations
JIT helpers that execute a direct eval(); the callee frame is untrusted, so VM is taken from the caller frame.
Top call frame
The VM’s record of the currently executing frame, consulted during stack walks and GC; a stale value causes crashes.

Root Cause Analysis

This fixes a crash / potential corruption in JavaScriptCore’s JIT direct-eval operations that failed to update the VM’s top call frame. operationCallDirectEvalSloppy/Strict (and the …TaintedByWithScope variants) run when a direct eval() is invoked from JIT code. They derive the VM from the caller frame because the callee frame may be garbage at entry. Pre-patch they computed VM& vm = calleeFrame->callerFrame()->deprecatedVM() but did NOT install a JITOperationPrologueCallFrameTracer, so the VM’s current top call frame was left pointing at the untrusted callee/garbage frame during the operation. If the operation subsequently allocates or throws — for example eval of an enormous string that triggers an out-of-memory or exception, as the regression test does — the engine walks the stack or runs GC using that stale/garbage top frame, causing a crash (and potentially memory corruption).

The fix captures CallFrame* callFrame = calleeFrame->callerFrame() and constructs JITOperationPrologueCallFrameTracer tracer(vm, callFrame), setting the VM’s top call frame to the trusted caller for the duration of the operation.

The restored invariant is that JIT runtime operations that can allocate or throw set the correct top call frame via the tracer. The test evals huge strings in a loop to force the allocation/throw path.

Key insight
The JIT direct-eval operations read VM from the caller frame but never set the VM’s top call frame via the tracer, so an allocation/throw during eval walked a garbage frame; installing JITOperationPrologueCallFrameTracer fixes the top-frame invariant.

Attack Path

  1. Call eval from JIT code Run hot JS that reaches operationCallDirectEval* for a direct eval().
  2. Force allocation/throw eval an enormous string so the operation triggers OOM/exception handling.
  3. Walk a stale top frame Because no call-frame tracer was installed, stack walking / GC uses the garbage callee frame as the top frame.
  4. Crash or corrupt The stale-frame walk crashes (or corrupts state) in the WebContent process.

Impact Assessment

A crash and potential memory corruption in the WebContent process, reachable by calling eval() from JIT-compiled code and forcing an allocation/throw. The advisory rates it a crash; the missing top-frame update is the kind of engine-state inconsistency that can be developed into stronger primitives.

Changed Functions

FunctionChangeNotes
operationCallDirectEvalSloppy / Strict / SloppyTaintedByWithScope / StrictTaintedByWithScope
Source/JavaScriptCore/jit/JITOperations.cpp
modified Capture the caller frame and install JITOperationPrologueCallFrameTracer(vm, callFrame) so the VM's top call frame is correct when the eval operation allocates or throws.

Audit Directions

  • Same file: tracer coverage
    Grep JITOperations.cpp for JSC_DEFINE_JIT_OPERATION handlers that can allocate/throw but omit a JITOperationPrologue*CallFrameTracer.
  • Caller-frame VM derivation
    Audit operations that take VM from callerFrame()->deprecatedVM() to confirm they also set the top call frame.

Original Bug Report

The reporter's bug is still restricted on the tracker.