Verified Boot

Verified Boot 需要在开始使用 Android 版本之前,以加密方式验证属于要启动的 Android 版本的所有可执行代码和数据。这包括内核(从 boot 分区加载)、设备树(从 dtbo 分区加载)、system 分区、vendor 分区等等。

对于只读取一次的小分区(例如 bootdtbo),通常通过将全部内容加载到内存中,然后计算其哈希值来进行验证。然后,将计算出的哈希值与预期哈希值进行比较。如果值不匹配,Android 将不会加载。如需了解详情,请参阅启动流程

对于无法放入内存的较大分区(例如,文件系统),可以使用哈希树,其中验证是在将数据加载到内存中时持续进行的过程。在这种情况下,哈希树的根哈希是在运行时计算的,并根据预期根哈希值进行检查。Android 包括 dm-verity 驱动程序,用于验证较大的分区。如果在某个时候,计算出的根哈希与预期根哈希值不匹配,则不使用数据,并且 Android 进入错误状态。如需了解详情,请参阅 dm-verity 损坏

预期哈希值通常存储在每个已验证分区的末尾或开头、专用分区或两者中。至关重要的是,这些哈希值由信任根签名(直接或间接签名)。例如,AVB 实现同时支持这两种方法,有关详情,请参阅 Android Verified Boot

回滚保护

即使更新过程完全安全,非持久性 Android 内核漏洞也可能手动安装旧的、更易受攻击的 Android 版本,重启到易受攻击的版本,然后使用该 Android 版本安装持久性漏洞。这样一来,攻击者将永久拥有设备,并且可以执行任何操作,包括停用更新。

针对此类攻击的保护称为回滚保护。回滚保护通常通过使用防篡改存储来记录 Android 的最新版本,并拒绝启动低于记录版本的 Android 来实现。版本通常按分区进行跟踪。

如需详细了解 AVB 如何处理回滚保护,请参阅 AVB README

处理验证错误

验证可能会在启动时失败(例如,如果 boot 分区上计算出的哈希与预期哈希不匹配),或者在运行时失败(例如,如果 dm-verity 在 system 分区上遇到验证错误)。如果在启动时验证失败,则设备无法启动,最终用户需要执行步骤来恢复设备。

如果在运行时验证失败,则流程会稍微复杂一些。如果设备使用 dm-verity,则应将其配置为 restart 模式。在 restart 模式下,如果遇到验证错误,设备会立即重启,并设置特定标志以指示原因。启动加载程序应注意到此标志,并将 dm-verity 切换为使用 I/O 错误 (eio) 模式,并在此模式下保持状态,直到安装新的更新。

当在 eio 模式下启动时,设备会显示一个错误屏幕,告知用户已检测到损坏,并且设备可能无法正常运行。屏幕会一直显示,直到用户将其关闭。在 eio 模式下,如果 dm-verity 驱动程序遇到验证错误,则不会重启设备,而是返回 EIO 错误,并且应用需要处理该错误。

目的是系统更新程序将运行(以便可以安装没有损坏错误的新操作系统),或者用户可以尽可能多地从设备上获取数据。安装新操作系统后,启动加载程序会注意到新安装的操作系统,并切换回 restart 模式。