Chrome · V8 › Maglev
CVE-2026-110168
UAF in V8 (Maglev)
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
src/maglev/maglev-code-generator.hsrc/maglev/maglev-code-generator.ccsrc/maglev/maglev-code-gen-state.hsrc/maglev/maglev-ir.cc
Patch
From e321b042d4115179bb01270df2e75fc35ed65548 Mon Sep 17 00:00:00 2001 From: Marja Hölttä <[email protected]> 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ä <[email protected]> Reviewed-by: Leszek Swirski <[email protected]> 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.
References
On This Page