← All issues

[11] Navigate-on-pageswap re-entrancy crash

Severity: Medium | Component: WebCore loader / Navigation API | e7745af

관찰 가능한 영향은 pageswap 핸들러 re-entrancy를 통해 commit 도중 m_provisionalDocumentLoader를 초기화하는, 매번 재현 가능한 WebContent crash입니다. memory-safety primitive로의 확장 가능성은 pdl Ref capture 등 diff에서 드러나지 않는 loader ownership 세부사항에 달려 있습니다. 이러한 이유로 Medium으로 평가되었습니다.

Source/WebCore/loader/FrameLoader.cpp

+SetForScope dispatchingPageSwapEvent(m_isDispatchingPageSwapEvent, true);
document->dispatchPageswapEvent(canTriggerCrossDocumentViewTransition, WTF::move(activation));

Source/WebCore/page/Navigation.cpp

-if (!protect(window->document())->isFullyActive() || window->document()->unloadCounter())
+if (!protect(window->document())->isFullyActive() || frame()->loader().isDispatchingPageSwapEvent() || window->document()->unloadCounter())
return createErrorResult(WTF::move(committed), WTF::move(finished), ExceptionCode::InvalidStateError, "Invalid state"_s);

FrameLoader::commitProvisionalLoaddocument->dispatchPageswapEvent() 호출을 SetForScope로 감싸, dispatch가 진행되는 동안 m_isDispatchingPageSwapEvent = true로 설정합니다. 새로 추가된 bool m_isDispatchingPageSwapEvent { false } 멤버는 public getter isDispatchingPageSwapEvent()를 통해 노출됩니다. Navigation::navigate()는 해당 플래그가 true인 경우 InvalidStateError로 거부하도록 수정되었습니다. regression test는 onpageswap = async (e) => { await navigation.navigate('foo'); }를 설치하여 crash를 재현합니다.

commit 도중 dispatch되는 동기 JS 이벤트 중 re-navigation을 유발하는 API를 차단하지 않아, 이벤트 핸들러가 commit이 의존하는 loader를 무효화할 수 있는 패턴.

FrameLoader::commitProvisionalLoadm_provisionalDocumentLoader를 active loader로 승격시킨 뒤, script가 cross-document transition을 관찰할 수 있도록 pageswap을 동기적으로 dispatch합니다. 이후 transitionToCommittedHistoryController::updateForStandardLoad를 차례로 호출합니다. navigation.navigate(url)은 in-flight provisional load를 중단하거나 교체할 수 있는 policy check를 포함한 동기 초기 단계를 실행합니다. SetForScope<T>는 scope가 유지되는 동안 변수를 설정하고, scope 종료 시 원래 값으로 복원합니다.

pageswap은 commit pipeline 내부에서 동기적으로 dispatch됩니다. 패치 이전에는 navigation.navigate('foo')를 호출하는 script 핸들러가 m_provisionalDocumentLoader를 초기화할 수 있는 동기 policy/setup 단계를 실행했습니다. 이벤트가 반환된 뒤 commitProvisionalLoadtransitionToCommittedupdateForStandardLoadDocumentLoader::urlForHistory 순서로 실행을 계속했는데, 이 시점에서 loader는 이미 stale 상태이거나 null이었습니다.

🔒

Investigates the re-entrancy window opened by a synchronous DOM event fired mid-commit, and the lifetime implications for the provisional loader on either side of the dispatch.

더 확인하려면 구독해 주세요

🔒

Multiple reusable audit patterns covering synchronous-event re-entrancy across the loader pipeline, with concrete entrypoint lists for variant discovery.

더 확인하려면 구독해 주세요