← All issues

[AppKit Gestures] Reentrancy UAF in PositionInformationManager pending-handler loop

94c5f97

Source/WebKit/UIProcess/mac/PositionInformationManager.cpp

- for (auto& slot : m_pendingHandlers) {
+ // 이 부분은 의도적으로 range-based for-loop를 사용하지 않습니다. stale iterator pointer로 인한 reentrancy UAF가 발생할 수 있기 때문입니다.
+ for (size_t index = 0; index < m_pendingHandlers.size(); ++index) {
+ auto& slot = m_pendingHandlers[index];
if (!slot)
continue;
+
if (!matches(slot->request))
continue;

PositionInformationManager는 UIProcess에서 동작하며, AppKit gesture 처리로부터 position-information 업데이트를 기다리는 콜백들을 m_pendingHandlers라는 큐에 쌓아둡니다. 이 설계는 reentrancy를 명시적으로 허용합니다. invokeAndRemovePendingHandlers 실행 중 호출된 콜백이 다시 doAfterUpdate()를 호출할 수 있고, 이 과정에서 constructAndAppend()를 통해 새 핸들러를 큐에 추가하면 Vector의 backing store가 확장되며 재할당될 수 있습니다.

문제는 range-based for 루프가 루프 시작 시점에 begin()/end()를 한 번만 캡처한다는 점입니다. reentrant 콜백이 iteration 도중 버퍼를 재할당하고 나면, 캐시된 포인터들은 이미 해제된 메모리를 가리키게 됩니다. 이 상태에서 slot을 다시 참조하면 use-after-free로 이어집니다.

패치는 range-based 루프를 index 기반 루프로 교체합니다. 매 iteration마다 size()를 다시 읽고 m_pendingHandlers[index]로 재인덱싱하기 때문에, 재할당된 버퍼를 올바르게 참조하게 됩니다.

  Range-based (buggy):                  Index-based (fixed):
  for (auto& slot : m_pendingHandlers)  for (index = 0; index < size(); ++index)
    caches begin/end once                 slot = m_pendingHandlers[index]
    callback() reenters                   callback() reenters
      constructAndAppend() reallocates      may reallocate
    cached ptrs -> freed memory           next iter re-indexes live buffer
    slot-> ...  UAF                       (safe)

AppKit gesture 처리에서 도달 가능한 UIProcess 콜백 큐에서 발생하는 reentrancy 기반 UAF이며, 이 버그 패턴 자체가 다른 WebKit 콜백 큐에도 재사용되었을 가능성이 있는 템플릿에 해당합니다.

이번에 수정된 형태 — iteration 중인 Vector를 변경하는 reentrant synchronous 콜백 — 는 WebKit의 UIProcess pending-request/callback 큐 전반에서 반복적으로 나타나는 패턴입니다. 좁게 보면, PositionInformationManager와 유사한 *Manager 클래스들에서 m_pending* 벡터를 순회하는 range-based for 루프 중, 그 body가 reentrant 방식으로 append/constructAndAppend/insert를 호출할 수 있는 콜백을 실행하는 지점을 검색해볼 필요가 있습니다. 특히 gesture, touch, position-info IPC 응답을 처리하는 UIProcess 클래스가 우선 대상입니다. 좀 더 넓게 보면, client 코드나 JS에서 도달 가능한 코드로 진입하면서 동일한 컨테이너를 변경할 수 있는 Vector/HashMap에 대한 range-based iteration 전반을 점검할 필요가 있습니다. 이 경우 컨테이너가 반드시 콜백 큐일 필요는 없습니다. 가장 넓게 보면, 컨테이너와 콜백이 결합된 설계 전반에서 나타나는 iterator-invalidation-under-reentrancy 클래스 자체가 대상이 됩니다. 리뷰에서 눈여겨봐야 할 신호는, member container에 대한 range-based for 루프와 reentrancy를 허용한다는 뉘앙스의 주석이나 메서드 이름(doAfterUpdate, "may reenter" 등)이 한 함수 안에 함께 있는 경우입니다. 이 두 가지가 동시에 발견되면 index 기반 iteration으로 전환하거나 컨테이너를 먼저 스냅샷해야 한다는 신호로 볼 수 있습니다.