22、安全启动链:Verified Boot、AVB、dm-verity、密钥管理
安全启动链,说白了就是一套「信任传递」的机制。从你按下电源键那一刻起,系统就要确保每一段被加载的代码都是可信的、未被篡改的。我在做第一代定制ROM时,曾经跳过这个环节,结果设备被root后刷入了恶意内核,直接变砖——嗯,从那以后我再也不敢轻视安全启动链了。
22.1 什么是安全启动链?
安全启动链的核心思想很简单:信任从硬件开始,逐级传递。你想想看,如果Bootloader被篡改了,那它加载的内核还能信吗?如果内核被改了,那它挂载的system分区还能信吗?
整个链条是这样的:
- 硬件根信任(SoC内部熔丝/OTP)
- Boot ROM(只读,不可修改)
- Bootloader(校验下一级)
- Boot image(内核+dtb+ramdisk)
- System/Vendor分区(通过dm-verity校验)
每一级都要验证下一级的签名或哈希,一旦发现不匹配,立即拒绝启动。我个人习惯把这种机制叫做「洋葱模型」——剥一层,验一层。
核心原则:信任不能凭空产生,必须源自硬件。任何软件级别的信任都是可以被绕过的。
22.2 Verified Boot 与 AVB
Android的Verified Boot(已验证启动)经历了几个阶段。早期是Google自己搞的一套,后来演进成了AVB(Android Verified Boot)。AVB现在已经是AOSP的标准组件了。
AVB的核心工作流程:
- 启动时:Bootloader读取boot image的vbmeta头部,验证签名
- 校验方式:使用哈希树(hash tree)或哈希描述符
- 失败处理:可以配置为「警告但继续启动」或「直接拒绝启动」
我记得有一次,客户要求关闭AVB以加快启动速度。我劝了半天没劝住,结果设备在OTA升级后因为分区校验失败全部变砖——那次教训让我明白,AVB不是可以随便关的。
小提示:AVB的vbmeta结构体里有一个flags字段,可以控制「是否允许回滚」和「是否启用dm-verity」。调试阶段可以临时关闭,但发布版必须开启。
22.3 dm-verity:块设备级别的完整性校验
dm-verity是Linux内核的Device Mapper模块,专门用来做块设备的哈希校验。它和AVB配合使用:AVB负责校验启动镜像,dm-verity负责校验挂载后的分区数据。
工作原理其实不复杂:
- 构建系统时,为整个分区生成一棵Merkle哈希树
- 树的根哈希被签名后存入vbmeta
- 启动时,内核加载dm-verity表,指定根哈希和校验设备
- 每次读取块设备时,dm-verity都会验证哈希路径
你可能会问:「每次都校验,性能会不会很差?」嗯,这里有个优化点——dm-verity只校验实际被读取的块,不是全盘校验。所以性能开销其实很小,大概在5%以内。
注意:dm-verity只能检测篡改,不能修复。一旦发现哈希不匹配,它会返回I/O错误,应用层会收到SIGBUS或EIO。所以如果你的ROM经常报「存储空间不足」或「文件损坏」,先查查dm-verity是不是误报了。
22.4 密钥管理:安全启动链的命门
安全启动链再强,密钥泄露就全完了。密钥管理这块,我踩过不少坑,分享几个关键点:
22.4.1 密钥层级
| 密钥名称 | 用途 | 存储位置 | 泄露后果 |
|---|---|---|---|
| 根密钥(Root Key) | 签名vbmeta | 硬件安全模块(HSM) | 全盘崩溃 |
| 中间密钥(Intermediate Key) | 签名boot/recovery | 构建服务器 | 可伪造启动镜像 |
| 应用密钥(App Key) | 签名APK/OTA包 | 开发机 | 可伪造应用更新 |
我个人习惯把根密钥放在离线HSM里,连构建服务器都不能直接访问。中间密钥可以放在CI/CD系统里,但必须加密存储。
22.4.2 密钥轮换与回滚保护
AVB支持密钥轮换,但要注意回滚保护。每个vbmeta里都有一个rollback_index,Bootloader会检查这个值是否大于等于上次记录的值。如果小于,说明有人想降级攻击。
我曾经在项目中遇到过一个问题:OTA升级后rollback_index没更新,导致所有设备都无法再次升级。排查了两天才发现是脚本里漏了更新逻辑——嗯,这种低级错误,犯过一次就不会再犯了。
最佳实践:密钥轮换时,一定要同时更新rollback_index。建议把rollback_index和系统版本号绑定,比如版本号v1.2.3对应rollback_index=123。
22.5 安全启动链的完整流程图
下面这张图展示了从硬件上电到系统启动的完整信任链。我特意把每个环节的校验关系画清楚了,方便你理解。
22.6 实际项目中的避坑指南
做定制ROM时,安全启动链最容易出问题的几个地方:
- 密钥丢失:我曾经把根密钥放在一个加密U盘里,结果U盘坏了。从那以后,我至少备份三份,分别放在不同物理位置。
- 签名算法不匹配:AVB默认用RSA2048+SHA256,但有些SoC只支持RSA4096。一定要提前确认硬件支持的算法。
- dm-verity表配置错误:hash_offset和fec_offset写错会导致启动卡在「verity」阶段。建议用avbtool的verify_image先验证。
- 回滚保护忘记更新:OTA脚本里一定要显式更新rollback_index,不要依赖默认值。
调试技巧:如果设备卡在启动阶段,可以用fastboot boot命令临时加载未签名的镜像,配合adb logcat查看avb和dm-verity的日志。关键词搜「avb」「verity」「dm-verity」。
22.7 总结
安全启动链不是可选项,而是Android设备安全的基石。从硬件根信任到dm-verity,每一环都不可或缺。密钥管理更是重中之重——密钥丢了,安全启动链就是摆设。
做定制ROM时,我建议你先把安全启动链跑通,再去做其他功能。否则,你辛辛苦苦做的ROM,可能连开机都开不了。
公众号:蓝海资料掘金营,微信deep3321