ブラウザーは、見知らぬ人が作成したメディアファイルを解析するコードを信頼しており、攻撃者はそうしたフォーマットをデコーダーのメモリバグに対して繰り返し武器化してきた。MozillaはC++の安全な代替として構想された言語であるRustを約7年間支援してきたが、2016年半ばまでにそのいずれもFirefoxには出荷されていなかった。安全性優先のこの言語は、巨大で性能重視のC++ブラウザーの中で自らを証明する必要がまだあった。

ユーザーを保護する明白な方法はいずれも不十分だった。C++パーサーにパッチを当てることは、新たな脆弱性それぞれを永久に防御することを意味した。サンドボックス化は影響範囲を縮小したが、バグの種類自体は除去しなかった。そしてブラウザー全体をRustで書き直すことは、その途中で製品を壊しかねない多年がかりの賭けだった。MozillaのMedia Playbackチームは代わりに、境界のはっきりしたセキュリティ上重要な一部分を選んだ。信頼できないウェブメディアに対して実行されるmp4メタデータパーサーである。

Ralph GilesとMatthew Greganはそのパーサーの純粋なRustによる代替実装を書き、C APIを通じて公開することで周囲のC++ビルドをそのまま保ち、置き換えたコードと同一の結果を生み出すことを検証した。その後Firefox 48がそれをすべてのデスクトッププラットフォームに搭載し、製品版Rustを初めて数億人のユーザーの前に置いた。Androidのサポートは次に計画されていた。

この試みが機能したのは、イデオロギーを証拠に変えたからである。Rustのコンパイル時の規則は、防御の層をさらに一つ加えるのではなく、そのコンポーネントについてメモリバグの種類を排除した。そしてFirefoxのテレメトリーは、新しいコードの10億回を超える使用で問題ゼロを記録した。Mozillaはこれを終わりではなく第一歩と呼んだ。すなわち、今後のより大規模な移行に向けた、実証済みのテンプレート——最も危険な境界のはっきりしたコンポーネントを置き換え、同等性を証明し、出荷し、測定する——である。

移行は、信頼できないデータを消費するパーサーから始める

メディア解析は信頼できないバイト列がネイティブコードと出会う場所であるため、この試みは行あたりの残存リスクが最大の対象を狙った

自己完結したパーサーには明確で検証可能な境界があり、C++コンポーネントとの同一の出力を確認できた

コンパイル時のメモリ安全性は、防御の層をさらに一つ加えるのではなく、バグの種類全体を除去した

10億回の使用でテレメトリー上の問題がゼロだったことが、言語への賭けを測定可能な製品上の証拠に変えた

RustをC APIを通じて公開したことで、C++ビルドの残りの部分を乱すことなくパーサーを出荷できた

新しい技術をレガシーコードベースに持ち込むことは、書き直しではなく移植である。検証可能な境界を持つ最も危険なコンポーネントを選び、出荷し、製品データにさらなる拡大の根拠を示させるのだ

Firefox 48は初の製品版Rustをすべてのデスクトップユーザーに届け、Mozillaはこの節目を終わりではなく序盤の一手として扱った。Oxidation wikiは、どのRust機能が各プラットフォームにいつ搭載されるかを整理し、Bugzilla 1284816はRustをFirefoxビルドの必須部分にすることの追跡を行った。展開中に見つかった低メモリ時のクラッシュは、クラッシュする代わりにエラーを返す失敗可能なスレッドビルダーAPIに切り替えることでFirefox 48向けに修正された。同じ道筋——テレメトリーで証明された、境界のはっきりしたメモリ安全な置き換え——が、その後に続くRustコンポーネントの青写真となった。

出典をたどる

出典

  1. Shipping Rust in Firefox Mozilla Hacks · hacks.mozilla.org ·
  2. mozilla/mp4parse-rust — Parser for ISO Base Media Format aka video/mp4 written in Rust GitHub · github.com