| <html devsite><head> |
| <title>验证启动</title> |
| <meta name="project_path" value="/_project.yaml"/> |
| <meta name="book_path" value="/_book.yaml"/> |
| </head> |
| <body> |
| <!-- |
| Copyright 2018 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| //www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <p>验证启动要求在使用前以加密形式验证要启动的 Android 版本包含的所有可执行代码和数据,其中包括内核(从 <code>boot</code> 分区加载)、设备树(从 <code>dtbo</code> 分区加载)、<code>system</code> 分区和 <code>vendor</code> 分区等。 |
| </p> |
| |
| <p>仅读取一次的小分区(例如 <code>boot</code> 和 <code>dtbo</code>)通常是通过将整个内容加载到内存中,然后计算相应哈希值来进行验证的。接下来,系统会比较这个计算出的哈希值与预期哈希值。<em></em>如果值不一致,则 Android 将无法加载。如需了解详情,请参阅<a href="/security/verifiedboot/boot-flow">启动流程</a>。 |
| </p> |
| <p>内存装不下的较大分区(如文件系统)可以使用哈希树;此时,验证流程会在将数据加载到内存时持续进行。在这种情况下,系统会在运行时计算哈希树的根哈希值,并对照预期根哈希值进行检查。<em></em>Android 包含用于验证较大分区的 <a href="/security/verifiedboot/dm-verity">dm-verity 驱动程序</a>。如果在某个时间点计算出的根哈希值与预期根哈希值不一致<em></em>,系统便不会使用相应数据,而且 Android 会出现错误。如需了解详情,请参阅 <a href="/security/verifiedboot/boot-flow#dm-verity-corruption">dm-verity 损坏</a>。 |
| </p> |
| <p>预期哈希值<em></em>通常存储在每个经过验证的分区的末尾或开头、专用分区中,或同时位于以上两个位置。最重要的是,这些哈希值是由信任根以直接或间接的方式签名的。举个例子,AVB 实现就支持这两种方式;要了解详情,请参阅 <a href="/security/verifiedboot/avb">Android 验证启动</a>。 |
| </p> |
| |
| <h2 id="rollback-protection">回滚保护</h2> |
| <p>即使更新流程完全安全,攻击者仍可能会利用非永久性 Android 内核漏洞来手动安装更易受攻击的旧版 Android 系统,重新启动进入易受攻击的版本,然后通过该 Android 版本来安装永久性漏洞。在这种情况下,攻击者可通过这种漏洞永久拥有相应设备,并可以执行任何操作(包括停用更新)。 |
| </p> |
| <p>防范这类攻击的保护措施称为“回滚保护”<em></em>。“回滚保护”通常通过以下方式实现:使用防篡改的存储空间来记录最新的 Android 版本,并在 Android 版本低于记录的版本时拒绝启动 Android。系统通常会针对每个分区来跟踪版本。 |
| </p> |
| <p>要详细了解 AVB 处理回滚保护的方式,请参阅 <a href="https://android.googlesource.com/platform/external/avb/+/master/README.md#Rollback-Protection" class="external">AVB README</a>。</p> |
| |
| <h2 id="handling-verification-errors">处理验证错误</h2> |
| <p>验证在启动时(例如,如果在 <code>boot</code> 分区上计算出的哈希值与预期哈希值不一致)和运行时(例如,如果 dm-verity 在 <code>system</code> 分区上遇到验证错误)都可能会失败。如果验证在启动时失败,设备则无法启动,而且最终用户需要执行相关步骤才能恢复设备使用。 |
| </p> |
| <p>如果验证在运行时失败,恢复流程就会更复杂一些。如果设备使用的是 dm-verity,则应在 <code>restart</code> 模式下进行配置。在 <code>restart</code> 模式下,如果遇到验证错误,设备会立即重启,并设置特定标记以表明错误原因。引导加载程序应该会注意到该标记,并将 dm-verity 切换为使用 I/O 错误 (<code>eio</code>) 模式并保持该模式,直到安装新的更新为止。 |
| </p> |
| <p>在 <code>eio</code> 模式下启动时,设备会显示错误屏幕,以通知用户系统已检测到损坏,而且设备可能无法正常使用。该屏幕会持续显示,直到用户将其关闭为止。在 <code>eio</code> 模式下,如果遇到验证错误,则 dm-verity 驱动程序将不会重启设备,而是会返回 EIO 错误,并且相应的应用需要处理该错误。 |
| </p> |
| <p>这样做的目的是,让系统更新程序能够正常运行(以便安装不含损坏错误的新操作系统),或者让用户能够从设备上获取尽可能多的数据。安装新的操作系统后,引导加载程序会注意到新安装的操作系统,并切换回 <code>restart</code> 模式。 |
| </p> |
| |
| </body></html> |