RFC-0199:保护子 VMAR

RFC-0199:保护子 VMAR
状态已接受
区域
  • 内核
说明

允许 zx_vmar_protect 应用于子 VMAR 中的映射。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-09-13
审核日期(年-月-日)2022-11-03

摘要

允许 zx_vmar_protect 降低范围内子 VMAR 的权限。

设计初衷

在 Fuchsia 上,软件(例如组件加载器)将映射放置在子 VMAR 中,但不保留并将句柄传递给这些子 VMAR,这种情况并不少见。在这种情况下,您将无法再对这些映射执行 zx_vmar_protect 等操作,即使使用根 VMAR(理论上是该范围的父级授权机构)也是如此。

protect 无法提升超出用于创建映射的句柄允许的权限,通常用于在应用中提供额外的错误检查。例如,应用可能会移除对其堆中未使用的部分的访问权限,以捕获任何释放后使用或其他无效访问。

对于某些用例,无需提升权限,而 protect 仅用于降低权限。在这些情况下,如果映射位于子 VMAR 中,则无法使用 protect 来减少权限,这有助于减少应用可以执行的错误检测。

利益相关方

教员

cpu@google.com

Reviewers:

travisg@google.com、rasheqbal@google.com、nickcano@google.com

咨询了

wez@google.com、palmer@google.com、mvanotti@google.com

社交

此提案之前已与 Zircon 团队讨论过。

设计

引入了新权限 ZX_RIGHT_OP_CHILDREN,用于控制是否允许对对象执行的操作递归到子对象。此提案仅为 VMAR 赋予此权限,不允许将其授予其他对象。右侧将成为 ZX_DEFAULT_VMAR_RIGHTS 的一部分。

我们将更改现有操作的定义,以便以以下方式理解此权利:

  • zx_vmar_protect:能够递归地应用于子区域中的映射,但限制是子区域映射只能降低权限。下一部分将对此进行进一步讨论。
  • zx_vmar_unmapzx_vmar_op_range:已是递归的,并将遵循限制此行为的新权限。
  • zx_vmar_destroy:逻辑上是递归的,并且需要操作权限。

对于所有操作,其 API 说明将定义为,当指定范围包含子区域且不存在 ZX_RIGHT_OP_CHILDREN 权限时,返回 ZX_ERR_ACCESS_DENIED

在对范围进行操作时,内核 VMAR 代码已经能够递归到子 VMAR,并且无需为此设计新方法,因为可以使用现有的枚举工具。

保护机制

zx_vmar_protectZX_RIGHT_OP_CHILDREN 存在时唯一可执行的操作,本部分将探讨映射权限的运作方式,以及在应用于子映射时如何应用于 protect

映射权限

映射具有两种权限概念。

  1. 用于创建映射的 VMAR 和 VMO 句柄的访问权限的交集。这表示映射的最大权限。
  2. 映射的当前操作权限,系统会根据这些权限检查所有访问。这些权限始终不超过最大权限。

首次构建时,系统仅根据句柄权限推断出最大权限,并且用户没有任何机制来限制这一点。初始操作权限在选项中设置为 zx_vmar_map,并且必须小于或等于句柄的最大权限。

构建后,可以随时使用 zx_vmar_protect 操作更改操作权限,前提是请求的权限不超过原始的最大权限。

其结果是,即使映射的最大权限允许读取,如果当前权限不允许读取,系统也会拒绝访问并生成异常。其他 VMAR 操作(例如 zx_vmar_op_range)的行为与 protect 类似,受最大权限(而非当前权限)控制。

层次结构权限

与映射不同,VMAR 只有一种权限概念,并且无法更改。VMAR 是使用 zx_vmar_allocate 创建的,其输入为:

  • 指向父级 VMAR 的句柄
  • 新 VMAR 的权限

在这里,请求的权限必须与父 VMAR 句柄的权限相同或更低,这符合预期。

生成的子 VMAR 句柄的句柄权限设置为与所创建 VMAR 的权限一致,而这些权限与请求的权限一致。

这会产生两个后果:

  1. 在遍历 VMAR 层次结构时,权限只能被舍弃,而不能增加。
  2. VMAR 句柄的句柄权限绝不会超出 VMAR 权限,但可以具有较少的权限。

影响

zx_vmar_protect 操作目前对请求的权限施加了三项要求:

  1. 调用的 VMAR 句柄必须具有请求的权限。
  2. 由覆盖该范围的最内部 VMAR 调用的 VMAR,系统不会递归到子 VMAR。
  3. 范围内的每个映射都必须具有足够的最大权限。

在此变更生效后,第二个要求将改为:范围内子 VMAR 中的每个映射都必须具有当前操作权限,且该权限不低于请求的权限。

实现

这可以在几个小 CL 中完全实现,这些 CL 具有以下特点:

  • ZX_RIGHT_OP_CHILDREN 引入内核 API。
  • 为每个 VMAR 操作添加了对权限的支持,并根据需要更新了文档和添加了测试。

性能

预计不会对性能产生影响。更改实现以支持子 VMAR 迭代可能会使现有用例的性能变差,我们将使用 Zircon 微基准来检查这一点。

向后兼容性

ZX_RIGHT_OP_CHILDREN 将成为默认权限,对于已递归的现有操作,行为将保持不变。protect 将默认获得递归功能,但在测试之外,用户不应依赖于此类情况下生成的错误。因此,protect 成功而不是失败,应该不会破坏任何现有用户。

安全注意事项

目前,创建无法更改权限的映射时,需要依赖于将映射放入 VMAR、保护该映射,然后丢弃 VMAR 的句柄。即使映射具有更高的最大权限,但由于没有 VMAR 句柄,因此当前权限永远无法更改。如果可以增加这些映射的权限,则会违反安全属性。

虽然此提案允许更改子 VMAR 中的权限,但只能减少权限,而不能增加权限。举个类似的例子,现在已经可以使用 zx_vmar_unmap 操作有效地将子区域权限缩减为零。能够选择将权限缩减到介于无权限和当前权限之间的某个级别,并不会提供任何其他类型的权限。

注重安全的组件还可以从其拥有的任何句柄中移除 ZX_RIGHT_OP_CHILDREN

缺点、替代方案和未知情况

传递所有 VMAR 句柄

主要替代方案是让内核保持不变,并更改用户空间以跟踪和传递所有子 VMAR 句柄。虽然在概念上很简单,但鉴于此信息交换需要在组件创建边界上进行,因此定义或扩展 API 以传输此信息将是一项不小的变更。

除了这种方法的实现复杂性更高之外,人们普遍认为,为了执行操作而需要保留和跟踪所有子 VMAR 或 VMO 句柄,对用户空间来说是一种不合理的负担。