本页逐步说明 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
封装在句柄处置中,以指定来自 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
。
- 使用