瀏覽器會信任解析陌生人製作之媒體檔案的程式碼,而攻擊者已多次將這些格式武器化,用以攻擊解碼器的記憶體錯誤。Mozilla 贊助 Rust 已近七年;這門語言被構想為 C++ 的安全替代方案,但截至 2016 年中,它尚未有任何部分在 Firefox 中正式上線;這門安全優先的語言仍須在一個龐大且效能關鍵的 C++ 瀏覽器內部證明自己。

保護使用者的顯而易見做法都未能奏效。修補 C++ 解析器意味著必須永遠防禦每一個新漏洞;將其沙箱化雖縮小了影響範圍,卻未移除該類錯誤;而用 Rust 重寫整個瀏覽器則是一場多年期的賭注,會在過渡期間破壞產品。Mozilla 的媒體播放團隊改為挑選一個範圍有限且安全關鍵的部分:處理不受信任網路媒體的 mp4 中繼資料解析器。

Ralph Giles 與 Matthew Gregan 為該解析器撰寫了純 Rust 的替代品,透過 C API 對外暴露,使周遭的 C++ 建置維持不變,並驗證其產生的結果與被替換的程式碼完全相同。Firefox 48 隨後將其帶到所有桌面平台,首次讓正式環境的 Rust 呈現在數億使用者面前,並計畫下一步支援 Android。

這項試點之所以成功,是因為它把意識形態轉化為證據。Rust 的編譯期規則為該元件消除了記憶體錯誤類別,而非增加另一層防禦;Firefox 電傳數據記錄到,新程式碼在超過十億次使用中零問題。Mozilla 稱這是第一步,而非終點:一套經證實的範本——替換風險最高的有限元件、證明行為一致、上線、並量測——供未來更大規模的遷移使用。

從處理不受信任資料的解析器開始遷移

媒體解析是不受信任位元組與原生程式碼交會之處,因此試點鎖定每行程式碼中最大的剩餘風險

自成一體的解析器具有清晰且可測試的邊界:可檢查其輸出是否與 C++ 元件完全相同

編譯期記憶體安全移除了整個錯誤類別,而非增加另一層防禦

在十億次使用中零電傳問題,將一場語言賭注轉化為可量測的正式環境證據

透過 C API 暴露 Rust,讓解析器得以在不擾動其餘 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