
CVE-2026-74970、Firefox WebRenderにおけるFissionサイト分離バイパス
このディレクトリには、Firefox WebRender における Fission サイト分離の認可バイパスを再現するための、誠実な再現用スキャフォールドが含まれています。Fission では、各コンテンツプロセスがそれぞれ固有の PipelineId 名前空間を所有しますが、コンポジット可能な PipelineId を登録する GPU プロセスのコードは、その PipelineId の名前空間が送信元プロセスに属しているかどうかを一切検証していませんでした。したがって、侵害されたコンテンツプロセスは、別のプロセスの名前空間に PipelineId を登録し、共有マネージャー内でそのオリジンの非同期イメージパイプラインを上書きすることができます。
ここにあるものはすべて、合成コンテンツのみを使用するローカルビルドの Firefox ツリーを対象としています。稼働中または第三者のシステムを攻撃、接触、調査、参照することは一切ありません。これはリモートコード実行でもメモリ破壊でもありません。脅威モデルは、すでに侵害されたコンテンツプロセスです。
対応する PoC リポジトリ: https://github.com/defineid/Trespasser
解説記事: このポートフォリオ内の writeup-webrender-pipelineid.html。
| 項目 | 値 |
|---|---|
| CVE | CVE-2026-74970 |
| コンポーネント | Core / Graphics: WebRender |
| 分類 | サイト分離バイパス |
| CWE | 862 (認可の欠如) · 284 (不適切なアクセス制御) |
| 修正バージョン | Firefox 154 · ESR 153.1 |
| バグ | https://bugzilla.mozilla.org/show_bug.cgi?id=2056558 |
| PoC リポジトリ | https://github.com/defineid/Trespasser |
Fission では、WebRender は各コンテンツプロセスに固有の PipelineId 名前空間を割り当てます。GPU プロセスのブリッジは、名前空間が送信元プロセスに属さないリソースを拒否することが期待されており、これによりあるコンテンツプロセスが別のプロセスのレンダリングリソースをアドレス指定したり上書きしたりできないようになっています。
GPU プロセスで実行される WebRenderBridgeParent::AddPipelineIdForCompositable は、受信したパイプラインをルート/WebRender ガードおよびこのブリッジ自身が登録したパイプラインの集合に対して検証していましたが、PipelineId に対して MatchesNamespace を呼び出すことは一切ありませんでした。同じファイル内の image-key、font-key、blob-key の各パスはすべてこの MatchesNamespace による所有権チェックを実行していますが、PipelineId のパスだけは実行していませんでした。RemovePipelineIdForCompositable も同様にチェックされておらず、削除時にも同じ名前空間所有権の穴が存在します。
下流では、AsyncImagePipelineManager::AddAsyncImagePipeline がパイプラインの一意性を MOZ_ASSERT のみで保護しており、これはリリースビルドでは何もしない処理にコンパイルされます。そのため、偽造されたクロス名前空間の PipelineId が共有の AsyncImagePipelineManager に到達すると、マネージャーは重複を拒否せず、被害オリジンの既存の非同期イメージパイプラインエントリを黙って上書きしてしまいます。
これらを連鎖させることで、侵害されたコンテンツプロセス A は、コンテンツプロセス B (Fission 下では別プロセスにある異なるオリジン) の名前空間に属する PipelineId を偽造し、それをコンポジット可能登録パスで送信し、GPU プロセスに受理させて共有マネージャー内の B のイメージパイプラインを破壊させることができます。
Fission 下ですでに侵害されたコンテンツプロセスです。攻撃者は、すでに 1 つのコンテンツプロセス内でコード実行を獲得しており (たとえば別のコンテンツプロセスバグを通じて)、攻撃者が選択したフィールドを持つ WebRender IPC メッセージを送信できると想定されています。この欠陥は、そのプロセスがサイト分離境界を越えて別のオリジンのレンダリングリソースに到達できるようにする、認可の欠如です。
これは Fission サイト分離の認可バイパスであり、メモリ破壊ではありません。影響はクロスオリジンのレンダリング混同とクロスタブのサービス拒否です。下流のコンシューマーは null ガードと参照カウントで保護されているため、コード実行には至りません。PoC はコード実行を主張してはならず、また主張していません。
README.md — このファイル。forge-namespace.patch — ローカルの Firefox ツリー向けの研究用パッチ。コンテンツ側では、XRE_IsContentProcess() と環境変数 MOZ_POC_FORGE_WR_NAMESPACE によってガードされ、送信される PipelineId の名前空間を偽造する。GPU プロセスの親側では、クロス名前空間の PipelineId が登録された際に ACCEPTED 診断を出力し、欠落していたチェックによってそれが通過してしまったことを実証する。poc.html — コンテンツ側のみの最小テストケース: WebGL キャンバス(非同期イメージパイプラインが作成される)と、クロスオリジンのアウトオブプロセス iframe(Fission によって別のコンテンツプロセスに配置される)。標準ビルドでは通常どおりレンダリングされ、観測可能な動作は何も起こらない。victim.html — iframe が読み込む合成された第2のオリジン。スクリプトを含まない単純なページで、その唯一の役割は生きたクロスオリジンドキュメントとして存在することであり、Fission 下では独自の PipelineId 名前空間を持つ専用のコンテンツプロセスに配置される(偽造された登録が標的とする名前空間)。poc-render.png — ローカルの標準 Firefox 140.11.0esr で poc.html を読み込んだスクリーンショット。テストページが通常どおりレンダリングされている様子を示す: WebGL キャンバスがフレームを描画し、アウトオブプロセス iframe が victim.html を読み込んでいる。無害なレンダリングのみを示している。バイパス自体には研究用パッチと脆弱なビルドが必要であり、ここではトリガーされていない(検証状況を参照)。これらの手順は、作者がローカルの Firefox チェックアウトに対して実行することを想定している。この環境では Firefox に対して何も実行されていない(以下の検証状況を参照)。
脆弱な Firefox ソースツリー(154 以前 / ESR 153.1 以前)をチェックアウトし、Fission が有効であることを確認する(fission.autostart = true、最近のビルドではデフォルト)。
ソースツリーの最上位から研究用パッチを適用する:
patch -p1 < forge-namespace.patch
パッチは gfx/layers/wr/WebRenderBridgeChild.cpp(コンテンツ側、名前空間を偽造する)と gfx/layers/wr/WebRenderBridgeParent.cpp(GPUプロセス側、ACCEPTED 診断を出力する)に変更を加えます。どちらの変更も、ガード条件が満たされない限り不活性です。
通常どおりビルドします(./mach build)。
このディレクトリを配信して、poc.html のアウトオブプロセス iframe が、真に異なる登録可能ドメインからコンパニオンの victim.html を読み込むようにします。これにより Fission は iframe を独自のコンテンツプロセスに配置します。例えば、python3 -m http.server 8000 --bind :: を実行し、http://victim.localtest.me:8000/victim.html から iframe を読み込みます。poc.html 内のインラインコメントを参照してください。
forge 変数を設定してビルドを起動し、テストページを読み込みます:
MOZ_POC_FORGE_WR_NAMESPACE=999999 ./mach run --temp-profile poc.html
999999 は、実在するどのプロセスにも属さないように選ばれた任意の名前空間値です。これにより、偽造されたクロス名前空間の登録がログ上で明確になります。
パッチを適用した脆弱なビルドでは、GPU プロセスの親が、そのようなプロセスに属さない名前空間を持つ PipelineId を受け入れて登録し、次のように出力します(これは writeup に示されている正確な形式です):
[POC-2056558] ACCEPTED cross-namespace PipelineId:
sender-namespace=4 pipeline-namespace=999999 (should have been rejected)
sender-namespace は送信側のコンテンツプロセスが正当に所有する名前空間であり、pipeline-namespace は偽装された値です。この2つの異なる値と、登録が受け入れられたという事実こそが要点です。これを拒否すべき所有権チェックが欠落しています。
修正済みのビルド(154 / ESR 153.1 以降)では、同じメッセージが IPC_FAIL で拒否され、そのような ACCEPTED 行は出力されません。PipelineId の経路が MatchesNamespace を強制するようになったためです。
PipelineId の経路において、リソースキーの経路がすでに使用しているものと同じ名前空間所有権チェックを強制します:
if (!MatchesNamespace(aPipelineId)) {
return IPC_FAIL(this, "PipelineId namespace does not belong to the sending process");
}
AddPipelineIdForCompositable(および対称的にRemovePipelineIdForCompositable)に適用され、名前空間が送信元プロセスに属さないPipelineIdを拒否し、バイパスを塞ぎます。
poc.htmlをローカルの標準Firefox 140.11.0esrで一度読み込み、poc-render.pngとしてキャプチャしました。このスクリーンショットはテストページが正常にレンダリングされている様子のみを示しています(WebGLキャンバスがフレームを描画し、プロセス外iframeがvictim.htmlを読み込みます)。ローカルのFirefoxは標準の非パッチビルドであるため、スクリーンショットには偽造された登録も[POC-2056558]ログ行も含まれていません。クロス名前空間受け入れの出力を取得するには、上記の手順に従ってパッチをローカルの脆弱なビルドに適用し、ご自身で実行してください。このスキャフォールドには、欠落した認可チェックがクロス名前空間のPipelineIdを通してしまうことを示す以上の悪用プリミティブは含まれていません。コード実行を試みることも、メモリ破壊を引き起こすこともありません。
これは、すでに報告され、すでにパッチが適用されたCVEの解説記事のために、合成された自作コンテンツを用いてローカルでビルドしたFirefoxツリーを対象としています。リサーチパッチはローカルの開発者ビルドにのみ影響するようにガードされており、解説記事が説明する侵害されたコンテンツプロセスの前提をコード化しています。リモートエクスプロイトではありません。ここにあるものは、稼働中または第三者のサービスを攻撃、接触、調査、あるいは攻撃への参照を行うものではありません。テストケースのプロセス外iframeはFissionのプロセス分割を再現するために不可欠であり、そのように文書化されています。トップページ自体には他のネットワーク依存関係はありません。