# CVE-2021-4102: Chrome incorrect node elision in Turbofan leads to unexpected WriteBarrier elision

Turbofan's SimplifiedOperatorReducer elided ChangeTaggedToInt32->ChangeInt31ToTaggedSigned, storing a HeapNumber into a TaggedSigned field without a WriteBarrier, causing a use-after-free in V8.

- Payout: Real-world hack
- Severity: high
- Program: Google Chrome
- Credited: Anonymous
- Disclosed: 2021-12-13
- CVE: CVE-2021-4102
- Write-up quality: 9/10
- Original: https://github.com/googleprojectzero/0days-in-the-wild/blob/main/0day-RCAs/2021/CVE-2021-4102.md
- Library page: https://bugbountylibrary.com/r/p0%3ACVE-2021-4102
- Tags: domain:browser impact:rce kind:incident platform:project-zero sev:high tech:chromium technique:chained technique:source-review vuln:dos vuln:memory-corruption

**Target:** V8 Turbofan JIT compiler (SimplifiedOperatorReducer / StoreField)
**Root cause:** EarlyOptimizationPhase's SimplifiedOperatorReducer elides ChangeTaggedToInt32 -> ChangeInt31ToTaggedSigned after SimplifiedLoweringPhase already decided to omit the WriteBarrier for a TaggedSigned field, allowing a TaggedPointer (HeapNumber) to be stored without a barrier.
**Steps:**
1. Create object `o` with mutable TaggedSigned field `o.a`, move to OldSpace via `new ArrayBuffer(2**34)`.
2. In optimized function, store `b = i + -0` to global (emits CheckHeapObject -> StoreField) and `o.a = Math.abs(b)` (emits CheckSmi -> StoreField).
3. LoadElimination passes CheckHeapObject into NumberAbs and global StoreField; SimplifiedLowering lowers to ChangeUint32ToFloat64 -> ChangeFloat64ToTaggedPointer -> ChangeTaggedToInt32 -> ChangeInt31ToTaggedSigned -> StoreField.
4. Add FrameState/StateValue/CheckPoint nodes taking ChangeTaggedToInt32 as input so DFS visits ChangeInt31ToTaggedSigned first, triggering elision.
5. Trigger Scavenger (`new ArrayBuffer(16777216)` churn) then mark_sweep, read `o.a` and dereference `ret[0]` for UAF.
**How found:** Manual analysis: noted SimplifiedLoweringPhase assumes TaggedSigned fields need no WriteBarrier, then audited later reduction passes (EarlyOptimizationPhase) for elisions that violate that assumption; crafted node ordering via FrameState/CheckPoint to force DFS to visit ChangeInt31ToTaggedSigned before ChangeTaggedToInt32.
**Exploitation:** Not observed; RCA assumes UAF used to leak sentinel values (TheHole/UninitializedOddball) or materialize a fake object, then build arbitrary read/write and shellcode execution.
**Insight:** When a compiler pass makes a safety decision (WriteBarrier elision) based on field representation, audit later optimization passes that can change the stored value's type; control GraphReducer DFS order via FrameState/CheckPoint inputs to force the vulnerable reduction order.
