RFC-0013:複製 VMO 對應

RFC-0013:複製 VMO 對應
狀態已接受
區域
  • 核心
說明

系統呼叫,可從對應項目建立 VMO 的 CoW 副本,不需要控點。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2020-10-26
審查日期 (年-月-日)2020-12-09

摘要

目前只有在擁有 VMO 控制代碼的情況下,才能建立 VMO 的 CoW 副本。這不足以用於 Zygote 使用情境,因為這類情境需要 CoW 複製整個位址空間,包括所有 VMO 控制代碼已關閉的對應。這項 RFC 建議使用新的系統呼叫來解決這個問題。

動機和問題描述

Linux 版 Chromium 會從 Zygote 程序分叉,藉此產生算繪器,大幅節省記憶體和 CPU 資源。我們希望在 Fuchsia 上實現這些節省。

為此,我們需要實作「位址空間複製」作業,

  • 程序根 VMAR
  • 參照位址空間中對應 VMO 的部分控制代碼

將傳回:

  • 新程序,其位址空間會填入輸入程序中對應 VMO 的副本
  • 對於輸入程序中參照 VMO 的每個控制代碼,新程序中參照該 VMO 對應副本的新控制代碼

新增這個系統呼叫後,我們就能在使用者空間中輕鬆實作這項功能。 這項作業的原理是使用 ZX_INFO_PROCESS_MAPS 取得位址空間配置,並使用 zx_vmar_create_vmo_child 建立每個對應的副本,但有控制代碼的 VMO 除外,這些 VMO 會使用 zx_vmo_create_child 處理。

設計

zx_vmar_create_vmo_child

zx_status_t zx_vmar_create_vmo_child(zx_handle_t handle,
                                     uint32_t options,
                                     zx_vaddr_t addr,
                                     size_t size,
                                     zx_handle_t* out)

Creates a CoW clone of the pages mapped in the range addr to addr+size in the VMAR referenced by handle. 範圍必須是單一 VMO 對應的子範圍,也就是說,範圍不得跨越兩個對應,也不得包含任何未對應的網頁。結果是新的 VMO,屬於範圍內對應 VMO 的子項。

允許的選項為 ZX_VMO_CHILD_SNAPSHOT、ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE 和 ZX_VMO_CHILD_NO_WRITE。解讀方式與 zx_vmo_create_child 相同。 (基於安全考量,目前不允許使用 ZX_VMO_CHILD_SLICE: 必須特別注意,確保修改父項 VMO 的功能不會破壞任何安全界線。)

如果符合下列條件,則傳回 ZX_ERR_INVALID_ARGS:

  • 範圍 addr 至 addr+size 不是單一 VMO 對應的子範圍
  • addr 或 size 未與網頁對齊

如果符合下列條件,則傳回 ZX_ERR_ACCESS_DENIED:

  • 對應是使用新旗標 ZX_VM_CANNOT_CREATE_VMO_CHILD 完成,或 vmar 選項包含此旗標
  • handle 沒有 ZX_RIGHT_INSPECT

如果 handle 不是有效的控制代碼,則傳回 ZX_ERR_BAD_HANDLE;如果 handle 不是 VMAR,則傳回 ZX_ERR_WRONG_TYPE;如果 VMAR 已毀損,則傳回 ZX_ERR_BAD_STATE。如果適用文件中的原因,也可以傳回 zx_vmo_create_child 傳回的任何錯誤。

傳回的 VMO 控制代碼會包含 ZX_DEFAULT_VMO_RIGHTS,並有下列變更:

  • 如果指定 ZX_VMO_CHILD_NO_WRITE,系統就會移除 ZX_RIGHT_WRITE。
  • 如果對應可執行,且未指定 ZX_VMO_CHILD_NO_WRITE,系統會新增 ZX_RIGHT_EXECUTE。 也就是說,您可以建立可執行對應項的可執行檔副本,但必須為唯讀。

ZX_VM_CANNOT_CREATE_VMO_CHILD

ZX_VM_CANNOT_CREATE_VMO_CHILD 是新的 zx_vm_options_t 標記,可為 VMO 對應或 VMAR 指定。這項標記可讓對應 VMO 或建立 VMAR 的程式碼禁止 zx_vmar_create_vmo_child。

實作

新增系統呼叫並非複雜的變更,一個 CL 即可完成。 實作複製演算法不在本 RFC 的討論範圍內。

效能

由於這個系統呼叫只會在 Zygote 實作中使用,因此不值得單獨進行基準測試。我們應改為評估 Zygote 實作的整體效能。

安全性考量

目前無法使用 VMAR 參照 (而非控制代碼) 建立 VMO 子項,但這項 RFC 可望實現這個目標。這有點像是無中生有地授予新能力。

就這個情況而言,風險似乎不高,因為最終結果與建立新的 VMO 並複製資料 (但記憶體用量較少) 相同,而這在先前是可行的。如果需要禁止存取,這項 RFC 建議使用 zx_vm_options_t 標記 (ZX_VM_CANNOT_CREATE_VMO_CHILD)。

測試

系統會對系統呼叫執行單元測試。 未來實作位址空間複製的測試,也會做為系統呼叫的整合測試。

說明文件

這份 RFC 是 zx_vmar_create_vmo_child 說明文件的起點。

缺點、替代方案和未知事項

還有哪些策略可以解決相同問題?

我們可以新增系統呼叫,執行整個位址空間的複製作業。 無論是介面或實作,這都會是非常複雜的系統呼叫。 最好將複雜性推入使用者空間。

我們可以新增系統呼叫,允許從對應項目鑄造 VMO 控制代碼。這項功能可讓使用者空間實作 zx_vmar_create_vmo_child,方法是先從對應建立控制代碼,然後呼叫 zx_vmo_create_child。但一般來說,Zircon API 只允許鑄造新建立物件的控制代碼,以便更容易分析介面。這個系統呼叫必須憑空建立控制代碼。

有許多技巧可用於避免關閉任何 VMO 控制代碼,例如修改所有建立及對應 VMO 的程式碼,避免關閉這些控制代碼,或是攔截 zx_handle_close。不過,這不足以實作位址空間複製,因為載入器服務會在程序開始執行前,將部分 VMO 對應至程序,而這無法協助您取得這些 VMO 的控制代碼。我們可以修改載入器服務,將必要的控制代碼傳遞至程序,但這比新增這個系統呼叫更費工。

既有技術和參考資料

https://chromium.googlesource.com/chromium/src/+/master/docs/linux/zygote.md http://neugierig.org/software/chromium/notes/2011/08/zygote.html