← All issues

[Site Isolation] Cross-process resource and loaderId aggregation in Page.getResourceTree

df1a3bd

Site Isolation 환경에서는 cross-origin frame이 각각 독립된 WebContent process에서 실행됩니다. 그러나 캐시된 subresource를 보유하는 CachedResourceLoader는 UIProcess가 아닌, 해당 frame을 호스팅하는 process에 존재합니다. 기존의 Page.getResourceTree는 cross-origin frame의 frame 구조와 URL은 올바르게 반환했지만, cross-process 조회 경로가 없어 loaderId와 resources는 빈 값으로 반환되었습니다.

LayoutTests/http/tests/site-isolation/inspector/page/resource-tree-resources-cross-origin-iframe.html

for (let attempt = 0; attempt < 50; ++attempt) {
({ frameTree } = await WI.backendTarget.PageAgent.getResourceTree());
child = frameTree.childFrames?.[0];
if (child && (child.resources || []).some((r) => r.url.endsWith("/resource-tree-subframe-style.css")))
break;
await new Promise((resolve) => setTimeout(resolve, 50));
}

이번 수정에서 proxy는 WebFrameProxy 트리를 순회하여 frame ID를 호스트 process별로 분류합니다. 각 process에는 해당 process의 frame ID만을 담은 typed GetFrameResourceData IPC 요청이 전송되고, 응답으로 받은 구조체는 CallbackAggregator를 통해 하나의 통합된 트리로 조립됩니다. round-trip을 수용하기 위해 이 명령은 비동기로 변경되었으며, secure decoding은 새로 추가된 serialization.in 파일에서 자동 생성됩니다.

이번 변경으로 Web Inspector에 비동기 multi-process IPC 경로가 새로 추가되었습니다. 여러 WebContent process에 걸친 CallbackAggregator 구조는, frame lifetime 관련 버그와 TOCTOU race가 나타나기 쉬운 전형적인 코드 패턴입니다.

frame-to-process 분류 순회는 frame 트리의 안정적인 snapshot 없이 수행됩니다. 순회 완료 후 IPC 응답이 도착하기 전에 cross-origin frame이 navigation하거나 detach되면, aggregator는 stale frame ID에 대응하는 데이터를 수신할 수 있습니다. 이 mismatch가 무시되는지, 잘못된 위치에 삽입되는지, 아니면 UAF로 이어지는지 추적이 필요합니다. WebContent process 내부의 WebInspectorBackend::getFrameResourceData는 UIProcess로부터 전달받은 frame ID를 순회합니다. navigation race로 인해 특정 frame ID가 다른 process에 속하게 되는 경우, WebContent process가 외부 frame의 데이터를 서빙하지 않도록 방지해야 합니다. 이 유효성 검증 경계는 이번에 새로 생긴 것입니다. loaderId 캐싱 경로는 frameNavigated 시점에 값을 캐시하며, 호스트 process가 보고한 식별자로 fallback됩니다. 이 두 code path는 항상 동일한 protocol ID를 도출해야 합니다. 만약 두 값이 달라지면, inspector 클라이언트가 mismatched loaderId를 통해 서로 다른 origin의 리소스를 상호 연계할 가능성이 있습니다.