flawopen.com/Teardowns/cve-2024-4947-chrome-v8-type-confusion

● CVE-2024-4947 · CVSS 9.8 · Crítica
Pesquisa · FlawOpen

CVE-2024-4947: Chrome V8 JIT Compiler Type Confusion Teardown

Análise técnica detalhada e engenharia de mitigação do patch para 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.

💡 Explicação em Linguagem Simples (ELI5)

Analogia explicativa: 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.

Conceitos Centrais e Termos

Turbofan JIT
O compilador otimizador do motor V8 do Google que converte o bytecode JavaScript em código de máquina de alta velocidade específico da arquitetura.
Hidden Class / Map
Objeto de metadados interno do V8 que rastreia o layout, nomes de propriedades e tipos de elementos de objetos JavaScript na memória (Map/HiddenClass).
Type Confusion
Falha de corrupção de memória que ocorre quando o código trata uma região de memória inicializada como Tipo A como se fosse do Tipo B.
Map Deprecating Transition
Quando a modificação dinâmica de uma propriedade de objeto faz com que seu layout interno mude, exigindo que o código JIT compilado anteriormente seja desotimizado.

Análise de Causa Raiz

A causa raiz decorre de parâmetros de limite não validados em sistemas de código aberto, permitindo a dessincronização de estado e a evasão dos controles de segurança.

Fluxo de Ataque Passo a Paso

Step 1

1. JIT Warm-Up

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.

Step 2

2. Prototype Getter Interception

Inside a customized property getter, the attacker alters the array layout by storing an object reference, changing the map to PACKED_ELEMENTS.

Step 3

3. Unchecked Native Execution

Because Turbofan omitted a dynamic map transition check, the compiled native loop continues to read the array as raw 64-bit IEEE floats.

Step 4

4. Arbitrary Read/Write Primitive

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.

Código-Fonte: Vulnerável vs. Seguro

✕ IMPLEMENTAÇÃO VULNERÁVEL
// 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();
}
✓ PATCH SEGURO E ROBUSTO
// 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();
}

Lista de Verificação de Segurança para Engenharia