flawopen.com/Teardowns/cve-2024-23222-apple-ios-webkit-type-confusion
vulnerabilidade 소스 코드 심층 기술 분석 및 시스템 보안 강화 가이드: 취약점 근본 원인과 패치 메커니즘 분석.
직관적인 현실 비유 설명: Apple devices have special hardware called Pointer Authentication (PAC) that stamps memory addresses with cryptographic signatures so hackers can't forge them. But in Safari's JavaScript engine, a math helper took an untrusted object and stripped off its label without verifying what it was. This allowed attackers to trick the processor into signing a fake pointer, letting targeted spyware take over Safari.
JavaScriptCore (JSC)DFG (Data Flow Graph) JITPointer Authentication Code (PAC)Speculative Unboxing근본 원인은 오픈 소스 시스템의 검증되지 않은 경계 매개변수로 인해 상태 비동기화 및 보안 제어 우회가 발생한 데 있습니다.
The victim navigates to an attacker-controlled web page in Safari on iOS or macOS.
The script executes an object unboxing routine in a tight loop. JavaScriptCore's DFG compiler speculates that the input is always a native JS object.
The compiled bytecode strips the NaN-box metadata tag without emitting a type assertion guard.
The attacker supplies a disguised object structure, forging a signed pointer to execute shellcode and begin the secondary kernel privilege escalation chain.
// VULNERABLE: C++ Logic from WebKit/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
void DFGSpeculativeJIT::compileUnboxObject(Node* node) {
Edge edge = node->child1();
GPRReg jsValueGPR = edge.useInfo().gpr();
GPRReg resultGPR = node->gpr();
// CRITICAL ROOT CAUSE:
// Speculatively stripped the TagMask from JSValue without verifying
// that the value actually satisfied isCell() and was an Object pointer!
m_jit.move(jsValueGPR, resultGPR);
m_jit.and64(TrustedImm64(TagMask), resultGPR);
// Resulting pointer assumed authenticated without PAC validation!
}
// SECURE: Open-Source C++ Patch from WebKit Repository
void DFGSpeculativeJIT::compileUnboxObject(Node* node) {
Edge edge = node->child1();
GPRReg jsValueGPR = edge.useInfo().gpr();
GPRReg resultGPR = node->gpr();
// 1. Emit explicit type tag assertion guard
MacroAssembler::Jump notCell = m_jit.branchIfNotCell(jsValueGPR);
speculationCheck(BadType, JSValueRegs(jsValueGPR), edge.node(), notCell);
// 2. Verify object structure cell before unmasking pointer
m_jit.move(jsValueGPR, resultGPR);
m_jit.and64(TrustedImm64(TagMask), resultGPR);
// 3. Ensure PAC authentication check verifies target pointer integrity
speculationCheck(BadType, JSValueRegs(jsValueGPR), edge.node(),
m_jit.branchTest8(MacroAssembler::Zero,
MacroAssembler::Address(resultGPR, JSCell::typeInfoTypeOffset())));
}
branchIfNotCell) prior to speculative value unboxing in JIT compilers.