FIDL 中帳號代碼的生命週期

本頁面會逐步說明 FIDL 如何將 Zircon 控制代碼從一個程序轉移至另一個程序。特別是「處理權」的各種涵義,以及驗證權利的驗證方式。

情境

以透過下列通訊協定進行通訊的簡易用戶端和伺服器:

protocol LifeOfAHandle {
    Method(resource struct {
        h zx.Handle:<VMO, zx.Rights.MAP | zx.Rights.READ | zx.Rights.WRITE>;
    }) -> ();
};

假設我們從處理權限中移除 zx.Rights.WRITE,但只會重新編譯伺服器,而非用戶端。如果用戶端建立 VMO 並傳送至 Method,會發生什麼事?

圖表

在這個情況下,用戶端會是「傳送者」,而伺服器則是「接收端」。我們會使用以下字詞,因為這是轉移帳號代碼的目的。如果方法傳回控制代碼,則會將相同的步驟套用至角色相反。

如需圖表的詳細說明,請參閱下文

透過 FIDL 傳送帳號代碼的圖表

說明

  1. 使用者代碼 (寄件者)

    • 假設傳送者使用 zx_vmo_create 系統呼叫取得 VMO。傳回的控制代碼 h1 擁有 VMO 的預設權限:DUPLICATETRANSFERREADWRITEMAPGET_PROPERTYSET_PROPERTY
    • 呼叫 Method 並傳遞 h1
  2. FIDL 繫結 (傳送者)

    • h1 納入處理序中,以指定 FIDL 類型:MAPREADWRITE 的權利。這會告知核心在轉移 h1 時應提供什麼權利。繫結並不瞭解 h1 實際具有哪些權限。(他們不知道 VM 也會參照 VMO,但這點與平常不同,通常會以靜態類型系統表示,因此不小心傳遞錯誤的帳號代碼類型)。

      zx_handle_disposition{
          .operation = ZX_HANDLE_OP_MOVE,
          .handle = h1,
          .type = ZX_OBJ_TYPE_VMO,
          .rights = ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE,
      }
      
    • 叫用 zx_channel_write_etc Syscall 或類似系統。

  3. 核心

    • 確認寄件者程序的帳號代碼資料表中有 h1
    • 確保 h1 參照 VMO。
    • 確認h1 (至少) 擁有MAPREADWRITE的權利。
    • 限制僅納入 MAPREADWRITE,並移除 DUPLICATETRANSFERGET_PROPERTYSET_PROPERTY 等權限。我們稱這個受限帳號代碼為「h2」。這相當於叫用 zx_handle_replace 系統呼叫。
    • 使用 h2 (而非 h1) 將訊息排入佇列。
  4. FIDL 繫結 (接收端)

    • 叫用 zx_channel_read_etc Syscall 或類似系統。
    • 從傳回的帳號代碼資訊中解除 h2。與控制代碼配置不同,控制代碼會儲存核心回報的「實際」類型和權利。

      zx_handle_info{
          .handle = h2,
          .type = ZX_OBJ_TYPE_VMO,
          .rights = ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE,
      }
      
    • 取得 FIDL 類型預期的類型和權限:MAPREAD

    • 確認 h2 (至少) 具備這些權利。

    • 由於 h2 具有非預期的正確 WRITE,請叫用 zx_handle_replace 系統呼叫來取得僅具有 MAPREAD 的新控制代碼 h3

  5. 使用者代碼 (接收端)

    • 使用 h 引數 (即 h3) 的 Method 服務。