Site Isolation UI process crash via unchecked mouse event queue access
Source/WebKit/UIProcess/WebPageProxy.cpp
WebKit의 multi-process 구조에서, web content process는 입력 이벤트 처리가 완료되면 DidReceiveEvent IPC 메시지를 UI process로 전송해 확인 응답을 전달합니다. Site Isolation 환경에서는 cross-origin subframe으로 라우팅된 이벤트에 remoteUserInputEventData 필드가 포함됩니다. 이 필드는 UI process가 해당 이벤트를 어느 frame에 전달해야 하는지를 알려줍니다. mouseEventQueue는 UI process 내의 deque로, 응답 대기 중인 mouse 이벤트를 추적합니다. MESSAGE_CHECK는 validation 조건이 실패할 때 송신 process와의 connection을 종료하는 macro이며, 손상된 renderer로부터 오는 비정상적인 IPC에 대한 주요 방어 수단입니다.
이 버그는 구조적인 문제에서 비롯됩니다. MESSAGE_CHECK(!queue.isEmpty()) guard는 함수 하단의 takeFirst() 호출만 보호하고 있었습니다. remoteUserInputEventData가 존재하는 경우, 함수는 더 앞선 분기로 진입해 guard 없이 queue.first()를 호출합니다. 손상된 web content process가 remoteUserInputEventData를 설정한 조작된 DidReceiveEvent를 전송한다고 가정합니다. 이때 queue가 비어 있는 상태라면, 빈 container에 대한 검증 없는 deque::first() 호출이 발생합니다. 결과적으로 손상된 renderer의 connection이 종료되는 대신 UI process가 crash하게 됩니다.
Before: After:
mouseEventHandlingCompleted() mouseEventHandlingCompleted()
│ │
├─ if (remoteUserInputEventData) { ├─ MESSAGE_CHECK(!queue.isEmpty())
│ queue.first() ← NO CHECK │
│ ... ├─ if (remoteUserInputEventData) {
│ } │ queue.first() ← now guarded
│ │ ...
├─ MESSAGE_CHECK(!queue.isEmpty()) │ }
│ │
└─ queue.takeFirst() └─ queue.takeFirst()
Significance
손상된 web content process가 조작된 DidReceiveEvent IPC 메시지를 전송함으로써 UI process를 의도적으로 crash시킬 수 있습니다. 이는 browser process의 무결성을 교란하는 다단계 exploit에서 유용한 primitive로 활용될 수 있습니다. 이 유형의 버그는 MESSAGE_CHECK가 특정 경로만 보호하고 그 위의 조건 분기는 보호하지 못하는 구조에서 발생합니다. alternate code path를 통한 IPC validation bypass로, WebKit의 process separation layer에서 역사적으로 자주 발생해 온 패턴입니다.