[5] [JSC] Move DataView null vector check in IC outside of register save/restore
Severity: High | Component: JSC InlineCacheCompiler | 34669c8
IC handler가 매칭되는 push 없이 register를 pop하는 문제를 수정한 diff입니다. 이 경우 손상된 register file과 stack 상태로 polymorphic continuation에 진입하게 됩니다. 이후 JIT 코드는 공격자가 영향을 줄 수 있는 register 상태에서 실행됩니다. Severity를 High로 평가한 이유입니다.
emitIntrinsicGetter에서 push 이전의 null-vector check와 push 이후의 out-of-bounds check가 동일한 JumpList를 공유하고 있었습니다. 공유된 link site는 두 경우 모두에 대해 register를 pop하는 구조였습니다. 결과적으로 push 이전의 실패 경로에서 restoreReusedRegistersByPopping이 매칭되는 push 없이 실행되었습니다.
Source/JavaScriptCore/bytecode/InlineCacheCompiler.cpp
if (isResizableOrGrowableSharedTypedArrayIncludingDataView(accessCase.structure()->classInfoForCells())) {
+ m_failAndIgnore.append(failAndIgnore);
auto allocator = makeDefaultScratchAllocator(m_scratchGPR);
...
+ CCallHelpers::JumpList postPushFailAndIgnore;
if (isDataView) {
auto [outOfBounds, doneCases] = jit.loadDataViewByteLength(...);
- failAndIgnore.append(outOfBounds);
+ postPushFailAndIgnore.append(outOfBounds);
doneCases.link(&jit);
}
- if (allocator.didReuseRegisters() && !failAndIgnore.empty()) {
- failAndIgnore.link(&jit);
+ if (allocator.didReuseRegisters() && !postPushFailAndIgnore.empty()) {
+ postPushFailAndIgnore.link(&jit);
allocator.restoreReusedRegistersByPopping(jit, preservedState);
m_failAndIgnore.append(jit.jump());
} else
- m_failAndIgnore.append(failAndIgnore);
+ m_failAndIgnore.append(postPushFailAndIgnore);
Patch Details
push 이전 단계의 failAndIgnore jump는 pop 없이 m_failAndIgnore에 직접 추가됩니다. 새로 도입된 postPushFailAndIgnore 목록은 push 이후의 실패를 수집하며, restoreReusedRegistersByPopping을 올바르게 경유하는 경로로 처리됩니다.
JIT IC 실패 경로에서 register save/restore 불균형 발생: push 이전의 실패 jump가 post-push pop 경로를 통해 처리되어 stack이 비정상 상태가 되는 패턴.
Background
JSC는 byteLength의 get_by_id와 같은 property 접근 연산을 작은 machine code stub으로 캐싱합니다. check 실패 시에는 m_failAndIgnore로 fall through합니다. IntrinsicGetterAccessCase는 DataView.prototype.byteLength와 같은 built-in getter를 특화 처리합니다. ScratchRegisterAllocator::preserveReusedRegistersByPushing / restoreReusedRegistersByPopping은 stub에 필요한 scratch register가 여유 register를 초과할 때, 재사용 register를 native stack에 push합니다. 이 두 함수 사이의 모든 exit 경로는 push와 pop을 모두 수행하거나, 둘 다 수행하지 않아야 합니다. loadDataViewByteLength는 underlying buffer의 length를 읽는 inline code를 생성하고, detach되거나 범위를 초과한 view에 대해 outOfBounds jump를 생성합니다.
Analysis
push 이전의 null-vector check가 생성하는 jump는 매칭되는 push 없이 재사용 register를 pop하는 코드에 연결되어 있었습니다. 이로 인해 SP가 push 크기만큼 어긋나고, 재사용된 callee/scratch register가 잘못된 값을 담게 됩니다.
Aa Aaa Aaa Aaaa Aaa Aaaaaaaaa Aaa Aa Aa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaa a Aaaaaaaaa Aaaaaaa Aaaaaa Aaaaa a Aaaaaaaaa Aaa Aaa Aaaaaa Aaaaa Aaaaaaaaaa Aaaa Aaaaaaa Aaa Aaaaaaaaaa Aaaaa Aaa Aa Aaaaa Aaaaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaa Aaaaa Aaaa Aa Aaaa Aaa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaa Aaa Aaaaaa Aa Aaa Aaaa Aaa Aa Aaa Aaaaaa
a Aaaa Aa Aa Aaaaaaaa Aaa Aaaaaaaa Aaaaaaa Aaaaaa Aaa a Aaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaa Aaa Aa Aaaaaaaaaa Aaaaaaa Aa Aaaaaaaaaa Aaaa Aaaa Aaa Aaaa Aa Aaa Aaa Aa Aa Aaa Aaaaaaaaaa Aaaaaaaaaa Aaa Aaaa Aaa Aaaa Aaaaaa
🔒The escalation potential of a JIT stack desynchronization bug, and the conditions under which a misbalanced pop becomes more than a crash.
더 확인하려면 구독해 주세요
Audit directions
a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aa Aaa Aa Aaaaa Aa Aaaaaaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaa Aaaa Aaaa Aa Aaa Aaa Aaaaaaaaaaa Aaaa Aaaa Aaa Aaa Aaaa Aa Aaaaaa
a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaa Aaaaaaaaaaa Aa Aaaa Aaa Aa Aaaaa Aaaa Aaaaa Aaa Aaaa Aaaaaa Aaaa Aaaa
a Aaaaaaaaaaaaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaa a Aaaa Aaaa Aa Aaaa Aaaaaaaaaaa Aaa Aaaaa Aaaa Aaaa
a Aaaaaaaaaaaaaaa Aaa Aaaaaa Aa Aaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaa Aa Aaaaaa Aaa Aaaa Aa Aaaaaa Aaaaaaaaaaaaa Aaa Aaa Aa Aaa Aaaa Aa Aaaaaa
🔒Multiple reusable audit patterns identified for JIT register-save discipline, with specific JSC compilation paths as starting points.
더 확인하려면 구독해 주세요