RFC-0137:捨棄 FIDL 中的未知資料

RFC-0137:捨棄 FIDL 中的不明資料
狀態已接受
領域
  • FIDL
說明

設定 FIDL 繫結會捨棄未知的資料,而不是保留資料並進行 Proxy 處理。

問題
毛皮變化
作者
審查人員
提交日期 (年-月-日)2021-08-25
審查日期 (年-月-日)2021-10-13

摘要

大部分的 FIDL 繫結會保留未知的資料表欄位與聯集變體, 使用者程式碼,檢查並重新編碼原始位元組,並處理。這項行為 這會造成安全性和隱私權風險,導致 FIDL 變得更為複雜, 傳輸格式難以遷移,且無法在所有繫結中執行。三 建議讓繫結捨棄未知的資料,導致 如表 1 所示。

表 1:含有未知資料的彈性類型變更

類型 是否可存取不明資訊? 可以重新編碼嗎? Proxy 不明?
位元 可轉移
列舉 可轉移
桌子 是 → 是 →
聯集 是 → 僅限 Ordinal 是 → 是 →

背景

彈性型別是 FIDL 中用來編寫進化 API 的重要功能。 引入於 RFC-0033:處理未知欄位和嚴格程度中。 但自 2020 年底開始在所有繫結中都可供使用。透過彈性類型 因此解碼器就會成功FIDL 資料表一律為 彈性,而位元、列舉和聯集則可標示為嚴格或彈性。 使用彈性位元和列舉時,未知值只是整數。不過 如果是未知的資料表欄位或聯集變數,該值會包含原始位元組 和帳號代碼,也就是我們所謂的不明資料

現今大多數的繫結都會「保留」網域物件中的不明資料。例外狀況 是 LLCPP,因為其設計限制可能會導致此項問題難以支援。對於 其他,保留未知資料會導致下列行為。假設 程序 A、B 和 C 透過 FIDL 通訊。如果 A 和 C 知道新資料表 欄位 B 沒有,且該欄位從 A 傳送到 B,那麼 C 就會 儘管 B 無從接收並瞭解它。也就是 B Proxy,以收集不明資料。應用程式也可以解讀未知的資料 根據結構定義的假設 其中前 4 個位元組 一律都會做為 ID。不過,這類情況會持續存在,並經過更妥善的模擬 都直接整合為 FIDL 類型Proxy 是唯一能夠實際保留資料的 未知的資料。

提振精神

設計 FIDL 時,我們致力於透過Fewest 使用解決真正的問題 功能保存未知資料的功能尚未發展 這些原則自從導入這個做法以來 紫外線一直造成麻煩, 便考量其他 FIDL 的工作。

這也讓我們質疑我們對未知資料的代理關係。好主意 一開始就做出決定但我們認為至少不會將其設為預設值 行為對於 FIDL 伺服器 主要是 Proxy不過,比起使用 FIDL 專屬的 Proxy 支援,這將涵蓋 而非只有未知的資料

即使我們假設預設 Proxy 是可行的, 將 FIDL 網域物件直接重新編碼。不過,還是很常見的情況 ( 建議),將這些物件轉換為功能更豐富的應用程式專屬類型 再進行後續處理這種做法只不過是評估 會需要在未修改的情況下傳送編碼訊息,或 以最少的處理速度,直接重新編碼已解碼的訊息舉例來說, Rust Crate fidl_table_validation 可在轉換 FIDL 網域物件放入應用程式網域物件中。因此,當對等節點 複雜系統中多個躍點的資料表無法依賴所有欄位 如果任何參與者使用這個模式,就會到達最終目的地。

無論是否使用 Proxy,保護未知資料都有幾個 這會讓電匯格式更困難。在遷移期間 所有同儕都能同時閱讀新舊格式 建議您開始編寫新格式由於無法進行這項變更 但難免會遇到同儕互傳訊息的狀況 接收舊格式與新格式的訊息。假設接收的 而且每個資料表中都有未知的資料表欄位,接著嘗試以 單一訊息。此時,保留不明資料的唯一方法就是加入 每個信封的傳輸格式中繼資料,但這違反了規定 複雜程度和負擔

另一個負面疑慮是 FIDL 繫結之間的功能對等性。在符合下列條件的繫結中 支援就地解碼功能 (例如 LLCPP),難以選擇網域 物件表示法,可同時擁有控點,且代表未知的控點。 針對已知資料,解碼器會透過覆寫 狀態指標。如果是未知資料,解碼器只會知道 在帳號代碼表中略過的控點,而非其所在位置 指標因此,您無法傳回內含 會傳回網域物件和重新封裝的控制代碼。而是 繫結功能則不支援保存未知的資料。這很可能會 避免在其他繫結中使用這類資料,提高測試效率 減輕負擔;需要對所有涉及不明資料的情況執行兩項 GIDL 測試。

