← All issues

[22] [JSC] Move FTL stack overflow check to prologue

Severity: Medium | Component: JSC FTL JIT | 1b42291

JIT prologue 상태 불변식을 수정하는 diff이기 때문에 Medium으로 평가되었습니다. Stack overflow의 late path가 callee-save를 pop한 이후, ThrowStackOverflowAtPrologue로 점프하기 전에 SP를 복원하지 않았습니다. 결과적으로 throw thunk는 부분적으로 구성된 frame을 가리키는 SP 상태에서 실행되었습니다.

Stack overflow patchpoint는 emitFunctionPrologue, frame allocation, callee-save spilling이 모두 완료된 이후 — 즉 lowered function body 안에서 실행되었습니다. 이 상태에서 "at prologue" stack shape을 기대하는 thunk로 점프하기 전에 상태를 되돌리려 했습니다.

Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

+ Ref<B3::Air::PrologueGenerator> mainPrologueGenerator = createSharedTask<B3::Air::PrologueGeneratorFunction>(
+ [=](CCallHelpers& jit, B3::Air::Code& code) {
+ jit.emitFunctionPrologue();
+ // Stack overflow check before frame allocation; SP == FP, no callee-saves saved.
+ ...
+ auto stackOverflow = jit.branchPtr(...);
+ stackOverflow.linkThunk(...ThrowStackOverflowAtPrologue...);
+ if (ftlFrameSize)
+ jit.subPtr(CCallHelpers::TrustedImm32(ftlFrameSize), CCallHelpers::stackPointerRegister);
+ jit.emitSave(code.calleeSaveRegisterAtOffsetList());
+ });
+ m_proc.code().setPrologueForEntrypoint(0, WTF::move(mainPrologueGenerator));

JIT exception edge에서의 stack pointer 상태 불일치: SP를 대칭적으로 되돌리지 않은 채 prologue를 지나친 지점에서 out-of-line thunk에 도달한 패턴.

원래 코드에는 이 commit이 닫는 bug 번호를 직접 가리키는 FIXME 주석이 남아 있었습니다. 작성자 스스로 stack check가 Air prologue에 위치해야 한다는 것과, late-path의 emitRestore가 임시방편에 불과했다는 사실을 인식하고 있었던 셈입니다.

이 코드에 도달하려면 FTL 함수 진입 시점에 실제 stack overflow를 강제로 유발해야 합니다. 이때 나타나는 오동작은 memory write primitive보다는 exception machinery 손상이나 crash 형태일 가능성이 높습니다. 다만 diff만으로는 throw thunk 내부에서 발생 가능한 결과의 범위를 완전히 특정하기 어렵습니다.

이 취약점은 exception throw 경로가 의존하는 내부 불변식을 약화시킵니다. 커스텀 Air PrologueGenerator로 check를 이동함으로써 대칭성 요건 자체가 제거되었습니다.