flawopen.com/Teardowns/cve-2024-4947-chrome-v8-type-confusion
Analyse technique détaillée du code source et mesures de durcissement pour vulnerabilidade : How property getter transitions in V8's Turbofan JIT compiler tricked optimized native code into reading raw pointers as floating-point numbers, yielding in-the-wild remote code execution.
Analogie concrète : V8 makes JavaScript super fast by making assumptions. If you pass an array of numbers to a function 1,000 times, V8 turns that function into machine code that skips all safety checks. An attacker creates a sneaky property that changes the array from 'numbers' to 'object pointers' right in the middle of execution. The machine code treats an object's memory address as a number, letting the attacker read and write raw computer memory.
Turbofan JITHidden Class / MapType ConfusionMap Deprecating TransitionLa cause fondamentale provient de paramètres de limites non validés dans les systèmes open source, permettant une désynchronisation d'état et le contournement des contrôles de sécurité.
The attacker runs a loop passing an array of floating-point numbers (PACKED_DOUBLE_ELEMENTS) to a function until Turbofan compiles it to unverified native assembly.
Inside a customized property getter, the attacker alters the array layout by storing an object reference, changing the map to PACKED_ELEMENTS.
Because Turbofan omitted a dynamic map transition check, the compiled native loop continues to read the array as raw 64-bit IEEE floats.
The float values represent raw pointers. The attacker constructs an addrof (read address) and fakeobj (corrupt address) primitive to break out of the V8 sandbox.
// VULNERABLE: Simplified C++ Turbofan Graph Optimization (v8/src/compiler/)
// The optimizer assumed Map state remained unchanged across property accesses!
Reduction JSNativeContextSpecialization::ReduceNamedAccess(Node* node) {
MapRef receiver_map = GetReceiverMap(node);
// VULNERABILITY:
// If property access invokes a custom JS getter that mutates the object's Map,
// Turbofan fails to emit an effect-dependent map verification node!
if (receiver_map.is_stable()) {
// Relies on static stability without guarding against dynamic in-getter mutation
return BuildPropertyLoad(node, receiver_map);
}
return NoChange();
}
// SECURE: Explicit Map Transition Guard Insertion in Turbofan Graph
Reduction JSNativeContextSpecialization::ReduceNamedAccess(Node* node) {
MapRef receiver_map = GetReceiverMap(node);
// FIX: Verify map stability AND emit runtime type transition guard
if (receiver_map.is_stable()) {
dependencies()->DependOnStableMap(receiver_map);
// Explicitly insert dynamic Map check node before unboxing properties
Node* effect = NodeProperties::GetEffectInput(node);
Node* check = graph()->NewNode(
simplified()->CheckMaps(CheckMapsFlag::kNone,
ZoneHandleSet<Map>(receiver_map.object())),
receiver, effect, control);
// If an in-flight getter changes the object layout, force JIT deoptimization!
NodeProperties::ReplaceEffectInput(node, check);
return BuildPropertyLoad(node, check, receiver_map);
}
return NoChange();
}
CheckMaps) in JIT compiler IR graphs before performing element unboxing.v8_enable_sandbox = true) to restrict in-process memory corruption to a 1TB virtual address cage.