← All reports

[Site Isolation] Elect the NowPlaying session in the GPU process

Component: WebKit GPUProcess | 041d344

Source/WebKit/GPUProcess/GPUProcess.cpp

+void GPUProcess::recomputeNowPlayingOwner()
+{
+ Candidate* winner = nullptr;
+ for (auto& connection : m_webProcessConnections) {
+ for (auto& candidate : connection->nowPlayingCandidates()) {
+ if (!winner || isMoreEligible(candidate, *winner, m_currentNowPlayingOwner))
+ winner = &candidate;
+ }
+ }
+ ...
+}

Source/WebKit/GPUProcess/GPUConnectionToWebProcess.messages.in

+ SetNowPlayingCandidateState(WebCore::PageIdentifier pageID, WebKit::NowPlayingCandidateState state)
+ SetNowPlayingInfoForPage(WebCore::PageIdentifier pageID, WebCore::NowPlayingInfo info)
+ ClearNowPlayingInfoForPage(WebCore::PageIdentifier pageID)

NowPlayingManager in the GPU process owns the single system-wide NowPlaying/remote-control session — the thing that populates the lock screen and receives play/pause hardware commands. Previously it simply accepted whichever web process pushed info most recently, which was safe when one page mapped to one process.

This commit moves session election from each web process into the GPU process. Web processes now report per-page candidacy (SetNowPlayingCandidateState) and NowPlaying info (SetNowPlayingInfoForPage) separately over IPC, and GPUProcess::recomputeNowPlayingOwner picks the single system owner across all pages and processes using the same tiered comparator logic (presentation type, audio, playing state, size, recency of interaction) that PlatformMediaSessionManager previously ran within one process. Candidate state is keyed by {process, page}, and interaction recency switches from MonotonicTime to WallTime since monotonic clocks are not comparable across processes.

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)

Under Site Isolation a page's cross-origin subframes run in separate web processes, so without centralized arbitration an audible subframe process could push its NowPlaying info last and hijack the system session — and its remote-control commands — from a more eligible session in the same page. The election logic that used to be a within-process detail is now a cross-process trust decision.

The forward-facing pattern is a renderer-supplied identifier used as a key into shared cross-process state without proving the sending connection owns that identifier. Narrow: this adds three message handlers taking a PageIdentifier plus attacker-controlled comparator inputs (presentation type, isLargeEnoughForMainContent, isPlaying, interaction WallTime) — the match tell is a message receiver that stores into a {process, page}-keyed map before confirming the pageID belongs to that connection. Wider: audit the other GPUConnectionToWebProcess message handlers taking a PageIdentifier or MediaSessionIdentifier for the same missing ownership proof, and the analogous NetworkConnectionToWebProcess handlers — under Site Isolation every one of those now receives identifiers from processes that own only part of a page. Widest: comparator inputs supplied by an untrusted party are their own class — a tie-break or ranking function fed attacker-chosen WallTime values can be forced into orderings the designer never considered; look for any cross-process arbitration whose winner is decided by a comparator over remote-supplied fields, and check whether rapid or out-of-order candidate/info messages can leave the arbitration in a state inconsistent with what any single sender believes.