RFC-0008:移除 zx_clock_get 和 zx_clock_adjust | |
---|---|
状态 | 已接受 |
区域 |
|
说明 | 定义了弃用 zx_clock_get 和 zx_clock_adjust 系统调用的计划,并将其移除。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2020-10-12 |
审核日期(年-月-日) | 2020-10-29 |
摘要
我们提出了五步流程来弃用 zx_clock_get
和 zx_clock_adjust
系统调用,将其余用户迁移到自 2019 年起推出的替代系统调用,最后移除原始系统调用。
设计初衷
Fuchsia 目前包含两组独立的系统调用来与时间进行交互:
- 原始设计使用
zx_clock_get
读取内核维护的单调时钟、UTC 时钟和线程时钟,并使用zx_clock_adjust
写入 UTC 时钟。这种设计没有提供任何用于调整时钟、在不同产品上定义其他时钟或传达时钟状态的方法。 - 2019 年,我们添加了
zx_clock_create
、zx_clock_read
、zx_clock_update
和zx_clock_get_details
系统调用,以便对时钟对象执行丰富的管理,让用户空间能够定义和维护任意数量的时钟。还添加了zx_clock_get_monotonic
来读取内核的单调时钟。
Fuchsia 目前定义了两个不同的 UTC 时钟:可使用 zx_clock_get
读取的内核 UTC 时钟,以及可使用 zx_clock_read
读取的用户空间 UTC 时钟。时间同步系统会尝试使这些时钟保持一致,但由于它们提供的功能不同,因此难免会出现一些差异。
此提案定义了原始时间系统调用的废弃计划,完成了自 2019 年添加替代系统调用设计期间开始的迁移。移除这些系统调用解决了维护两种半兼容的时间管理方式所带来的持续(且不断增加)的运营和认知成本。
实现
zx_clock_get
和 zx_clock_adjust
各接受一个 clock_id
参数,用于指定应使用三个可能时间轴中的哪一个。最好分别考虑这三个时间轴上的迁移:
ZX_CLOCK_MONOTONIC
- 对zx_clock_get(ZX_CLOCK_MONOTONIC)
的调用可以直接替换为对zx_clock_get_monotonic
的调用。这种替代系统调用更易于使用,并且通常可提供更好的性能。ZX_CLOCK_THREAD
- 对zx_clock_get(ZX_CLOCK_THREAD)
的调用可以替换为使用主题ZX_INFO_THREAD_STATS
对zx_object_get_info
的调用。这种替换提供了更高的灵活性,并且作为线程属性,与线程执行时间更契合。ZX_CLOCK_UTC
- 在 2019 年,系统调用 UTC 由 Fuchsia 平台在用户空间中管理,而不是直接由内核管理。大多数语言运行时已修改为读取用户空间 UTC 时钟,因此在大多数情况下,对zx_clock_get(ZX_CLOCK_UTC)
的调用应替换为语言运行时中的标准 UTC 调用。在必要时,可以使用zx_utc_reference_get
函数获取一个只读时钟句柄,以传递给zx_clock_read
。对zx_clock_adjust(ZX_CLOCK_UTC)
的调用可以替换为使用从fuchsia.time.Maintenance
获取的读写时钟句柄对zx_clock_update
的调用。
我们建议您按照以下五步流程移除 zx_clock_get
和 zx_clock_adjust
:
- 更新了文档,将系统调用标记为已废弃
- 将所有已知用户迁移到替代系统调用
- 停止维护内核 UTC 时钟并移除
zx_clock_adjust
- 从 SDK 中移除
zx_clock_get
声明 - 从 Zircon 中移除
zx_clock_get
实现
第 1 步 - 更新文档,将系统调用标记为已废弃
此步骤已完成。zx_clock_get
和 zx_clock_adjust
调用已明确标记为已废弃,并且文档中包含我们上面推荐的替代解决方案。
第 2 步 - 将所有已知用户迁移到替代系统调用
此步骤正在进行中。fxr/433865 最近将标准语言运行时 UTC 函数移到了用户空间 UTC 时钟。这已移除大多数 zx_clock_get
用法,但仍有大量来自不同代码库中各种不同调用点的长尾用法。
我们将在 Global Integration 中通过代码搜索来查找调用并使用 syscalls_zx_clock_get_type_*
kcounter 来跟踪进度,以消除 stem 和 petals 中的这些剩余用法。鉴于可用的资源以及将上游更改推送到下游代码库通常需要数周或数月的时间,这将是一个漫长的过程。
如果语言运行时为 zx_clock_get
或 zx_clock_adjust
提供了封装容器(例如 Rust 中的 fuchsia_zircon::Time::get
函数),我们会在没有客户端再使用该封装容器后移除每个封装容器。
第 3 步 - 停止维护内核 UTC 时钟并移除 zx_clock_adjust
如需在 ZX_CLOCK_UTC
中保持准确的时间,需要从驱动程序和多个测试组件调用 zx_clock_get
和 zx_clock_adjust
。在第 4 步之后,这些调用将无法再执行,因此我们不再将维护内核 UTC 作为单独的步骤。
在第 3 步中,我们将移除 ZX_CLOCK_UTC
同步,导致尝试读取 ZX_CLOCK_UTC
的所有客户端崩溃,并完全移除 zx_clock_adjust
系统调用(此系统调用仅用于设置 UTC,并且仅由少数特权客户端调用)。
完成第 2 步后,我们应该已经非常确信 Global Integration 中没有任何其他组件在使用 UTC,但通过在读取尝试时导致客户端崩溃,我们可以快速检测任何遗漏。
具体而言,我们将:
- 移除所有用于验证
ZX_CLOCK_UTC
的测试。 - 修改
zx_clock_get(ZX_CLOCK_UTC)
以将调用方标记为违反政策的用户。 - 从实时时钟驱动程序中移除对
zx_clock_adjust
的调用(并完全移除回退 RTC 驱动程序,因为这是其唯一用途) - 完全移除
zx_clock_adjust
。
第 4 步 - 从 SDK 中移除 zx_clock_get
声明
在第 3 步之后,我们可能已成功移除头文件中对 zx_clock_get
的所有调用,但仍需要支持依赖于 zx_clock_get
的旧版预构建二进制文件。在这种情况下,我们将移除 SDK 中的 zx_clock_get
声明,但不会移除 zircon 实现。在此阶段,任何尝试使用 zx_clock_get
编译代码的行为都会导致编译失败。
如果没有预构建二进制文件依赖于 zx_clock_get
,我们将直接跳转到第 5 步。
第 5 步 - 从 Zircon 中移除 zx_clock_get
实现
一旦没有预构建二进制文件依赖于 zx_clock_get
(由其符号导入决定),我们将完全移除 zx_clock_get
及其关联文档。
性能
此提案通过鼓励更广泛地使用更高效的 zx_clock_get_monotonic
系统调用并简化 RTC 驱动程序的操作,将使整体系统性能略有提升。
安全注意事项
此提案不会影响管理单调时间或线程时间的安全性。
在其他操作系统中,攻击者利用 UTC 管理漏洞执行了各种回滚攻击。此提案通过提供更精细的访问权限控制,提高了管理 UTC 时间的安全性。
使用 zx_clock_adjust
系统调用时,必须使用根资源更改 UTC 时间。这意味着,需要调整时间的组件还会获得强大的不相关功能,这意味着,无论是否需要此权限,具有根资源的任何组件都拥有修改 UTC 的权限。
此提案实施后,修改 UTC 的唯一方法是通过 fuchsia.utc.Maintenance
分发读写时钟句柄。此协议仅会明确路由到需要它的组件,并且这些组件不会通过此句柄获得任何其他功能。
隐私注意事项
在实施时,此提案不会影响隐私权。
此提案将支持将来移除 UTC 时间作为环境权威(进程可以在没有用户空间 UTC 时钟句柄的情况下启动,并且不再有权访问内核 UTC 时钟)。这可能有助于提高某些类型的数据处理的隐私保护级别。
测试
目前,单元测试、集成测试和端到端测试涵盖了每个时间管理系统调用以及依赖于它们的时间同步基础架构。移除这两个系统调用和第二个 UTC 时钟后,这些测试会稍微简化。
文档
文档更新包含在上文的实现部分中。
缺点、替代方案和未知情况
此方案的费用很低 - 我们估计,组件平台和内核团队中的 2-3 名工程师需要在 1-3 个季度内每周工作几个小时。
替代方案主要涉及不清理此技术债务或减少清理此技术债务;例如,可以停止维护内核 UTC 时钟,但不移除关联的系统调用。这些替代方案可在短期内降低费用,但从长远来看会大幅增加费用。
在先技术和参考文档
kernel_objects/clock 清晰地概述了用户空间时钟的运作方式,建议您阅读。