一般而言,保留未知資料的需求會導致 FIDL。簡化作業不僅不受導入作業影響,也會影響使用者 這一點會因與其他功能互動 而獲得良好成效舉例來說 是為了影響 API 相容性而設計 而非 ABI。然而,他們後來發現無法避免 針對收到不明帳號代碼換取彈性值的情況,對 ABI 的影響 類型。這個極端案例只是因為要保留 網域物件中的不明資料

相關人員

誰會負責確認 RFC 是否已獲接受?(這個部分為選填,但 encouraged.)

講師:pascallouis@google.com

審查者:abarth@google.com、yifeit@google.com、ianloic@google.com

諮詢:bryanhenry@google.com

社交:此 RFC 的草稿已送交 FIDL 團隊以供審查。

設計

針對彈性位元和列舉,對未知值的處理方式維持不變。

解碼資料表和彈性聯集時:

  • 繫結「不得」儲存未知的位元組,並「不得」在網域物件中處理,除非 這些繫結專為 Proxy 設計

  • 繫結「必須」關閉所有未知的控點。

重新編碼先前解碼的資料表和彈性聯集時:

  • 繫結「必須」能成功重新編碼資料表的已知欄位,且不得 包括未知的欄位 (可能代表儲存欄位)。

  • 使用含有 未知的變化版本。

為資料表和彈性聯集考量領域物件:

  • 繫結「不得」提供任何機制來區分沒有不存在的資料表 資料表中已捨棄不明欄位。 如果繫結提供深度相等函式,則會視為相等。

  • 繫結「必須」提供機制,以判斷彈性聯集是否具有 未知的變體,且「應該」提供存取未知序數 (即 網域物件的未知變數只能儲存序數)。未知 如果繫結提供深等相等函式,應行為與 NaN 類似。 比較不等

在 Rust 中,後者表示從彈性聯集中移除 Eq 特徵 和遞移包含 1 的型別和處理浮點值一樣。

實作

執行主要是刪除負責 會保留所有繫結中的未知數。我們認為 並在實際工作環境中使用未知的資料存取子如果有,我們必須 瞭解用途並嘗試找出更有效的方法

目前,LLPP 無法將含有不明欄位的資料表重新編碼。這將 必須根據設計進行變更,才能成功只對已知欄位進行編碼。

安全性考量

本提案旨在提升安全性,因為此提案能減少 功能。保存不明的資料時 可讓您輕鬆傳遞任意位元組,並透過不知情的元件處理。 捨棄時,資料界線會由 FIDL 正確編碼。 因此更易於稽核

隱私權注意事項

本提案可改善隱私權,因為這項限制會限制未知的傳輸作業 中可能包含機密資訊

測試

測試主要是在 GIDL 中發生。涉及不明資料的 success 測試會 可以分成兩個部分:decode_successencode_success (編碼) 只有已知資料表欄位) 或 encode_failure (聯集無法編碼)。 含有未知資料的值表示法也會改變GIDL 不應 更較長的剖析位元組和控制代碼,請改用 123: unknown 語法 (序數為 123 的不明信封)。

您可以移除分割 LLCPP 和非 LLCPP 的許可清單和拒絕清單。所有語言 繫結與不明屬性的編碼/解碼行為相同 資料。此外,在 fxrev.dev/428410 中新增的 LLCPP 特定單元測試可以 以便進行 GIDL 測試

測試時,應執行嚴格/彈性和價值/資源的所有組合 仍會保留,但透過控點為彈性值型別的控點解碼不明資料 也不會失敗

說明文件

必須更新下列文件:

缺點、替代方案和未知

替代做法:視需要保留未知

與其完全移除支援保留未知資料的支援,我們可以 而不只是預設支援舉例來說 具有 類型的屬性,也許只能用值類型來減輕 未知的處理序。不過,這個做法 變得簡單複雜,無法解決線路格式問題 遷移問題。

缺點:彈性類型不一致

此提案的缺點是,彈性類型的行為會更低。 可能較不符合直覺解釋這個概念 位元、列舉、資料表和聯集和兩個軸,如表 2 所示: 代數類型 (產品或總和) 與酬載 (無論是否包含酬載)。

表 2:彈性類型分類

產品類型 總和類型
沒有酬載 位元 列舉
具酬載功能 桌子 聯集

目前,所有彈性類型都會透過 Proxy 傳送未知的資訊。這個提案中斷 找出對稱的同義詞例如,請考慮以下 FIDL 類型:

// Product types (multiple fields set)
type Bits  = bits  {    A = 1;         B = 2; };
type Table = table { 1: a struct{}; 2: b struct{}; };

// Sum types (one variant selected)
type Enum  = enum  {    A = 1;         B = 2; };
type Union = union { 1: a struct{}; 2: b struct{}; };

首先,我們無法讓有效負載軸保持一致。目前來自Bits Table或從 EnumUnion會增加功能,允許 以便承載一個酬載有了本提案 和不再保有未知因素的成本

