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
Tracker568010382
Fix commite321b042d411 (v8/v8) +46/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-13

Files Changed

  • src/maglev/maglev-code-generator.h
  • src/maglev/maglev-code-generator.cc
  • src/maglev/maglev-code-gen-state.h
  • src/maglev/maglev-ir.cc
From e321b042d4115179bb01270df2e75fc35ed65548 Mon Sep 17 00:00:00 2001
From: Marja Hölttä <marja@chromium.org>
Date: Thu, 01 Oct 2026 16:01:51 +0200
Subject: [PATCH] [maglev] Retain ArrayBuffers of constant TypedArrays

Constant TypedArrays are already held strongly by whatever
object they're constant in (PropertyCell, constant field),
and if they're no longer constants, the code should be deopted.

As an additional defense, "retain" the buffers in Maglev code.

This adds a "Retain" mechanism to Maglev; previously it was
only possible in Turbofan / Turboshaft. (It doesn't really retain,
but it inserts the target object as a weak embedded object,
so if the object dies, the code is deoptimized.)

Fixed: 568010382
Change-Id: I371c8b3e12973213410348f40244f7201235596a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8494795
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#110249}
---
diff --git a/src/maglev/maglev-code-gen-state.h b/src/maglev/maglev-code-gen-state.h
index fe88347..2d1b062 100644
--- a/src/maglev/maglev-code-gen-state.h
+++ b/src/maglev/maglev-code-gen-state.h
@@ -5,6 +5,8 @@
 #ifndef V8_MAGLEV_MAGLEV_CODE_GEN_STATE_H_
 #define V8_MAGLEV_MAGLEV_CODE_GEN_STATE_H_
 
+#include <unordered_set>
+
 #include "src/codegen/assembler.h"
 #include "src/codegen/label.h"
 #include "src/codegen/machine-type.h"
@@ -132,6 +134,15 @@
 
   inline BasicBlock* RealJumpTarget(BasicBlock* block);
 
+  using RetainedObjects =
+      std::unordered_set<Handle<HeapObject>, Handle<HeapObject>::hash,
+                         Handle<HeapObject>::equal_to>;
+  void Retain(Handle<HeapObject> heap_object) {
+    retained_objects_.insert(heap_object);
+  }
+
+  const RetainedObjects& retained_objects() const { return retained_objects_; }
+
  private:
   MaglevCompilationInfo* const compilation_info_;
   MaglevSafepointTableBuilder* const safepoint_table_builder_;
@@ -143,6 +154,8 @@
   std::vector<LazyDeoptInfo*> lazy_deopts_;
   std::vector<NodeBase*> handlers_;
 
+  RetainedObjects retained_objects_;
+
   int untagged_slots_ = 0;
   int tagged_slots_ = 0;
   uint32_t max_deopted_stack_size_ = kMaxUInt32;
diff --git a/src/maglev/maglev-code-generator.cc b/src/maglev/maglev-code-generator.cc
index 0db7647..d5a7ac6 100644
--- a/src/maglev/maglev-code-generator.cc
+++ b/src/maglev/maglev-code-generator.cc
@@ -1892,6 +1892,7 @@
   EmitDeferredCode();
   if (!EmitDeopts()) return false;
   EmitExceptionHandlerTrampolines();
+  EmitRetainedObjects();
   __ FinishCode();
 
   code_gen_succeeded_ = true;
@@ -2041,6 +2042,21 @@
 #endif
 }
 
+void MaglevCodeGenerator::EmitRetainedObjects() {
+  if (code_gen_state_.retained_objects().empty()) return;
+
+  // This code is never executed; it's just for inserting weak embedded objects
+  // into the code.
+  __ RecordComment("-- Retained objects");
+  __ Trap();
+
+  MaglevAssembler::TemporaryRegisterScope temps(masm());
+  Register scratch = temps.AcquireScratch();
+  for (Handle<HeapObject> heap_object : code_gen_state_.retained_objects()) {
+    __ Move(scratch, heap_object);
+  }
+}
+
 void MaglevCodeGenerator::EmitMetadata() {
   // Final alignment before starting on the metadata section.
   masm()->Align(InstructionStream::kMetadataAlignment);
diff --git a/src/maglev/maglev-code-generator.h b/src/maglev/maglev-code-generator.h
index e7c2967..b38547c 100644
--- a/src/maglev/maglev-code-generator.h
+++ b/src/maglev/maglev-code-generator.h
@@ -41,6 +41,7 @@
   void EmitDeferredCode();
   V8_NODISCARD bool EmitDeopts();
   void EmitExceptionHandlerTrampolines();
+  void EmitRetainedObjects();
   void EmitMetadata();
   void RecordInlinedFunctions();
 
diff --git a/src/maglev/maglev-ir.cc b/src/maglev/maglev-ir.cc
index bb82fb8..9f225fc 100644
--- a/src/maglev/maglev-ir.cc
+++ b/src/maglev/maglev-ir.cc
@@ -8271,6 +8271,18 @@
   }
 }
 
+void RetainConstantTypedArrayBuffer(MaglevAssembler* masm,
+                                    compiler::JSTypedArrayRef typed_array) {
+  // The constant typed array comes from a constant-folded source (property
+  // cell, const field, ...) which holds it strongly, and the code depends on
+  // that source not changing. So the buffer behind the embedded data pointer
+  // cannot die while this code is valid. Embed the buffer anyway as defense in
+  // depth: with this weak reference, the code is deoptimized when the buffer
+  // dies.
+  masm->code_gen_state()->Retain(
+      typed_array.buffer(masm->compilation_info()->broker()).object());
+}
+
 template <typename ResultReg>
 void GenerateTypedArrayLoad(MaglevAssembler* masm, Register object,
                             Register index, ResultReg result_reg,
@@ -8298,6 +8310,8 @@
                                     compiler::JSTypedArrayRef typed_array,
                                     Register index, ResultReg result_reg,
                                     ElementsKind kind) {
+  RetainConstantTypedArrayBuffer(masm, typed_array);
+
   MaglevAssembler::TemporaryRegisterScope temps(masm);
   Register data_pointer = temps.Acquire();
   __ Move(data_pointer, reinterpret_cast<intptr_t>(typed_array.data_ptr()));
@@ -8359,6 +8373,8 @@
                                      compiler::JSTypedArrayRef typed_array,
                                      Register index, ValueReg value,
                                      ElementsKind elements_kind) {
+  RetainConstantTypedArrayBuffer(masm, typed_array);
+
   MaglevAssembler::TemporaryRegisterScope temps(masm);
   Register data_pointer = temps.Acquire();
 
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.