Medium CVSS 4.3 webkit UAF 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected process crash
ComponentJSC
Sub-componentJSC Bytecode
Bug ClassUAF
Tracker301726
Fix commit1025bd18c9c7 (WebKit/WebKit) +1/-1
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L
CISA KEVNot listed
CreditedNan Wang (@eternalsakura13)
Disclosed2025-12-12

Background

CodeBlock jettison
JSC’s action of discarding optimized bytecode/JIT code when it is invalidated or reoptimized, tearing down associated metadata.
StructureStubInfo
Per-inline-cache metadata for property access; reset() returns it to an uncached state, deref() releases a reference to it.
ConcurrentJSLocker
The lock guarding concurrent access to CodeBlock state between the mutator and compiler threads.

Root Cause Analysis

This fixes a use-after-free during CodeBlock jettison in JavaScriptCore’s inline-cache teardown. CodeBlock::jettison() throws away optimized/older code; under the ConcurrentJSLocker it iterated every StructureStubInfo (the per-inline-cache metadata for get/put/in operations) and called stubInfo.reset(locker, this). reset() re-initializes the stub back to its uncached state, which touches structures, watchpoints and the owning CodeBlock (passed as this) — objects that during jettison may already be undergoing teardown, so re-initializing the stub there dereferences state that is being destroyed. The one-line fix replaces stubInfo.reset(locker, this) with stubInfo.deref(), so jettison simply releases the stub’s reference (it is reference-counted) rather than resetting and re-touching now-fragile CodeBlock/structure state.

The restored invariant is that jettison only drops ownership of its inline-cache stubs and does not walk into their reset path during code-block teardown. Because the diff is a single call-site change, the exact object whose lifetime was violated is inferred from the reset(locker, this) signature (it re-enters CodeBlock/structure state); the patch clearly establishes that resetting stubs at jettison time was unsafe and dereferencing/releasing is the correct action.

Key insight
Jettison was resetting each inline-cache stub — re-entering CodeBlock/structure state that is already being destroyed — when it should simply release the stub’s reference; reset-at-teardown was the use-after-free.

Attack Path

  1. Trigger tiered compilation Run JS that builds inline caches (StructureStubInfos) in an optimized CodeBlock.
  2. Force a jettison Cause reoptimization/invalidation so CodeBlock::jettison() runs and iterates the stub infos.
  3. Re-enter fragile state reset(locker, this) re-initializes each stub, touching CodeBlock/structure state already being torn down — a use-after-free.
  4. Crash or corrupt The dangling access crashes or corrupts JSC heap state in the WebContent process.

Impact Assessment

A use-after-free confined to the WebContent process, reachable by driving inline-cache creation and forcing jettison. Teardown-time UAFs in JSC metadata are exploitable with grooming, though this particular site (releasing vs resetting a stub during jettison) is a narrower primitive than a direct object-reuse bug; the advisory rates it a process crash.

Changed Functions

FunctionChangeNotes
forEachStructureStubInfo
Source/JavaScriptCore/bytecode/CodeBlock.cpp
modified

Files Changed

  • Source/JavaScriptCore/bytecode/CodeBlock.cpp

Audit Directions

  • Other jettison/teardown loops
    Grep CodeBlock.cpp and JIT teardown for reset(locker, this) or similar re-initialization calls during destruction/jettison where a deref/clear is the safe action.
  • StructureStubInfo lifetime
    Review all StructureStubInfo::reset callers to ensure the owning CodeBlock and referenced structures are fully live at reset time.
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index fd1dd5c7e09b..919f203ef225 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -2285,7 +2285,7 @@ void CodeBlock::jettison(Profiler::JettisonReason reason, ReoptimizationMode mod
     {
         ConcurrentJSLocker locker(m_lock);
         forEachStructureStubInfo([&](StructureStubInfo& stubInfo) {
-            stubInfo.reset(locker, this);
+            stubInfo.deref();
             return IterationStatus::Continue;
         });
     }
Loading diff…

Original Bug Report

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