第二,我們失去了代數類型軸的一致性。目前兩者 TableUnion 允許在將含有不明資料的物件解碼後重新編碼, 透過這個提案,Table 可以重新編碼,但 Union 無法重新編碼。

我們認為,從抄襲的角度切入,勝過一致性,是不對的 「動機」中描述的複雜性。不過 下面說明其他維持一致性的設計。

替代做法:捨棄所有未知資訊

為提升一致性,我們可能會捨棄所有未知資訊,即使不明 輕鬆儲存。也就是說, 以及捨棄酬載之外的未知序數 。表 3 顯示產生的行為。

表 3:表 1 調整:捨棄所有未知資訊

類型 是否可存取不明資訊? 可以重新編碼嗎? Proxy 不明?
位元 是 → 是 →
列舉 是 → 是 → 是 →
桌子 是 → 是 →
聯集 是 → 是 → 是 →

替代做法:選用彈性聯集

為提高一致性,我們可能需要一律使用彈性聯集 這項指令,並將未知的變體解碼為無聯集。如此一來 重新編碼聯集,使其與資料表保持一致。表格 4 顯示產生的行為。

表 4:表 1 調整:選用彈性聯集

類型 是否可存取不明資訊? 可以重新編碼嗎? Proxy 不明?
位元 可轉移
列舉 可轉移
桌子 是 → 是 →
聯集 是 → 是 →

替代做法:記住是否已捨棄不明欄位

在建議的設計中,繫結使用者無法判斷是否不明 已捨棄 個欄位。另一種做法是 表格網域物件中的布林值或一組不明序數。使用者可 然後透過 has_unknown_fields() 等函式查詢。舉例來說 儲存空間服務可能會發生錯誤,以免遺失資料。

這個替代方案的缺點是會為資料表新增額外的隱藏狀態 網域物件它們不再是簡單的值類型,也就是欄位的總和。 舉例來說,它會提出問題,說明 == 運算子是否應 這類布林值旗標要納入考量

替代選項:重要欄位

檢查 had_unknown_fields() 的唯一實際用途,如所述 若傳回 true 則失敗。與其 在繫結中提供存取子,我們可接受資料表的屬性,並 彈性工會成員選擇採用該行為:

type Data = table {
  1: foo string;
  @important
  2: bar string;
};

這個屬性的作用是將 該欄位的信封標頭。當解碼器收到 就必須失敗也就是 @important 屬性不具前瞻相容性,運作原理類似動態版本 靜態 strict 修飾符的使用中,我們允許位元、列舉和聯集。

此方法可能需搭配自己的 RFC 來進行。

確認:此構想源自 yifeit@google.com。

替代做法:維持 ABI 對價值/資源的影響

本提案已消除 RFC-0057 的 ABI 影響。 認為這是捨棄未知資料而導致的改進。 但可以主張 ABI 是適當的影響,因此必須保留下來。

捨棄 ABI 影響的優點 (本提案):

  • 可提高嚴格/彈性和價值/資源方面的獨立功能。有 不再是特殊案例。考量到我們並不是 可能會注意到這個情況,直到其各的 RFC 報告的時間很久為止 導致使用者感到驚訝
  • 這麼做可讓類型更容易從值轉換為資源,因為只需要 無法執行在未出現程式碼中斷的情況下 (可能用於請求和 回應類型無法直接在某些繫結中參照),那麼這是一種 轉換也不會在不通知的情況下變更行為。

維持 ABI 影響力的優勢 (這個替代方案):

  • 可更準確模擬介面的意圖。如果您指定 您不會預期有帳號代碼 (透過值類型),而您會在 執行階段中,這指的是差距並失敗是很合適的做法。
  • 如果我們改變心意,日後可能會撤銷 ABI 的影響。從另一部裝置改用 Pixel 更有可能造成乾擾

既有藝術品和參考資料

普羅托巴夫

通訊協定緩衝區的設計來回溝通 點。在 proto2 中,系統會保留不明欄位並經由 Proxy 處理 (例如現今的 FIDL)。在 proto3 中,行為已變更為捨棄不明欄位 (如本提案所示)不過,結果後來被還原 因此,在 proto3 及更新版本 proto3 中,我們會再次保留不明欄位。

這會產生以下問題:如果我們接受這個做法,FIDL 將遵循相同的途徑 提案?我們認為答案是否,因為 FIDL 和 Protobuf 不同的設計空間Protobuf 必須還原為舊的保留行為 主要是因為兩個用途:中介伺服器和讀取-修改-寫入模式 這些都在富赫西亞都不盛行。沒有中介 Proxy 因此 Fuchsia 的安全性和隱私權原則 非常適用於內部微服務通訊FIDL API 評分量表而非讀取-修改-寫入模式 建議採用部分更新模式

Thrift

Apache Thrift 捨棄不明欄位