AVB相关的一些bug fix
vendor分区未加入avb校验中:
之前负责AVB的同事离职后,接手这个模块。走读代码时,发现vendor分区没有配置avb校验。
可能是之前整体调整fstab时,把这个配置给漏掉了。
拿手机试了下,确实如此:
# cat /sys/block/dm-*/dm/name
system_a
system_ext_a
product_a
vendor_a
system-verity
system_ext-verity
product-verity
userdata
修改点:
-vendor /vendor ext4 ro,barrier=1,discard wait,slotselect,logical,first_stage_mount +vendor /vendor ext4 ro,barrier=1,discard wait,slotselect,avb,logical,first_stage_mount
修改之后:
# cat /sys/block/dm-*/dm/name
system_a
system_ext_a
product_a
vendor_a
system-verity
system_ext-verity
product-verity
vendor-verity
userdata
CTSKeystoreTestcases测试fail:
从log看:
28104 10-31 09:58:06.506 3406 3423 I TestRunner: started: testEcAttestation_DeviceLocked(android.keystore.cts.KeyAttestationTest) 28604 10-31 09:58:07.482 3406 3423 E TestRunner: failed: testEcAttestation_DeviceLocked(android.keystore.cts.KeyAttestationTest) 28605 10-31 09:58:07.482 3406 3423 E TestRunner: ----- begin exception ----- 28607 10-31 09:58:07.484 3406 3423 E TestRunner: junit.framework.AssertionFailedError: expected:<0> but was:<1> //这里不符合预期 28608 10-31 09:58:07.484 3406 3423 E TestRunner: at junit.framework.Assert.fail(Assert.java:50) 28609 10-31 09:58:07.484 3406 3423 E TestRunner: at junit.framework.Assert.failNotEquals(Assert.java:287) 28610 10-31 09:58:07.484 3406 3423 E TestRunner: at junit.framework.Assert.assertEquals(Assert.java:67) 28611 10-31 09:58:07.484 3406 3423 E TestRunner: at junit.framework.Assert.assertEquals(Assert.java:199) 28612 10-31 09:58:07.484 3406 3423 E TestRunner: at junit.framework.Assert.assertEquals(Assert.java:205) 28613 10-31 09:58:07.484 3406 3423 E TestRunner: at android.keystore.cts.KeyAttestationTest.checkRootOfTrust(KeyAttestationTest.java:1142) 28614 10-31 09:58:07.484 3406 3423 E TestRunner: at android.keystore.cts.KeyAttestationTest.checkDeviceLocked(KeyAttestationTest.java:1121) 28615 10-31 09:58:07.484 3406 3423 E TestRunner: at android.keystore.cts.KeyAttestationTest.testEcAttestation_DeviceLocked(KeyAttestationTest.java:301)
对应CTS测试代码:
private void checkRootOfTrust(Attestation attestation, boolean requireLocked) {
RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
assertNotNull(rootOfTrust);
assertNotNull(rootOfTrust.getVerifiedBootKey());
assertTrue("Verified boot key is only " + rootOfTrust.getVerifiedBootKey().length +
" bytes long", rootOfTrust.getVerifiedBootKey().length >= 32);
if (requireLocked) {
assertTrue(rootOfTrust.isDeviceLocked());
checkEntropy(rootOfTrust.getVerifiedBootKey());
assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());//这里检查失败
}
}
结合log中cmdline的输出:
00037 01-14 01:48:31.489 0 0 I : Kernel command line: security=selinux …… androidboot.verifiedbootstate=yellow ……
初步怀疑是AVB校验这边校验出异常了。
追查下来,发现是前面有笔提交,给IsUserKey赋值为true了。修改后复测pass。
查看系统属性,也对上啦:
$ getprop |grep bootstate [ro.boot.verifiedbootstate]: [green]
GSI版本启动失败:
异常日志:
30275 [ 10.307797] device-mapper: verity-fec: 253:0: FEC 0: failed to correct: -74 30276 [ 10.323250] device-mapper: verity: 253:0: data block 0 is corrupted 30304 [ 10.899018] reboot: Restarting system with command 'dm-verity device corrupted'
查看253:0是哪个分区:
# dmctl list devices Available Device Mapper Devices: system_ext_a : 253:1 userdata : 253:8 system_a : 253:0 vendor-verity : 253:7 vendor_a : 253:3 system_ext-verity : 253:5 product-verity : 253:6 system-verity : 253:4 product_a : 253:2
最终追查下来,是使用的fastboot版本太低导致的问题。工作中真的是什么奇奇怪怪的问题都能碰到啊。
hash partition优化提升开机时间
修改原理如下:
首先,这处改动发生在函数load_and_verify_hash_partition中。
其中io_ret = ops->get_size_of_partition(ops, part_name, &image_size);是从partition中读到整个分区的长度。
我们注释掉了这条语句,转而通过image_size = hash_desc.image_size;来确定将要读取的数据大小。
这个是因为,对于hash partition(如boot,dtbo和vendor_boot),其image的大体框架如下:
以dtbo.img为例,该image的真实数据是dtbo + padding + vbmeta + padding + footer。
其中需要校验的仅仅是第一部分的真实dtbo数据,这块数据的长度在vbmeta.img的hash descriptor中保留了。
而这块数据在整个dtbo.img中占比较小,如果在读分区时只读这一部分,那么读取时间会得以较大改善。
如下,
original image size of dtbo = 0x11cf9b,从footer中读出的。
vbmeta的offset为0x11d000,也是footer中读出。
我们来看看0x11d000的数据,这里是vbmeta数据的位置,前面0x11cf9b所占整个dtbo.img的比例为 0x11cf9b ÷ 0x18000000 = 0.046
以本地的一份dtbo.img来看:
这个是编译过程中的打印,如下:
09157 add_hash_footer partition = dtbo 09158 add_hash_footer image_size = 1193543
这个是dtbo.img的footer中original_image_size,为0x123647 = 1193543,和打印值能对上。
上面的打印值是加在add_hash_footer中生成hash descriptor的地方,如下:
3286 h_desc = AvbHashDescriptor() 3287 h_desc.image_size = image.image_size 3288 h_desc.hash_algorithm = hash_algorithm 3289 h_desc.partition_name = partition_name 3290 print('add_hash_footer partition = ', partition_name) 3291 print('add_hash_footer image_size = ', image.image_size) 3292 h_desc.salt = salt 3293 h_desc.flags = 0 3294 if do_not_use_ab: 3295 h_desc.flags |= 1 # AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB 3296 if not use_persistent_digest: 3297 h_desc.digest = digest
从这里可以看到,hash descriptor中的hash值,其实算的是original dtbo image数据,而非整个分区长度。
uboot中在load_and_verify_hash_partition时,计算hash也是只算了这一部分,所以locked状态下,没有必要读取整个分区长度数据(耗时,无意义):
if (Avb_StrnCmp((CONST CHAR8 *)hash_desc.hash_algorithm, "sha256", avb_strlen("sha256")) == 0) { avb_debugv(part_name, "[avb]: do sha256 hash operation start.\n", NULL); avb_sha256_init(&sha256_ctx); avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len); avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size); digest = avb_sha256_final(&sha256_ctx); digest_len = AVB_SHA256_DIGEST_SIZE; avb_debugv(part_name, "[avb]: do sha256 hash operation done.\n", NULL); }