1. Android Verified Boot (AVB) 或称 Verified Boot 2.0 简介
官方解释:验证用户设备上运行的软件完整性。它通常从设备固件的只读部分开始,该部分加载代码并仅在通过密码验证代码是授权的并且没有任何已知的安全漏洞之后才执行代码。
AVB 2.0 引入一个新的分区:vbmeta.img(verified boot metadata),其包含分区的哈希,
下面是通过avbtool解析出的信息
Magisk$ ./avbtool info_image --image vbmeta.img
Minimum libavb version: 1.0
Header Block: 256 bytes
Authentication Block: 576 bytes
Auxiliary Block: 3776 bytes
Algorithm: SHA256_RSA4096
Rollback Index: 0
Flags: 0
Release String: 'avbtool 1.1.0'
Descriptors:
Chain Partition descriptor:
Partition Name: system
Rollback Index Location: 1
Public key (sha1): cdbb77177f731920bbe0a0f94f84d9038ae0617d
Chain Partition descriptor:
Partition Name: vm-linux
Rollback Index Location: 11
Public key (sha1): 1b75d7e33ff1ad3f71c2bd9b164595cc599088b6
Hashtree descriptor:
Version of dm-verity: 1
Image Size: 990666752 bytes
Tree Offset: 990666752
Tree Size: 7806976 bytes
Data Block Size: 4096 bytes
Hash Block Size: 4096 bytes
FEC num roots: 2
FEC offset: 998473728
FEC size: 7897088 bytes
Hash Algorithm: sha1
Partition Name: vendor
Salt:
...............................
其将所需校验的内容在编译时就计算好,打包到这个分区,启动过程中 BootLoader 只需要校验 vbmeta.img,就能确认 vbmeta 内的数据是否可信。再用 vbmeta 中的数据去比对 boot.img,dtbo,system.img,vendor.img
2. 校验流程
vbmeta分区中的VBMeta结构是通过加密签名,在启动阶段其会检查签名验证vbmeta分区是否可信,从而信任boot、system、vendor分区的哈希值,其中boot、dtbo等较小分区直接存储的是的哈希值,以及其他较大分区的是以哈希树的方式存储,VBMeta中只存放哈希树的根哈希。
校验vbmeta可信后,对于boot、dtbo分区,将整个镜像加载到内存中,直接计算其相应的哈希值与vameta中的值进行比较,如无法验证通过将无法继续启动
对于system、vendor这种很大的分区,直接将其加载进内存进行哈希校验,是耗时且很不换算,其采用哈希树的方式进行校验,其验证会在加载数据进内存的过程中持续进行,系统在运行时计算哈希树的根哈希,并于vameta中的根哈希进行比较,如果在某个时间点计算出的根哈希值与预期根哈希值不一致,系统便不会使用相应数据,而且 Android 会出现错误。这个校验是采用dm-verity实现
3. 启动流程
在启动时首先会检查设备启动状态,设备状态用于指明能够以多大的自由度将软件刷写到设备上,以及是否强制执行验证。设备状态为 LOCKED
和 UNLOCKED
。状态为 LOCKED
的设备禁止您将新软件刷写到设备上,而状态为 UNLOCKED
的设备允许您进行修改。这也是为什么root前需要对设备进行解锁。
当设备开机后,引导加载程序会先检查设备状态是 LOCKED
还是 UNLOCKED
。如果设备状态为 UNLOCKED
,引导加载程序会向用户显示警告,然后继续启动,即使加载的操作系统校验不通过也是如此。
验证启动问题分为以下几类:
绿色:设备已LOCKED
且未使用可由用户设置的信任根
黄色:针对设有自定义信任根的已锁定设备的警告屏幕
橙色:针对未锁定设备的警告屏幕
红色 (EIO):针对 dm-verity 损坏的警告屏幕
红色(未找到操作系统):未找到有效的操作系统
详细流程
在lk阶段其会检查设备的启动状态,即判断是否处于lock状态,如果处于lock状态,如果校验失败系统将无法启动,如果处于unlock状态即使校验出错也会继续启动,这里解锁就是fastboot flashing unlock
确定设备的启动状态后,LK阶段会通过vbmeta里数据校验boot、dtbo等,下面这段就是debug机器的串口log
avb_slot_verify.c:481: DEBUG: Loading vbmeta struct from partition 'vbmeta'.
Partition found: vbmeta
Partition found: recovery
avb_slot_verify.c:476: DEBUG: Loading vbmeta struct in footer from partition 'recovery'.
Partition found: recovery
avb_footer.c:41: ERROR: Footer magic is incorrect.
avb_slot_verify.c:453: DEBUG: vbmeta_system: No footer detected.
avb_slot_verify.c:481: DEBUG: Loading vbmeta struct from partition 'vbmeta_system'.
avb_slot_verify.c:181: DEBUG: boot: Loading entire partition.
Partition found: boot
avb_slot_verify.c:240: DEBUG: boot: success: Image verification completed
avb_slot_verify.c:181: DEBUG: dtbo: Loading entire partition.
Partition found: dtbo
avb_slot_verify.c:240: DEBUG: dtbo: success: Image verification completed
State: Unlocked, AvbSlotVerify returned OK, continue boot
DateSupport: 1
VB2: Authenticate complete! boot state is: green
VB2: boot state: green(0) //这里由于设备未解锁,所以传入值是green
通过command line 将状态传递给kernel,这里即verifiedbootstate,同时其也传递了vbmeta中的其他信息
#cat proc/cmdline
androidboot.verifiedbootstate=green
androidboot.keymaster=1
androidboot.vbmeta.device=PARTUUID=ff3da...
androidboot.vbmeta.avb_version=1.0
androidboot.vbmeta.device_state=locked
androidboot.vbmeta.hash_alg=sha256
androidboot.vbmeta.size=9024
androidboot.vbmeta.digest=f1abae9....
androidboot.veritymode=disabled
在内核启动后, init在校验时首先会读取传入的verifiedbootstate判断设备状态,这块处理流程比较复杂,只是粗略的看下,以后需要再深入研究
----------
https://android.googlesource.com/platform/system/core/+/refs/heads/master/fs_mgr/libfs_avb/util.cpp
----------
bool IsDeviceUnlocked() {
std::string verified_boot_state;
if (fs_mgr_get_boot_config("verifiedbootstate", &verified_boot_state)) {
return verified_boot_state == "orange";
}
return false;
}
-----------
https://android.googlesource.com/platform/system/core/+/refs/heads/master/fs_mgr/fs_mgr_boot_config.cpp
-----------
// Tries to get the boot config value in device tree, properties and
// kernel cmdline (in that order). Returns 'true' if successfully
// found, 'false' otherwise.
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
FS_MGR_CHECK(out_val != nullptr);
// firstly, check the device tree
if (is_dt_compatible()) {
std::string file_name = get_android_dt_dir() + "/" + key;
if (android::base::ReadFileToString(file_name, out_val)) {
if (!out_val->empty()) {
out_val->pop_back(); // Trims the trailing '\0' out.
return true;
}
}
}
// next, check if we have "ro.boot" property already
*out_val = android::base::GetProperty("ro.boot." + key, "");
if (!out_val->empty()) {
return true;
}
// finally, fallback to kernel cmdline, properties may not be ready yet
if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) {
return true;
}
return false;
}
#启动阶段init log
init: [libfs_avb]Returning avb_handle with status: Success
init: [libfs_avb]: Error verifying vbmeta image: OK_NOT_SIGNED
init: [libfs_avb]: allow verification error is not allowed
init: [libfs_avb]Failed to load vbmeta: /dev/block/dm-0
init: Failed to load offline vbmeta for /system
init: Fallback to built-in hashtree for /system
init: [libfs_avb]Built verity table:.....
安卓启动后也可以通过属性看到设备状态
#getprop
[ro.boot.vbmeta.avb_version]: [1.0]
[ro.boot.vbmeta.device_state]: [locked]
[ro.boot.vbmeta.digest]: [f1abae...]
[ro.boot.vbmeta.hash_alg]: [sha256]
[ro.boot.vbmeta.size]: [9024]
[ro.boot.verifiedbootstate]: [green]
[ro.boot.veritymode]: [disabled]
如有错误,欢迎指正,探讨
参考链接: