[Site Isolation] Elect the NowPlaying session in the GPU process
Component: WebKit GPUProcess | 041d344
Source/WebKit/GPUProcess/GPUProcess.cpp
Source/WebKit/GPUProcess/GPUConnectionToWebProcess.messages.in
GPU process 안의 NowPlayingManager는 시스템 전체에서 하나뿐인 NowPlaying/remote-control 세션을 관리합니다. 잠금 화면 정보를 채우고 재생/일시정지 하드웨어 명령을 받는 바로 그 세션입니다. 기존에는 어떤 web process든 가장 최근에 정보를 push한 쪽을 그대로 채택하는 방식이었는데, 페이지 하나가 프로세스 하나에 대응하던 시절에는 이 방식으로도 안전했습니다.
이번 commit은 세션을 결정하는 로직을 각 web process에서 GPU process 쪽으로 옮깁니다. Web process는 이제 페이지 단위 후보 상태(SetNowPlayingCandidateState)와 NowPlaying 정보(SetNowPlayingInfoForPage)를 IPC를 통해 각각 보고하고, GPUProcess::recomputeNowPlayingOwner가 모든 페이지와 프로세스를 통틀어 시스템의 유일한 owner를 선정합니다. 이때 사용하는 판단 기준은 PlatformMediaSessionManager가 기존에 단일 프로세스 안에서 적용하던 것과 동일한 계층형 comparator 로직으로, presentation type, 오디오 여부, 재생 상태, 크기, 그리고 interaction의 최신성을 순서대로 따집니다. 후보 상태는 {process, page} 조합을 key로 관리하며, interaction의 최신성을 측정하는 기준도 MonotonicTime에서 WallTime으로 바뀌었습니다. Monotonic clock은 프로세스 간에는 서로 비교할 수 없기 때문입니다.
Before (single process wins by push order):
WebProcess A ──setNowPlayingInfo──►┐
WebProcess B ──setNowPlayingInfo──►├─► NowPlayingManager (last write wins)
After (GPU process arbitrates per page/process):
WebProcess A ──SetNowPlayingCandidateState(page1)──►┐
WebProcess B ──SetNowPlayingCandidateState(page1)──►├─► GPUConnectionToWebProcess
│ (candidates keyed by {process,page})
▼
GPUProcess::recomputeNowPlayingOwner()
(tiered comparator, stable tie-break)
▼
NowPlayingManager (single owner)
Significance
Site Isolation 환경에서는 한 페이지의 cross-origin subframe들이 서로 다른 web process에서 실행됩니다. 따라서 중앙에서 조정하는 절차가 없다면, 소리를 내는 subframe의 process가 NowPlaying 정보를 가장 나중에 push해서 같은 페이지 안의 더 우선순위 높은 세션으로부터 시스템 세션과 그에 딸린 remote-control 명령을 가로챌 가능성이 있습니다. 원래 프로세스 내부의 사소한 디테일에 불과했던 이 election 로직이, 이제는 프로세스 간 신뢰를 판단하는 결정으로 격상된 셈입니다.
Audit directions
이번 변경에서 눈여겨봐야 할 패턴은, renderer가 넘겨준 식별자를 공유되는 cross-process 상태의 key로 사용하면서도 그 connection이 실제로 해당 식별자를 소유하는지는 확인하지 않는다는 점입니다. 좁게 보면, 이번 commit은 PageIdentifier와 함께 attacker가 통제 가능한 comparator 입력값(presentation type, isLargeEnoughForMainContent, isPlaying, interaction WallTime)을 받는 message handler 세 개를 추가합니다. 여기서 살펴야 할 특징은, message receiver가 pageID가 해당 connection 소유인지 확인하기도 전에 {process, page} key의 map에 값을 먼저 저장한다는 점입니다. 조금 더 넓게 보면, PageIdentifier나 MediaSessionIdentifier를 인자로 받는 다른 GPUConnectionToWebProcess message handler들에도 같은 방식으로 소유권 검증이 빠져 있지 않은지 점검할 필요가 있습니다. 이는 대응되는 NetworkConnectionToWebProcess의 handler들에도 동일하게 적용되는데, Site Isolation 하에서는 이들 모두가 페이지의 일부만 소유한 process로부터 식별자를 전달받게 되기 때문입니다. 가장 넓은 관점에서 보면, 신뢰할 수 없는 쪽이 제공하는 comparator 입력값은 그 자체로 하나의 취약점 범주에 해당합니다. Tie-break나 ranking 함수가 attacker가 고른 WallTime 값을 입력받는 경우, 설계자가 전혀 고려하지 못한 순서로 강제될 가능성이 있습니다. 승자를 remote로 전달된 필드에 대한 comparator로 결정하는 cross-process arbitration 로직이 또 있는지 찾아보고, candidate/info 메시지가 빠르게 연속되거나 순서가 뒤바뀌어 도착했을 때 arbitration 상태가 어느 한쪽 sender가 믿고 있는 상태와 어긋나게 되지는 않는지 확인해야 합니다.