RFC-0028:處理權利 | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 在 FIDL 中註解必要或排除的句柄權利。 |
作者 | |
提交日期 (年-月-日) | 2019-04-01 |
審查日期 (年-月-日) | 2019-04-18 |
「The Right Stuff」
摘要
在 FIDL 中註解必要或排除的句柄權利,具體如下:
提供機制,可針對所有已分類的句柄類型 (例如
Protocol
、request<Protocol>
、handle
) 說明權利在序列化時,強制執行權限篩選功能,也就是說,權限的說明會決定遮罩,而遮罩會指出必須具備的權限組合。
在反序列化時,強制執行權限驗證,並提供一組權限。
提振精神
權限處理程序是用於在 Fuchsia 中減弱權限的工具。在這個 FTP 之前,FIDL 無法描述句柄權利。目前,有幾個地方會將此說明納入方法的註解,以便對代管程式權限設下重要限制或規定。
建議的權利限制範例包括只讀 IPC 或 VMO 句柄,以及不可執行的 VMO 句柄。
建議的權限需求範例包括可寫入的 IPC 句柄。
設計
權利限制
這項提案會在 FIDL 中新增一種限制類型:權利註解。這項功能可套用至 FIDL 資料結構和方法參數中的所有句柄類型:句柄、通訊協定和通訊協定要求。
權利限制可在類型句柄宣告中指定:handle<*subtype*, *RC*>
。權限只能在特定句柄子類型的情況下使用,因此無法在一般句柄上指定。如果在句柄宣告中未指定權限限制,權限將會以相同的權限轉寄 (不會變更現有行為)。
範例:
handle<vmo, zx.rights.READ | zx.rights.WRITE>
必須具備讀取和寫入權限,傳送至用戶端時會移除其他權限
handle<vmo>
未指定權利,轉寄現有權利
每個權利限制條件都必須指定至少一個權利 (例如 handle<vmo, >
是非法的)。
您無法為伺服器和用戶端通訊協定端點 (myprotocol
和 request<myprotocol>
) 指定權限限制。這些端點一律會具有權限 zx.TRANSFER | zx.WAIT | zx.INSPECT | zx.WRITE | zx.READ | zx.SIGNAL | zx.SIGNAL_PEER
,且子類型設為管道。如果需要自訂權利 (例如不可移動的通訊協定),可以使用 handle<*channel*, *RRC, ORC*>
。(這可能會透過使用範本進一步精進,並會在日後的 FTP 中討論)。
權限限制必須遵循「預設拒絕」政策。必須明確列出所有權利。
語法
處理權限限制是位元型運算式,可透過位元運算子指定。在上述範例中,|
是位元 OR 運算子。此語法是通用的,也適用於 FIDL 語言中其他地方的位元型值。在 zx 程式庫中,會有一個位元定義 zx.rights,其中包含所有權利。
雖然重複使用 zx.rights.[*right*]
的權利規格冗長,但有提案建議在日後的 FTP 中縮短 zx.rights.[*right*]
,因此這項提案已超出本 FTP 的範圍。
繫結
繫結必須透過摧毀訊息並使用 ZX_ERR_ACCESS_DENIED
關閉管道,回應接收和反序列化具有錯誤必要權限的句柄。
繫結項目必須回應繫結項目序列化作業,並使用錯誤的必要權限,藉此拒絕序列化、銷毀訊息,並禁止傳送。繫結項目也必須使用 ZX_ERR_BAD_STATE
關閉管道。
預設值
處理權限不會有預設值。原因如下:
預設值的行為不明確,可能會因物件類型而異。使用者無法瞭解特定物件的預設權利。
預設值不鼓勵使用精細的句柄權利,因為在編寫 FIDL 定義時,很容易不考慮權利。
如果有預設值,對於許多物件類型而言,最合適的候選值應為「無權限」或「最大權限」。設定最大權限預設值會限制此 FTP 中變更的有效性,但不設定權限預設值會導致與沒有預設值相同的效果。這兩種方法都沒有太大幫助。
重複使用句柄宣告
沒有預設值的後果是,指定權利可能會冗長。為了改善這個問題,您可以使用別名功能 (即「using」關鍵字) 為整個句柄宣告命名。
using readable_vmo = handle<vmo, zx.READ>
另一種做法是允許權利限制使用別名 (例如 zx.READ | zx.WRITE
的「io
」別名),但這會提供一層間接方式來隱藏權利,尤其是在權利廣泛使用時。允許在物件層級使用別名,可將用途限制在類型相同的位置。
可參數化
我們希望建立包含可設定參數的權限限制管道的一般訊息。
舉例來說,請考慮 fuchsia.mem.Buffer
,它會保留 handle<vmo>
。您應該可以說 fuchsia.mem.Buffer:C
,其中限制 C
會流向限制 handle<vmo>
。
這裡的起點是泛型類型別名,而範本的引入將進一步滿足這項需求。雖然這不在本提案的範圍內,但在相關工作中必須考量這項要求。
導入策略
接收訊息時,應依賴 zx_channel_read_etc
系統呼叫,以便在呼叫時提供權利資訊。綁定會使用權利資訊,驗證是否具備必要權利,並篩除所有超出必要權利的額外權利。
傳送訊息時應依賴 zx_channel_write_etc
,這樣系統就能將傳送的權限減少至指定的權限集,並驗證是否具備所有必要權限,如果驗證失敗,則會傳回 ACCESS_DENIED
。繫結會在收到此回應後負責關閉管道。為了符合現有行為,系統會在這個系統呼叫中使用 ZX_HANDLE_OP_MOVE
,這等同於先呼叫 zx_handle_replace
,再呼叫 zx_channel_write
。如果未指定權利,系統會使用 ZX_RIGHT_SAME_RIGHTS
取代權利。
我們正在著手實作說明文件,以便詳細說明實作方式。
人體工學
長期來說,這項功能可改善人體工學。權利文件和檢查作業會以標準方式在 FIDL 中執行,而非使用臨時註解和檢查。
說明文件和範例
這項變更會影響以下說明文件:
Kernel 權限說明文件:如何指定權限
回溯相容性
ABI 相容性
權利變更不得破壞 ABI 相容性。
來源相容性
權利變更可能會導致來源相容性中斷。不過,破壞來源相容性是意料之外的情況,如果繫結作者選擇這條路徑,則應明確記錄。
新增必要權利
在訊息接收端,如果有額外的必要權限,則可回溯相容,因為這只會提供更多能力。不過,在訊息傳送端,新增必要權限是回溯不相容的變更,因為現在必須先具備權限才能傳送。
移除必要權利
在傳送端,移除必要權利的做法是回溯相容的,但在接收端則是回溯不相容的。收件者現在不會收到預期的權利。
新增選用權利
新增選用權利時,系統會回溯相容。
移除選用權
在傳送端移除選用權利時,這項功能可回溯相容,但在收件端則不相容。收件者現在不會收到先前可能已收到的權利。
環境假設
可能會出現環境假設,認為部署此模型會中斷。舉例來說,即使伺服器不打算提供這項保證,用戶端仍可能假設透過連線收到的所有 VMOs 皆可對應。
這項狀態可視為這項 FTP 的全部動機:移除這項普遍存在且隱含的契約。
成效
微型基準測試顯示 zx_channel_write_etc
和 zx_channel_read_etc
的效能相去不遠。對於含有 1 個句柄的 64 位元訊息,zx_channel_write
/zx_channel_read
耗時 962 毫秒,zx_channel_write_etc
/zx_channel_read_etc
則耗時 1000 毫秒。
讀取或寫入句柄時所需的句柄陣列,將從 256 位元組 (ZX_CHANNEL_MAX_MSG_HANDLES * sizeof(zx_handle_t))
增加至 1,024 位元組 (ZX_CHANNEL_MAX_MSG_HANDLES * sizeof(zx_handle_info_t))
。同樣地,在寫入句柄時分配的堆疊陣列會從 256 個位元組增加到 1280 個位元組 (ZX_CHANNEL_MAX_MSG_HANDLES * sizeof(zx_handle_disposition))
。
為了讓堆疊配置保持在 256 個位元組的最大值,如果句柄表太大 (讀取時超過 16 個句柄,或寫入時超過 12 個句柄),我們就需要使用堆積分配句柄表。為因應這項異動,我們將檢視訊息大小和句柄資料表的堆疊配置需求 (目前只考量訊息大小)。
安全性
這是一項安全性強化功能。這可讓我們更準確地稽核 API 途徑。它會將權限檢查作業移至繫結,這比在所有呼叫網址中進行相同的檢查作業更容易審查。
舉例來說,一旦權利完全用盡,您就能輕鬆稽核所有可執行 VMOs 的擁有權轉移位置。這在今天很難實現。
測試
每個繫結實作項目都應進行單元測試。
這項功能的推出也應確保,針對這項功能進行修改的 FIDL 通訊協定實作項目,能夠測試新功能。
缺點、替代方案和未知事項
缺點:公用 API 會變得冗長
從某種意義來說,這項功能是「雜訊」。在系統的一般執行情況下,可能不會採用缺少權限的路徑。但仍會佔用公開系統 API 的空間。
我們認為這項成本值得付出,因為這樣可以確保明確度和精確度,而且妥善使用別名就能滿足大部分需求。
舉例來說,以下兩種問題可以避免或減少:
因權利不相容而導致遠端中斷:失敗可能發生在離來源很遠的地方 (如果又將句柄轉移,甚至可能發生在其他程序的下游)。
未記錄的假設會導致相容性問題:部分用戶端/伺服器可能會傳遞權限過多的句柄,導致同儕假設他們可以依賴這些權限,進而導致相容性問題 (如果這些假設證明有誤)。
我們瞭解必須逐字列出權利的做法令人不悅,但這與能力類型資訊相同。
替代做法:權利的下限和上限
初始設計會針對權限的下限和上限呼叫 (例如「沒有可執行權」或「有可寫權」)。從安全性角度來看,Fuchsia 應採用「預設拒絕」政策,適用於所有功能 (和權限)。
因此,如果某項能力 (或權限) 未在任何地方明確提及,則不應授予該功能。元件資訊清單已針對沙箱環境採取這種做法,理想情況下,FIDL API 也應如此。
我們可能還想額外允許明確表達「選用權利」,也就是可能提供或不提供的權利。
因此,從限制語法角度 (也就是使用者在編寫 Fidl API 時輸入的內容) 來看,我們會傾向列出權利,並將部分權利標示為選用。
請注意,從限制語意學的角度來看,也就是需要在 JSON IR 中表示並透過繫結實作內容,這個語法變更會繼續表示下限和上限檢查。
強制來源相容性
在 Fuchsia 中,權利通常會以 uint32
表示,且權利的值隨時可能會變更。因此,我們認為 FIDL 中的權利值變更不會對產生的原始碼造成實質性的變化,這似乎是合理的。不過,有些用途可能會破壞來源相容性,例如在存在特定權限 (在本例中為 zx.rights.WRITE
) 時產生特定方法 (例如 write())。因此,我們並未規定權限變更不會破壞來源相容性。