RFC-0099:引入 `zx_socket_set_disposition` | |
---|---|
状态 | 已接受 |
区域 |
|
说明 | 引入了 `zx_socket_set_disposition`,以便使用可逆操作替换 `zx_socket_shutdown`。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2021-05-06 |
审核日期(年-月-日) | 2021-06-03 |
摘要
引入了 zx_socket_set_disposition
来替换 zx_socket_shutdown
。新系统调用通过允许撤消关闭操作来扩展旧系统调用。
引入 ZX_RIGHT_MANAGE_SOCKET
,并在新系统调用中对其进行要求。通过 zx_socket_create
新铸造的句柄将具有此权限。
设计初衷
将关闭替换为可逆操作的动机
我们在 fdio 中提供了一个精心设计的状态机,以应对未连接的流网络套接字不应接受写入这一事实。状态机具有本地状态(难以传播到其他进程中的复制套接字)和远程状态(Zircon 套接字上的用户信号),用于驱动本地状态。这些复杂的操作是必要的,因为套接字是“打开”状态创建的,因此必须通过外部方式阻止对它们进行 I/O,直到它们变为“已连接”(也通过外部方式)。
要求新权限的动机
Zircon 套接字关闭目前过于宽松。由于 zircon 套接字句柄可以克隆(实际上也确实如此),因此具有写入权限的单个句柄可以更改所有句柄的套接字状态。允许按此处所述的方式撤消关闭操作会使此问题更加严重。
综合应用
将套接字关闭替换为可逆操作,同时禁止非特权句柄启动它,这样网络堆栈实现就可以完全驱动套接字状态。
在将套接字出售给客户端之前,可以先将其关闭,这样就无需在 fdio 中进行上述状态跟踪。
套接字关闭可以由网络堆栈完全协调,由客户端 FIDL 调用发起,从而消除目前存在的竞态条件(例如 https://fxbug.dev/42140031)。
设计
在 FIDL 中定义 ZX_RIGHT_MANAGE_SOCKET
:
扩展 bits rights
:
library zx;
bits rights : uint32 {
MANAGE_SOCKET = 0x00100000;
};
在 rights.md 中记录 ZX_RIGHT_MANAGE_SOCKET
:
附加到表:
右 | 授予的权限 |
---|---|
ZX_RIGHT_MANAGE_SOCKET | 允许通过 zx_socket_set_disposition 更改套接字处理方式 |
在 FIDL 中定义 zx_socket_set_disposition
添加到 protocol socket
:
library zx;
protocol socket {
/// Set disposition of writes.
socket_set_disposition(handle:<SOCKET, rights.MANAGE_SOCKET> handle, uint32 disposition, uint32 disposition_peer) -> (status status);
}
/reference/syscalls/socket_set_disposition.md
中的文档 zx_socket_set_disposition
说明
zx_socket_set_disposition
会为套接字句柄及其对等体设置 zx_socket_write
调用的处理方式。
可使用的有效处置标志:
ZX_SOCKET_DISPOSITION_WRITE_DISABLED - 为指定的套接字端点停用写入。设置后,对指定套接字端点的写入将失败并返回 ZX_ERR_BAD_STATE。从指定套接字端点读取将会成功,直到指定套接字端点中缓冲的所有数据都被使用完毕,之后将会失败并返回 ZX_ERR_BAD_STATE。
ZX_SOCKET_DISPOSITION_WRITE_ENABLED - 为指定的套接字端点启用写入。设置后,对指定套接字端点的写入和读取操作将分别按 zx_socket_write
和 zx_socket_read
中所述的方式运行。
对包含缓冲数据的套接字端点指定 ZX_SOCKET_DISPOSITION_WRITE_ENABLED 是无效的;这样做会导致 zx_socket_set_disposition
返回 ZX_ERR_BAD_STATE,并且不会执行任何操作。
在 disposition 或 disposition_peer 中同时指定 ZX_SOCKET_DISPOSITION_WRITE_DISABLED 和 ZX_SOCKET_DISPOSITION_WRITE_ENABLED 是无效的;这样做会导致 zx_socket_set_disposition
返回 ZX_ERR_INVALID_ARGS,并且不会执行任何操作。
返回值
zx_socket_set_disposition()
在成功时返回 ZX_OK。
错误
ZX_ERR_BAD_HANDLE handle 不是有效的句柄。
ZX_ERR_BAD_STATE disposition 或 disposition_peer 包含 ZX_SOCKET_DISPOSITION_WRITE_ENABLED,并且 handle 是指在指定套接字端点上具有缓冲数据的套接字。
ZX_ERR_WRONG_TYPE handle 不是套接字句柄。
ZX_ERR_ACCESS_DENIED handle 不具有 ZX_RIGHT_MANAGE_SOCKET。
ZX_ERR_INVALID_ARGS disposition 或 disposition_peer 包含上述标志以外的标志,或标志组合无效。
Migration
实现后,现有的 zx_socket_shutdown
用法将替换为对 zx_socket_set_disposition
的等效调用。必要的 ABI 转换完成后,zx_socket_shutdown
及其关联的选项将被移除。
实现
实现应该完全在套接字调度程序内完成。
性能
这项更改对性能没有实质性影响。
工效学设计
这项更改对人体工学没有实质性影响。
向后兼容性
此更改向后兼容,因为不使用新 API Surface 的客户端不受影响。
安全注意事项
此更改可简化 fdio 代码,从而提高安全性。除此之外,这项更改对安全性没有实质性影响。
隐私注意事项
这项变更对隐私权没有实质性影响。
测试
此功能将使用系统调用的单元测试进行测试,并通过将已测试的 fdio 状态机的部分内容替换为新机器来进行测试。
文档
zx_socket_write
和 zx_socket_read
将更新为引用 zx_socket_set_disposition
,而不是 zx_socket_shutdown
。
其他文档将按照实现部分中所述的方式进行更新。
缺点、替代方案和未知情况
可以向 zx_socket_shutdown
添加一个新标志,而不是新的系统调用,以允许其行为发生反转。这种方法的好处在于,避免引入与行为明显不匹配的新术语(处置)。继续使用 zx_socket_shutdown
的主要缺点是,它接受的标志不直观;ZX_SOCKET_SHUTDOWN_READ
的行为与其说明不符(它禁止对等写入,而不是禁止读取)。
如果套接字中的指定方向存在数据,则“unshutdown”的行为被指定为会产生错误。另一种选择是允许该操作成功;我们选择更严格的选项,以防止意外后果。
您可以使用现有权限,而无需创建新权限。对现有权利的调查表明,没有现有权利与此使用情形相符。
仅此设计并不能完全解决流式套接字的状态传播问题。与此提案的替代方案是一种更全面的方法,旨在完全消除 fdio 流套接字状态机。此类提案也必须包含此提案。
在先技术和参考文档
流套接字语义实际上是由其在其他操作系统中的行为定义的,因此需要区分已连接的套接字与未连接的套接字。