← WebKit — 2026-W36

7b5f5df9aba3f2e84f450068496c3ec50fd89d23  [Site Isolation] Concurrent navigations to the same site should share the same process

severity medium class PolicyBypass confidence 0.35 signal score 9.97 Source/WebKit/UIProcess
Primitive: Site-isolation FrameProcess reservation during navigation
Triage note: prepareProcessForNavigation is threaded browsingContextGroup and sourceProcess and now reserves a per-site FrameProcess (ensureProcessForSite + addFrameProcessAndInjectPageContextIf) when site isolation is enabled. Touches the site-isolation process-assignment boundary but is largely plumbing with no clearly isolated bug stated in-diff, so not graded exploitable.
Structural signals: smartptr_member_added (+6.47), uaf_lifetime (+2.2), surgical (+1.3)

Commit message

[Site Isolation] Concurrent navigations to the same site should share the same process
https://bugs.webkit.org/show_bug.cgi?id=321029
rdar://184063194

Reviewed by Sihui Liu.

With site isolation enabled, there is a race where two concurrent navigations to
the same site can create two different web processes. It is expected that
navigations to the same site should be in the same process.

Both navigations reach WebProcessPool::processForNavigation and notice that
BrowsingContextGroup::m_processMap doesn't have an existing process entry for
their site. So, they both create a new web process for themselves, creating two
processes for the same site.

The entry isn't added until ProvisionalPageProxy::initializeWebPage runs, and
for a main frame navigation that is on the far side of the
addAllowedFirstPartyForCookies IPC in prepareProcessForNavigation. Any
navigation that reaches prepareProcessForNavigation during that gap
sees an empty process map for the same site.

In this patch, I reserve a process before that hop, in
prepareProcessForNavigation. This also keeps the reservation up to date
since prepareProcessForNavigation is called multiple times to retry
process selection if the chosen process dies during the
`addAllowedFirstPartyForCookies` IPC.
To perform the reservation I call BrowsingContextGroup::ensureProcessForSite there,
then register the site and inject page context for the group's other pages,
exactly as initializeWebPage does.

m_processMap only holds the FrameProcess weakly, so something has to keep it
alive in the meantime. I capture a strong reference in the completion handler
used for the retry attempts, so the reservation lasts exactly until that
handler has run. By then continueNavigationInNewProcess has created the
ProvisionalPageProxy that owns the FrameProcess, or the navigation was abandoned
and nobody needs it. I don't store it in API::Navigation, because a navigation
outlives the frames using its process. That was the leak 319916@main fixed by
deleting the equivalent reference for the shared process.

This patch only handles main frame navigations. Subframe navigations return
from processForNavigation synchronously and create the ProvisionalFrameProxy
that registers the site in the same task, so two of them can never both find
the site unregistered.

Tests: http/tests/site-isolation/concurrent-same-site-navigations-use-same-process.html
       TestWebKitAPI.SiteIsolation.ConcurrentPopupNavigationsToSameSiteShareProcessWhenOneFails

* LayoutTests/http/tests/site-isolation/concurrent-same-site-navigations-use-same-process-expected.txt: Added.
* LayoutTests/http/tests/site-isolation/concurrent-same-site-navigations-use-same-process.html: Added.
* Source/WebKit/UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigation):
(WebKit::WebProcessPool::prepareProcessForNavigation):
* Source/WebKit/UIProcess/WebProcessPool.h:
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/SiteIsolation.mm:
(TestWebKitAPI::TEST(SiteIsolation, ConcurrentPopupNavigationsToSameSiteShareProcessWhenOneFails)):

Canonical link: https://commits.webkit.org/320471@main

Before / after

Loading diff…