本页将逐步说明 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
系统调用来获取新标识名h3
,该标识名仅具有 权利MAP
和READ
。
- 调用
用户代码(接收方)
- 使用
h
参数(即h3
)服务Method
。
- 使用