High chrome UAF 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in V8
DescriptionUse after free in V8
ComponentV8
Sub-componentMaglev
Bug ClassUAF
Tracker569286602
Fix commit6c626cef3652 (v8/v8) +58/-5
CISA KEVNot listed
CreditedXinyang Ge
Disclosed2026-10-15

Files Changed

  • test/mjsunit/maglev/regress-569286602-1.js
  • test/mjsunit/maglev/regress-569286602-2.js
  • src/maglev/maglev-graph-builder.cc
From 6c626cef36527614a5f9001a2946ed4277118a77 Mon Sep 17 00:00:00 2001
From: Marja Hölttä <[email protected]>
Date: Tue, 06 Oct 2026 13:19:14 +0200
Subject: [PATCH] [maglev] Fix predecessor counting in the "smi case falls back to object case" logic

If the smi case "succeeds" but it just falls back to the object case
which fails, that should not count as a success.

Drive-by: Hardening; upgrading a DCHECK (which hits with one of the
variants) to CHECK. Another variant was already hitting a CHECK.

Fixed: 569286602
Change-Id: Iae131e470629efd6a1c4c062512843944b6df138
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8518260
Reviewed-by: Darius Mercadier <[email protected]>
Commit-Queue: Marja Hölttä <[email protected]>
Cr-Commit-Position: refs/heads/main@{#110393}
---
diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
index 47a95f1..82aba1e 100644
--- a/src/maglev/maglev-graph-builder.cc
+++ b/src/maglev/maglev-graph-builder.cc
@@ -9167,16 +9167,21 @@
         sub_graph.GotoOrTrim(&*object_case);
         sub_graph.Bind(&*object_case);
       }
-      any_successful |= (!build_kind_specific(kind).IsDoneWithAbort());
+      ReduceResult result = build_kind_specific(kind);
       if (IsSmiElementsKind(kind) && make_smi_fallthrough_to_object) {
         // After building the SMI specific parts (see build_kind_specific call
         // above), jump to the beginning of the case for the object elements
         // kind.
         DCHECK(object_case.has_value());
         sub_graph.GotoOrTrim(&*object_case);
+
+        // Whether the Smi case is successful depends on whether the object case
+        // is successful, so don't update any_successful here.
       } else {
         DCHECK(do_return.has_value());
         sub_graph.GotoOrTrim(&*do_return);
+
+        any_successful |= !result.IsDoneWithAbort();
       }
       sub_graph.Bind(&check_next_map);
     } else {
@@ -17039,11 +17044,11 @@
   ResetBuilderCachedState();
 
   if (merge_state.is_loop()) {
-    DCHECK_EQ(merge_state.predecessors_so_far(),
-              merge_state.predecessor_count() - 1);
+    CHECK_EQ(merge_state.predecessors_so_far(),
+             merge_state.predecessor_count() - 1);
   } else {
-    DCHECK_EQ(merge_state.predecessors_so_far(),
-              merge_state.predecessor_count());
+    CHECK_EQ(merge_state.predecessors_so_far(),
+             merge_state.predecessor_count());
   }
 
   if (merge_state.predecessor_count() == 1) {
diff --git a/test/mjsunit/maglev/regress-569286602-1.js b/test/mjsunit/maglev/regress-569286602-1.js
new file mode 100644
index 0000000..b89ebdc
--- /dev/null
+++ b/test/mjsunit/maglev/regress-569286602-1.js
@@ -0,0 +1,24 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --maglev
+
+function f(r) {
+  let pos;
+  while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); }
+  r.push(pos);
+}
+
+%PrepareFunctionForOptimization(f);
+let a = [{}];
+assertEquals(undefined, f(a));
+assertEquals([{}, undefined], a);
+let b = [1];
+assertEquals(undefined, f(b));
+assertEquals([1, undefined], b);
+
+%OptimizeMaglevOnNextCall(f);
+let c = [1];
+assertEquals(undefined, f(c));
+assertEquals([1, undefined], c);
diff --git a/test/mjsunit/maglev/regress-569286602-2.js b/test/mjsunit/maglev/regress-569286602-2.js
new file mode 100644
index 0000000..dc186b8
--- /dev/null
+++ b/test/mjsunit/maglev/regress-569286602-2.js
@@ -0,0 +1,24 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --maglev
+
+function f(r) {
+  let pos;
+  while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); }
+  if (r) r.push(pos);
+}
+
+%PrepareFunctionForOptimization(f);
+let a = [{}];
+assertEquals(undefined, f(a));
+assertEquals([{}, undefined], a);
+let b = [1];
+assertEquals(undefined, f(b));
+assertEquals([1, undefined], b);
+
+%OptimizeMaglevOnNextCall(f);
+let c = [1];
+assertEquals(undefined, f(c));
+assertEquals([1, undefined], c);
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/test/mjsunit/maglev/regress-569286602-1.js b/test/mjsunit/maglev/regress-569286602-1.js
new file mode 100644
index 0000000..b89ebdc
--- /dev/null
+++ b/test/mjsunit/maglev/regress-569286602-1.js
@@ -0,0 +1,24 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --maglev
+
+function f(r) {
+  let pos;
+  while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); }
+  r.push(pos);
+}
+
+%PrepareFunctionForOptimization(f);
+let a = [{}];
+assertEquals(undefined, f(a));
+assertEquals([{}, undefined], a);
+let b = [1];
+assertEquals(undefined, f(b));
+assertEquals([1, undefined], b);
+
+%OptimizeMaglevOnNextCall(f);
+let c = [1];
+assertEquals(undefined, f(c));
+assertEquals([1, undefined], c);
diff --git a/test/mjsunit/maglev/regress-569286602-2.js b/test/mjsunit/maglev/regress-569286602-2.js
new file mode 100644
index 0000000..dc186b8
--- /dev/null
+++ b/test/mjsunit/maglev/regress-569286602-2.js
@@ -0,0 +1,24 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --maglev
+
+function f(r) {
+  let pos;
+  while ('a'.startsWith('b', pos)) { do { pos = 1; } while (pos); }
+  if (r) r.push(pos);
+}
+
+%PrepareFunctionForOptimization(f);
+let a = [{}];
+assertEquals(undefined, f(a));
+assertEquals([{}, undefined], a);
+let b = [1];
+assertEquals(undefined, f(b));
+assertEquals([1, undefined], b);
+
+%OptimizeMaglevOnNextCall(f);
+let c = [1];
+assertEquals(undefined, f(c));
+assertEquals([1, undefined], c);
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.