RFC-0199:保护子 VMAR

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

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

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

总结

允许 zx_vmar_protect 减少范围内的子级 VMAR 的权限。

设计初衷

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

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

在某些用例中,不需要提升权限,并且会严格使用 protect 来减少权限。在这些情况下,如果映射位于子级 VMAR 中,则无法使用 protect 来减少权限,从而减少应用可执行的错误检测。

利益相关方

教员

cpu@google.com

审核者

travisg@google.com、rashaeqbal@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_protect 是唯一一个在 ZX_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 句柄才能执行操作是不合理的用户空间负担。