RFC-0064:Box <Knox>

RFC-0064:方塊 <Knox>
狀態已遭拒
區域
  • FIDL
說明

推出透過與 FIDL 訊息相關聯的輔助 VMO 傳輸大型結構化資料物件的機制。

作者
提交日期 (年/月)2018-09-27
審查日期 (年/月)2020-06-17

拒絕原因

透過 FIDL 在對等點之間傳輸大型訊息的問題非常重要,是開發人員目前面臨的非常問題,以及 FIDL 目前的不足之處。結合管道限制後,在定義訊息時,很容易就會根據執行階段行為超過這些限制,同時還會導致訊息大小不易 (例如最大分頁),導致這個問題至少無法用應用程式程式碼 (大規模) 解決。解決方案必須由 FIDL 提供

簡單來說,FIDL 需要讓程式庫作者能夠避免因通訊協定限制 (例如 Zircon 管道的位元組數量和處理方式) 而產生執行階段意外產生驚喜的方法,而 FIDL 開發人員必須依賴繫結來實作可能會交換大型訊息的通訊協定。

這個 RFC 有許多需要的成分,日後將做為參考。請特別注意以下幾點:

  • 問題陳述和動機。
  • 導入靜態驗證,以保證訊息符合通訊協定限制,或選擇採用繫結提供的執行階段機制來「適宜」 (可能會產生一些額外費用)
  • 依賴「值類型與資源類型」的差異,在便利性/效能的取捨方面有所不同。

儘管有上述情況,此 RFC 仍因為下列原因而遭到拒絕:

  • 訊息的位元組和控點如何從一個點傳送至另一個點的傳輸方式並不等同於傳輸格式問題,且不需要修改線路格式以符合相關規定。
  • 引入 box<T> 標記有助於在訊息中找出可以進行拳擊的地點,即是精細的機制,可在訊息中的任意位置 (大部分) 指出拳擊行為。目前的想法是,在方法層級提供註解較為理想,例如採用概略說明機制,而不要使用宣告網站,
  • 由於 FIDL 逐步全面化,以便支援 Zircon 管道以外的不同傳輸方式,我們必須考量每項傳輸機制都有其本身限制。舉例來說,當我們希望將 FIDL 擴展到 Zircon 圖版時,大小限制會有所不同,而且不允許使用任何帳號代碼。這種做法可以進一步產生建議使用方法層級註解 (而非以類型為中心的註解) 的檢視畫面。

目前,要在應用程式中解決這種情況的方法,是使用 fuchsia.mem/Data 類型,也就是在內嵌或 VMO 中代表資料的聯集。將此方法一般化為使用語法糖的任何要求和/或回應,就像錯誤一樣,再加上繫結支援,是推動這個主題繼續發展的主要優勢。

摘要

推出透過與 FIDL 訊息相關聯的輔助 VMO 傳輸大型結構化資料物件的機制。

提振精神

ZX_CHANNEL_MAX_MSG_BYTES 所定義,在程序之間可透過 Zircon 管道傳輸的 FIDL 訊息大小上限設有上限。撰寫本文時,含 FIDL 標頭的限制上限為 64 KB。

雖然許多應用程式都設有這項限制,但有時必須傳輸較大的物件。這對 FIDL API 設計人員造成了挑戰,因為他們必須設計傳輸這些物件的替代方式,例如:

  • 分頁:傳輸物件集合 (通常是向量) 時,請以增量方式傳送物件,而非一次提交所有物件。
    • 只要每個物件小於限制 (將標頭和其他欄位納入考量),也可正常運作。
    • 由於目前沒有用於估算 FIDL 訊息大小或逐步建構訊息的 API,因此開發人員很難判斷如何將物件有效封裝到訊息,又不會超過到期限制。
  • VMO 封裝:請將這類物件複製到 VMO,而不要在 FIDL 訊息本身內傳輸大型物件。這個屬性通常會以 fuchsia.mem/Buffer 表示。
    • 適用於位元組向量 (blob)。
    • 結構化資料物件發生問題,因為開發人員負責叫用序列化/去序列化。
    • 需遏止共用記憶體造成的安全性威脅。

如果不預期會發生這個問題,是導致執行階段不穩定的主因。

我們認為 FIDL 應提供用於傳輸大型資料物件的「內建」、「安全」、「可靜態驗證」及「有效率」機制。

設計

簡單明瞭的箱子

box 是容器,用於存放可能的大型資料物件,在訊息總大小 (包括標頭) 超過 Zircon 管道1的限制時,需要從頻段傳輸。

box 僅存放資料物件,不能容納有帳號代碼的物件2

設計時間,FIDL 通訊協定作者。

  • 當資料物件預期含有這些物件的訊息可能會超過管道限制時,系統就會將資料物件封裝成方塊

在「編譯時間」中,FIDL 編譯器...

  • 剖析宣告
  • 以靜態方式確認每個方塊僅含資料物件 (無控點)
  • 靜態驗證每則 FIDL 訊息的大小上限未超過管道限制 (在靜態訊息大小強制執行模式下)
    • 假設向量和字串尺寸都一樣
    • 假設可擴充的聯集和結構 (資料表) 可能變得較大
    • 拒絕遞迴結構,除非遞迴方塊切斷

編譯時間,每個 FIDL 程式碼產生器...

  • 產生的程式碼足以為裝箱資料序列化及還原序列化

執行階段,FIDL 編碼器。

  • 和所有外線物件一樣,封裝適當數量的方框物件
  • 可封裝所有無法放入 VMO 的已包裝物件

runtime 中,FIDL 解碼器。

  • 存取包含已裝箱物件的 VMO (如果有的話) 之前,請確保其具有 VMO 的唯一控制代碼 (系統不會共用 VMO)
  • 這個外掛程式能從訊息內文和 VMO 擷取盒子物件

