CVE-2026-11050
Overview
Background
- Body descriptor
- a per-object-type class (
BodyDescriptor) whoseIterateBodytells V8’s GC exactly which slots of a heap object hold tagged pointers to visit. - `WasmMemoryMapDescriptor`
- a
JSObjectsubclass used by the WebAssembly memory-mapping feature; being aJSObjectit can carry in-object properties in addition to its own named fields. - `IteratePointers` / `IterateMaybeWeakPointer` / `IterateJSObjectBodyImpl`
- GC helpers that visit, respectively, a strong-pointer range, a single maybe-weak slot, and the generic
JSObjectin-object property region. - `kMemoryOffset` / `kHeaderSize` / `JSObject::BodyDescriptor::kStartOffset`
- layout constants marking the maybe-weak memory slot, the end of the fixed header, and the first tagged field of a
JSObject.
Root Cause Analysis
The pre-patch WasmMemoryMapDescriptor::BodyDescriptor::IterateBody (in objects-body-descriptors-inl.h) visited only the single maybe-weak slot at kMemoryOffset via IterateMaybeWeakPointer, ignoring every other tagged reference the object holds. Because WasmMemoryMapDescriptor is a JSObject subclass, it also has strong tagged fields between JSObject::BodyDescriptor::kStartOffset and kMemoryOffset and generic in-object properties from kHeaderSize to object_size, none of which were being iterated. This violates the GC invariant that a body descriptor must enumerate all outgoing tagged pointers: objects reachable only through those un-visited slots could be freed while the WasmMemoryMapDescriptor still referenced them, leaving dangling pointers — a use-after-free.
The fix (authored by CodeMender) makes the descriptor final, templatizes IterateBody on ObjectVisitor, and adds IteratePointers(obj, JSObject::BodyDescriptor::kStartOffset, kMemoryOffset, v) before the maybe-weak slot and IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v) after it, so the strong header fields, the weak memory slot, and all in-object properties are now visited.
IterateBody that scanned only the maybe-weak kMemoryOffset slot and omitted the object’s JSObject strong fields and in-object properties; the fix adds IteratePointers for the leading range and IterateJSObjectBodyImpl for the JSObject body so the GC marks every referenced object.Attack Path
- Allocate a WasmMemoryMapDescriptor with extra references
Script/Wasm creates a
WasmMemoryMapDescriptorand causes it to hold tagged references in itsJSObjectfields/in-object properties (the slots outsidekMemoryOffset). - Trigger garbage collection
Normal allocation pressure invokes the GC, which calls the object’s
IterateBody. - Miss the live references
Pre-patch,
IterateBodyvisits onlykMemoryOffset, so objects reachable solely through the un-iterated slots are not marked and get reclaimed. - Dereference a freed slot
Subsequent use of the
WasmMemoryMapDescriptor’s now-dangling field reads/uses freed memory, producing the use-after-free (inferred: the reclaimed slot could be reallocated with attacker-controlled data to escalate).
Impact Assessment
WasmMemoryMapDescriptor, yielding a use-after-free in V8’s heap; the advisory classifies it as a UAF in V8. The precondition is the ability to allocate such a descriptor with additional tagged references and drive a GC cycle. Conversion of the dangling reference into a controlled read/write or code execution is not shown by the patch and is (inferred).Changed Functions
| Function | Change | Notes |
|---|---|---|
WasmMemoryMapDescriptorsrc/objects/objects-body-descriptors-inl.h |
modified |
Files Changed
src/objects/objects-body-descriptors-inl.h
Audit Directions
- JSObject subclasses with custom body descriptorsReview every
BodyDescriptor::IterateBodyfor aJSObject-derived type to confirm it covers both theJSObjectheader fields and the in-object property region, not only its own named slots. - Descriptors visiting a single slotFlag
IterateBodyimplementations that call onlyIterateMaybeWeakPointer/IteratePointeron one offset without a range visit up toobject_size. - Wasm/JSObject hybrid objectsAudit other Wasm-related
JSObjectsubclasses (descriptors, wrappers) for the same missingIterateJSObjectBodyImplcoverage.
Patch
From 533bed9f375d7663d99273ab3a9b4843bcde9928 Mon Sep 17 00:00:00 2001 From: Andreas Haas <[email protected]> Date: Wed, 15 Apr 2026 06:59:04 -0700 Subject: [PATCH] [wasm] Iterate all references of WasmMemoryMapDescriptor The WasmMemoryMapDescriptor is a subclass of JSObject, and therefore has to iterate all potential outgoing references of JSObject. The CL was made by CodeMender. Bug: 498818402 Change-Id: I20199d492e4f5ca15f7176d2b76fe5b13f7ae150 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7761131 Commit-Queue: Andreas Haas <[email protected]> Reviewed-by: Anton Bikineev <[email protected]> Cr-Commit-Position: refs/heads/main@{#106530} --- diff --git a/src/objects/objects-body-descriptors-inl.h b/src/objects/objects-body-descriptors-inl.h index 9d5d3bd..ba8a917 100644 --- a/src/objects/objects-body-descriptors-inl.h +++ b/src/objects/objects-body-descriptors-inl.h @@ -1077,11 +1077,15 @@ } }; -class WasmMemoryMapDescriptor::BodyDescriptor : public BodyDescriptorBase { +class WasmMemoryMapDescriptor::BodyDescriptor final : public BodyDescriptorBase { public: + template <typename ObjectVisitor> static inline void IterateBody(Tagged<Map> map, Tagged<HeapObject> obj, int object_size, ObjectVisitor* v) { + IteratePointers(obj, JSObject::BodyDescriptor::kStartOffset, kMemoryOffset, + v); IterateMaybeWeakPointer(obj, kMemoryOffset, v); + IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v); } static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) {
Original Bug Report
Crash in v8::internal::Heap::Contains
Detailed Report: https://clusterfuzz.com/testcase?key=6602752981499904
Fuzzer: big_sleep Job Type: linux_asan_d8_dbg Platform Id: linux
Crash Type: UNKNOWN READ Crash Address: 0x77cd01040000 Crash State: v8::internal::Heap::Contains v8::internal::HeapObject::VerifyHeapPointer v8::internal::TorqueGeneratedClassVerifiers::JSReceiverVerify
Sanitizer: address (ASAN)
Recommended Security Severity: Medium
Regressed: https://clusterfuzz.com/revisions?job=linux_asan_d8_dbg&range=103388:103389
Reproducer Testcase: https://clusterfuzz.com/download?testcase_id=6602752981499904
Issue filed automatically.
To reproduce this, please build the target in this report and run it against the reproducer testcase. Please use the GN arguments provided at bottom of this report when building the binary.
If you have trouble reproducing, please also export the environment variables listed under “[Environment]” in the crash stacktrace.
If you have any feedback on reproducing test cases, let us know at https://forms.gle/Yh3qCYFveHj6E5jz5 so we can improve.