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 包裝在 handle disposition 中,指定 FIDL 型別的權限:MAPREADWRITE。這會告知核心在轉移 h1 時要提供哪些權利。繫結不知道 h1 實際擁有哪些權利。(他們也不確定是否參照 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 系統呼叫 (或類似項目)。

  3. 核心

    • 確認傳送端程序控點資料表中存在 h1
    • 確認 h1 參照 VMO。
    • 確認 h1 至少擁有 MAPREADWRITE 權利。
    • 將權利限制為僅包含 MAPREADWRITE,移除 DUPLICATETRANSFERGET_PROPERTYSET_PROPERTY 權利。我們將這個受限控制代碼稱為 h2。這相當於叫用 zx_handle_replace 系統呼叫。
    • 使用 h2 而非 h1 將訊息加入佇列。
  4. FIDL 繫結 (接收器)

    • 叫用 zx_channel_read_etc 系統呼叫 (或類似項目)。
    • 從傳回的控制代碼資訊中解除包裝 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