RFC-0149:不需要 FIDL 編碼驗證

RFC-0149:FIDL 編碼驗證並非必要
狀態已接受
區域
  • FIDL
說明

不再需要在 FIDL 編碼期間進行驗證。不過,驗證仍會在解碼期間進行,且填充值在編碼期間必須設為零。

Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2021-11-19
審查日期 (年-月-日)2022-01-22

摘要

不再需要在 FIDL 編碼期間進行驗證。不過,驗證仍會在解碼期間進行,且填充資料在編碼期間必須設為零。

提振精神

這項 RFC 的動機在於放寬設計限制,目前規定繫結必須在編碼期間驗證。這並不表示繫結一定會變更行為,只是表示繫結的限制較少。事實上,在大多數情況下,這些項目不太可能因本 RFC 而有所變更。

不過,我們不再強制要求在編碼期間進行驗證,原因如下:

  • 在編碼期間,驗證會產生額外的額外負載。舉例來說,如果結構體中包含需要驗證的列舉欄位,就無法使用許多繫結中的 memcpy,因為結構體編碼有快速路徑,可將其縮減為 memcpy。對於 HLCPP 繫結而言,效能影響特別顯著,因為這會兩次檢查要編碼的物件,一次是進行編碼,另一次是進行驗證 (不過,這可以透過重新設計繫結來避免)。

  • 程式碼大小:驗證邏輯會增加程式碼大小。對於產生程式碼或使用巨集的繫結,這個程式碼大小增加幅度最為顯著,因為驗證邏輯會在輸出內容中重複多次。

相關人員

導師:pascallouis

審查者:pascallouis、yifeit、mkember

諮詢:

azaslavsky

社會化:

本 RFC 已在 FEC 討論郵寄清單上發布。

設計

  • 繫結可能會在編碼期間驗證 FIDL 物件,也可能不會。更精確地說,系統不再要求以保證物件在解碼期間一律通過驗證的方式進行編碼。

  • 繫結項目必須確保填充位元組在編碼後會歸零。不過,編碼器本身不必將填充值設為零,例如,可透過程式設計語言的保證將其設為零。

  • 繫結必須在解碼期間驗證 FIDL 物件。

實作

這個 RFC 沒有立即可交付的成果,因為目前的繫結會驗證 FIDL 物件,且可能會繼續這樣做。不過,日後的繫結將可放寬驗證檢查。

成效

效能效果取決於使用情境和綁定方式。以下列舉驗證對效能造成的部分影響:

  • 在 Rust 中,如果結構體包含 15 個 uint8 和 1 個布林值,在進行布林值驗證時,編碼速度會比不驗證時慢 3.2 倍 (52 毫秒)。如果結構體包含 254 個 uint8 和 1 個布林值,速度會變慢 21 倍 (844 毫秒)。不過,在 LLCPP 中,相同結構的效能成本微乎其微。我們選擇這個測試案例,是因為在許多繫結中,結構體、陣列或向量主體中的單一布林值或枚舉會防止 memcpy 最佳化。

  • 在 LLCPP 中,256 個列舉的陣列編碼速度比 Rust 慢 2.2 倍 (2.6us),在 Rust 中比 Go 慢 1.2 倍 (192ns),在 Go 中比 Go 慢 9 倍 (1.1us)。

  • 驗證後,HLCPP 物件的編碼速度會變慢 1 到 5 倍。16 個元素的表格編碼速度比 400ns 慢 1.7 倍,而訊息標頭的編碼速度則比 37ns 慢 1.3 倍。

這些測量值來自搭載 Intel Core i5-7300U CPU @ 2.60GHz 的機器。請注意,這些是微型基準測試,實際效能可能有所不同。

用於這些基準測試的 CL:

人體工學

這應該不會影響繫結的人體工學。不過,如果繫結在編碼期間停用驗證功能,則在某些可能影響使用者的失敗模式下,就不會再「快速失敗」。

回溯相容性

這項變更不會影響回溯相容性。

安全性考量

填充位元組一向會歸零而非驗證,未來也會繼續歸零。這一點很重要,因為 FIDL 物件可在舊的配置上分配,如果記憶體複製到線路上,就會導致記憶體外洩。對於大多數其他類型的驗證,資料外洩的風險較低。

系統會執行兩種主要驗證類別。

值限制

  • 布林值、列舉、位元:驗證可確保這些類型的支援整數位於預期範圍內。

  • 浮點 - 浮點驗證目前並非規格規定的一部分,但繫結可能仍會執行一些驗證,特別是為了避免 NaN 值。

  • UTF-8:FIDL 字串是載荷中含有 UTF-8 資料的向量。驗證可確保這些字串為 UTF-8。

這類型別的欄位通常是由使用者透過繫結 API 指派。驗證可確保使用者透過 API 提供有效的輸入內容,且不會有其他形式的意外錯誤 (例如記憶體毀損) 變更值。請注意,記憶體毀損錯誤可能會發生在處理物件的任何階段,因此期待透過布林值驗證等方式偵測到這類錯誤,有點不切實際。

  • 大小限制:某些物件 (例如表格) 的大小有限制。

傳輸程序必須遵守特定大小限制,例如管道傳輸的 64k 訊息大小限制,以免訊息大小無限擴大。因此,一般來說,這並非在到達解碼器前需要立即處理的問題。

州/省錯誤

  • 非選填類型視為選填 - 基本上是缺少酬載的非選填類型。

  • 信封內嵌位元組:信封含有欄位,可指出是否應將資料內嵌儲存。封套的大小可能小於或等於 4 個位元組,且應內嵌儲存,但缺少內嵌位元標記。

  • 向量不存在,但計數非零:編碼期間不應發生這種情況。

在遇到解碼器之前,這些都不會造成重大負面影響。這些問題也可能為 FIDL 實作中的內部問題,可透過其他方式保證其正確性。

結語

雖然需要考量安全性疑慮,但一般來說,這些問題通常會在解碼端而非編碼端發生,因為解碼端發生資訊外洩的風險較低。

隱私權注意事項

不會影響隱私權。

測試

這項 RFC 通常會降低測試需求。

說明文件

因此,我們需要更新 FIDL 繫結規格。

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

限制越多,彈性就越低。就驗證而言,更多限制可帶來相對的安全性優勢,而彈性則可改善效能和程式碼大小。這份 RFC 指出,安全性效益並不明顯,因此 FIDL 應考慮移除這項規定。

移除這項規定後,繫結會提供保留或移除現有編碼端驗證的選項。實際上,繫結應盡可能移除這項驗證,但某些繫結可能會繼續在偵錯模式中進行驗證,以便提早找出問題。

既有技術與參考資料