为了防止在 pVM 内运行任意负载,Android 虚拟化框架 (AVF) 使用分层安全方法,其中每一层都添加了额外的强制措施。以下是 AVF 安全层列表:
Android – Android 确保仅允许具有 pVM 权限的应用程序创建或检查 pVM。
引导加载程序——引导加载程序确保仅允许由 Google 或设备供应商签名的 pVM 映像引导并遵守Android 验证引导程序。这种架构意味着运行 pVM 的应用程序不能捆绑自己的内核。
pVM – pVM 为在 pVM 中运行的有效负载提供深度防御,例如SELinux 。纵深防御不允许将映射数据作为可执行文件 (
neverallow execmem
) 并确保W^X适用于所有文件类型。
安全模型
机密性、完整性和可用性,也称为 CIA 三元组,是一种旨在指导信息安全策略的模型:
- 机密性是一组限制信息访问的规则。
- 完整性是信息可信和准确的保证。
- 可用性是授权实体可靠访问信息的保证。
请注意,pKVM 旨在维护来宾的机密性和完整性,而不是可用性。这些原则影响跨越架构所有方面的设计决策,从管理程序到用户空间组件。
保密性和完整性
机密性源于 pKVM 管理程序强制执行的内存隔离属性。 pKVM 跟踪各个物理内存页面的内存所有权以及所有者对共享页面的任何请求。 pKVM 确保只有授权的 pVM(主机和来宾)将给定的页面映射到由管理程序控制的阶段 2 页表中。这种架构维护 pVM 拥有的内存内容保持私有,除非所有者明确与另一个 pVM 共享它。
维护机密性的限制还扩展到系统中代表 pVM 执行内存访问的任何实体,即具有 DMA 能力的设备和在更多特权层中运行的服务。 SoC 供应商必须满足一组新要求才能支持 pKVM,否则无法提供机密性。
完整性适用于内存和计算中的数据:
- pVM 不能在未经同意的情况下修改彼此的内存。
- pVM 不能影响彼此的 CPU 状态。
这些要求由管理程序强制执行。但是,在必须应用其他解决方案(例如 dm-verity 或 AuthFS)的虚拟数据存储中,也会出现有关数据完整性的问题。
这些原则与 Linux 提供的进程隔离没有什么不同,Linux 提供的对内存页面的访问由阶段 1 页表和进程之间的内核上下文切换控制。然而,执行这些属性的 pKVM 的 EL2 部分与整个 Linux 内核相比大约有一半的攻击面(大约 10000 行代码对 2000 万行代码),因此为过于敏感而无法依赖的用例提供更强的保证关于进程隔离。
鉴于它的大小,pKVM 适合于形式验证。我们正在积极支持学术研究,旨在在实际 pKVM 二进制文件上正式证明这些属性。
本文档的其余部分涵盖了 pKVM 周围的每个组件提供的机密性和完整性保证。
管理程序
pKVM 是一个基于 KVM 的管理程序,它将 pVM 和 Android 隔离到相互不信任的执行环境中。这些属性在任何 pVM (包括主机)内发生妥协的情况下仍然有效。符合 AVF 的替代管理程序需要提供类似的属性。
- 除非页面所有者明确共享,否则 pVM 无法访问属于另一个实体(例如 pVM 或管理程序)的页面。此规则包括主机 pVM 并适用于 CPU 和 DMA 访问。
- 在 pVM 使用的页面返回到主机之前,例如当 pVM 被销毁时,它会被擦除。
- 在 OS 引导加载程序在后续设备引导中运行之前,所有 pVM 的内存和一次设备引导中的 pVM 固件都会被擦除。
- 当连接了硬件调试器(例如 SJTAG)时,pVM 无法访问其先前生成的密钥。
- 如果 pVM 固件无法验证初始映像,则不会启动。
- 如果
instance.img
的完整性受到损害,pVM 固件将不会启动。 - 提供给 pVM 实例的引导证书链 (BCC) 和复合设备标识符 (CDI) 只能由该特定实例派生。
来宾操作系统
Microdroid是在 pVM 中运行的操作系统的一个示例。 Microdroid 由基于 U-boot 的引导加载程序、GKI、Android 用户空间子集和有效负载启动器组成。这些属性在任何 pVM (包括主机)内发生妥协的情况下仍然有效。在 pVM 中运行的替代操作系统应该提供类似的属性。
- 如果
boot.img
、super.img
、vbmeta.img
或vbmeta\_system.img
无法验证,Microdroid 将无法启动。 - 如果 APK 验证失败,Microdroid 将无法启动。
- 即使更新了 APK,同一个 Microdroid 实例也不会启动。
- 如果任何 APEX 未能通过验证,Microdroid 将无法启动。
- 如果在来宾 pVM 之外修改了
instance.img
,Microdroid 将无法启动(或以干净的初始状态启动)。 - Microdroid 为引导链提供证明。
- 对共享给来宾 pVM 的磁盘映像的任何(未签名)修改都会导致 pVM 端出现 I/O 错误。
- 提供给 pVM 实例的 BCC 和 CDI 只能由该特定实例派生。
安卓
这些是由 Android 作为主机维护的属性,但在主机受损的情况下不适用:
- 来宾 pVM 不能直接与其他来宾 pVM 交互(例如,建立 vsock 连接)。
- 只有宿主 pVM 中的
VirtualizationService
才能与 pVM 建立通信通道(注意:它可以将已建立的通道传递给其他人)。 - 只有使用平台密钥签名的应用程序才能请求创建、拥有或与 pVM 交互的权限。
- 用于在主机和 pVM 之间建立vsock连接的标识符称为上下文标识符 (CID) ,在主机 pVM 运行时不会重用。例如,不可能用另一个 pVM 替换正在运行的 pVM。
可用性
在 pVM 的上下文中,可用性是指主机为来宾分配足够的资源,以便来宾可以执行他们设计的任务。
主机的职责包括调度 pVM 的虚拟 CPU。与 Xen 等传统的 Type-1 管理程序不同,KVM 做出明确的设计决策,将工作负载调度委托给主机内核。鉴于当今调度程序的规模和复杂性,此设计决策显着减小了可信计算库 (TCB) 的规模,并使主机能够做出更明智的调度决策以优化性能。但是,恶意主机可以选择从不安排来宾。
类似地,pKVM 还将物理中断处理委托给主机内核,以降低管理程序的复杂性并让主机负责调度。努力确保访客中断的转发只会导致拒绝服务(太少、太多或错误路由的中断)。
最后,主机的虚拟机监视器(VMM)进程负责分配内存并提供虚拟设备,例如网卡。恶意 VMM 可以扣留来宾的资源。
尽管 pKVM 不向来宾提供可用性,但该设计保护主机的可用性免受恶意来宾的影响,因为主机始终可以抢占或终止来宾并回收其资源。
安全启动
数据与 pVM 的实例相关联,安全启动确保可以控制对实例数据的访问。实例的第一次启动通过为 pVM 随机生成一个秘密盐并从加载的图像中提取详细信息(例如验证公钥和哈希)来配置它。此信息用于验证 pVM 实例的后续启动,并确保实例的机密仅发布给通过验证的映像。这个过程发生在 pVM 中的每个加载阶段:pVM 固件、pVM ABL、Microdroid 等等。
DICE 为每个加载阶段提供一个证明密钥对,其公共部分在该阶段的 BCC 条目中得到认证。此密钥对可以在引导之间更改,因此还派生了一个密封密钥,该密钥对 VM 实例在重新引导期间是稳定的,因此适用于保护持久状态。密封机密对 VM 非常有价值,因此不应直接使用。相反,封印密钥应该从封印秘密中衍生出来,并且应该尽早销毁封印秘密。
每个阶段将确定性编码的CBOR对象传递给下一个阶段。该对象包含秘密和 BCC,其中包含累积的状态信息,例如最后阶段是否安全加载。
解锁设备
当使用fastboot oem unlock
设备时,用户数据将被擦除。此过程可保护用户数据免受未经授权的访问。当设备解锁时,pVM 的私有数据也会失效。
解锁后,设备所有者可以自由刷新通常受验证启动保护的分区,包括包含 pKVM 实现的分区。因此,解锁设备上的 pKVM 不会被信任来维护安全模型。
远程方可以通过在密钥证明证书中检查设备的已验证启动状态来观察这种潜在的不安全状态。