[25] [JSC] Don't advance bytecode when reifying inline frames at a checkpoint
Medium severity로 분류됩니다. diff는 잘못된 exception-handler dispatch metadata를 수정합니다. OSR exit 중 reified baseline frame에 기록되는
CallSiteIndex가 checkpoint 이후의 bytecode 위치를 가리키고 있어, re-executed checkpoint instruction에서 throw가 발생하면 잘못된HandlerInfotry-range로 매핑됩니다.
reifyInlinedCallFrames는 bytecodeIndexForExit(...)를 사용했습니다. 이 함수는 checkpoint가 포함된 index를 checkpoint 이후의 bytecode 위치로 정규화합니다. 재개(resumption) 목적으로는 올바른 동작이지만, unwinding 시에는 잘못된 위치를 참조하게 됩니다.
Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp
Checkpoint에서 inline frame을 reify할 때, resumption에 사용되는 bytecode index와 exception-handler 조회에 사용되는 bytecode index 간의 off-by-one.
Checkpoint는 baseline frame layout과 HandlerInfo 조회에 고정된 "스택 프레임당 하나의 bytecode index"라는 기존 관례 위에 sub-bytecode resumption을 덧씌우는 구조입니다. 재개 index는 OSR sidestate에 별도 보관되는 반면, unwinder는 프레임에 기록된 CallSiteIndex를 사용합니다. 두 index가 동일한 "baseline 정규화" 헬퍼에서 기록되는 모든 지점은 구조적 위험을 내포합니다.
도달 경로를 살펴보면, 세 가지 조건이 충족되어야 합니다. 먼저 DFG로 컴파일된 인라인 함수 내에 op_instanceof(또는 op_iterator_open/next, op_get_by_val_with_this)가 포함되어야 합니다. 또한 prototype/structure 무효화로 인해 re-execution 중 throw가 발생해야 하며, 호출 지점에 try/catch가 있어야 합니다. 이 세 조건이 충족되면 exception이 잘못된 catch 블록으로 전달됩니다.
이 vulnerability는 renderer 내부의 JS exception-handling 경계를 약화시킵니다. Baseline과 DFG semantics 사이의 JS state 불일치로 인해, 원래 control flow에서는 절대 생성되지 않았을 값이 노출될 가능성이 있습니다.
Audit directions
CodeBlock::bytecodeIndexForExitcallsites. 각 호출 지점을 세 가지 용도로 분류해야 합니다. 재개 용도(올바름), handler/range 조회 용도(checkpoint에서 잘못될 가능성), profiling/IC key 용도(잘못될 가능성)로 구분합니다.- Checkpoint-bearing bytecodes added without auditing every
BytecodeIndexrebuild site..checkpoint()와bytecodeIndexForExit를 함께 검색하고, OSR exit, OSR, inline-frame reification,genericUnwind각각에서 일관성을 검토해야 합니다. - Test coverage for
(DFG/FTL-inlined function) × (checkpoint bytecode that throws on re-execution) × (catch immediately following).(DFG/FTL 인라인 함수) × (re-execution 중 throw하는 checkpoint bytecode) × (직후의 catch)조합에 대한 테스트 커버리지가 필요합니다. 새로운 테스트 템플릿을 iterator-protocol checkpoint에 맞게 적용해야 합니다.