本页逐步介绍了 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 时,会发生什么情况?
图表
在此场景中,客户端充当发送者,服务器充当接收者。我们在下文中使用了这些术语,因为这对于转移标识名至关重要。如果该方法返回了一个句柄,则会应用相同的步骤,但角色会反转。
如需详细了解此图表,请参阅下文。
说明
用户代码(发送者)
- 假设发送者使用
zx_vmo_create系统调用获取 VMO。返回的句柄h1具有 VMO 的默认权限:DUPLICATE、TRANSFER、READ、WRITE、MAP、GET_PROPERTY和SET_PROPERTY。 - 调用
Method,并向其传递h1。
- 假设发送者使用
FIDL 绑定(发送方)
将
h1封装在 handle disposition 中,指定 FIDL 类型中的权限:MAP、READ和WRITE。这会告知内核在转移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系统调用(或类似调用)。
内核
- 确保
h1存在于发送方进程的句柄表中。 - 确保
h1指的是 VMO。 - 确保
h1至少拥有MAP、READ和WRITE权限。 - 将权限限制为仅包含
MAP、READ和WRITE,移除权限DUPLICATE、TRANSFER、GET_PROPERTY和SET_PROPERTY。 我们将此受限句柄称为h2。这相当于调用zx_handle_replace系统调用。 - 使用
h2而不是h1将消息加入队列。
- 确保
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 类型获取预期类型和权限:
MAP和READ。确保
h2拥有(至少)这些权利。由于
h2具有意外的权限WRITE,因此调用zx_handle_replace系统调用来获取仅具有权限MAP和READ的新句柄h3。
- 调用
用户代码(接收方)
- 使用
h实参(即h3)的服务Method。
- 使用