語言詳細資料

引入全新的內建 FIDL 類型,註明 box<T>T 會指定要放入方塊的物件類型。

  • T 必須是沒有直接或間接包含控制代碼的參照類型。
  • T 不得為原始類型。
  • T 可能是選用類型。

新的類型 box<T> 可用於任何接受參照類型的地方,例如結構體聯集向量字串

範例方塊類型

  • box<string>
    • 一個包含無界限字串的方塊
  • box<int>
    • 錯誤:方塊不得包含原始類型的物件
  • box<vector<T>:100>
    • 包含 T 物件的定界向量的方塊
  • box<vector<T>>
    • 這個方塊包含無界限的 T 物件向量
  • vector<box<T>>:100
    • 是 T 物件的定界向量。
  • box<string:100>
    • 包含受限字串的方塊
  • box<string>
    • 一個包含無界限字串的方塊
  • box<MyStruct>
    • 一個包含結構的方塊
  • box<MyStruct?>
    • 一個包含選用結構的方塊
  • box<MyStruct>?
    • 錯誤:方塊不得為選填

宣告範例

interface Database {
    // OK
    1: SelectTop(string:1000 query) -> (box<Record> record);

    // ERROR: reply may exceed message size limit
    // consider wrapping large objects in a box<>,
    // "Record" size is unbounded
    2: BadSelectTop(string:1000 query) -> (Record record);

    // OK
    3: SelectAll(string:1000 query) -> (box<vector<Record>> records);

    // ERROR: reply may exceed message size limit
    // consider wrapping large objects in a box<>,
    // "vector<Record>" size is unbounded
    4: BadSelectAll(string:1000 query) -> (vector<Record> records);
};

struct Record {
    string name;
    string address;
};

有線格式

(章節不完整)。

提案 1:在序列化的深度週遊期間,將接觸的所有方塊新增至佇列。完成後,先按照線外物件依序傳遞封裝項目,直到釋出空間,然後計算剩餘的黑邊物件大小,分配單一 VMO,並繼續從節點封裝方塊內容

提案 2:類似提案 1,但在每個包裝盒中放入各自的 VMO 中雖然較容易實作,但可能會有更嚴格的限制

構想 3:也許我們就應該完全捨棄方塊概念,並改為在方法層級執行操作,例如註解,例如 [Huge]

繫結

(章節不完整)。

強化的 VMO Syscall

(章節不完整)。

提案 1:定義「確保未共用」標記、確認 VMO 只有一個控制代碼、不與其他 VMO 共用頁面,且未對應,可將這個標記傳送至 zx_vmo_read/write/map 等。

提案 2:定義新的系統呼叫,檢查 VMO 是否未共用

提案 3:確實檢查 VMO 是否已取消共用 (應該不需要人工管理)

提案 4:棄踢 VMO 並改用 View

導入策略

(章節不完整)。

人體工學

(章節不完整)。

說明文件與範例

(章節不完整)。

回溯相容性

除了提供轉移大型資料物件的機制之外,方塊也有助於解決靜態安全疑慮

目前,如果程式嘗試傳輸超過管道限制的 FIDL 訊息,就會在執行階段失敗,導致系統不穩定。一旦可用方塊,應該就能在 FIDL 編譯器中導入靜態訊息大小強制執行機制,確保「編譯時間」絕不會超出管道限制;最違規的內容只要由 FIDL 通訊協定作者將想法移到方塊中即可。

但是,一次強制啟用靜態訊息大小可能會破壞現有程式碼,並阻礙遷移工作。

我們建議按照下列步驟解決這個問題:

  • 一開始,在寬容模式中啟用靜態郵件大小檢查功能。
    • FIDL 編譯器應檢查訊息大小,並在管道限制可能超過時發出警告。建議 FIDL 通訊協定作者開始改用方塊。
  • 繼續執行遷移作業。
  • 完成後,請在強制執行模式中啟用靜態訊息大小檢查功能。
    • FIDL 編譯器應檢查訊息大小,並在管道限制可能超過時發出錯誤。暫停合輯。

效能

(章節不完整)。

安全性

透過將現有的臨時機制替換為 FIDL 語言繫結支援的官方解決方案,就有機會改善整體安全性層面。

例如,FIDL 語言繫結可在嘗試存取其內容前,確保含有裝箱資料的 VMO 只有單一擁有者。這樣做可以解決常見的共用記憶體威脅,例如:

  • VMO 提供者會在用戶端存取資料時修改資料。
  • VMO 提供者會在用戶端存取 VMO 時變更其大小,或引出用戶端來分頁錯誤。

相反地,導入這項功能可能會增加大量訊息的使用率,進而增加其他威脅的可能性,例如:

  • VMO 供應商傳送大量回覆給用戶端,導致用戶端在取消序列化時分配大量堆積。

測試

(章節不完整)。

缺點、替代方案和未知

(章節不完整)。

既有圖片與參考資料

(章節不完整)。

編輯者註意事項:拒絕了「RFC-0062:不可能的方法」,其中提出了可能超過通訊協定限制的所有方法。由於靜態分析的限制,這會造成太多限制。這種分析方式可避免擷取執行階段行為來正確分頁訊息,或手動將訊息「裝箱」。



  1. 就假設而言,FIDL 可經由其他管道傳輸,而拳擊手的本質可能會不同。不過,實作方式不在本提案的討論範圍內。 

  2. 編輯者註意事項:由於這個 RFC 於 2018 年編寫而成,因此值類型和資源之間的差異正式成為 FIDL 語言的一部分,請參閱 RFC-0057