设备bootloader上锁状态下1217无法工作问题分析
背景
前面讲到r上6月份升级基线后, 因KM TA date support的升级导致recovery下无法正常使用解密服务.
当时的方案是配置recovery vbmeta区域的 prop --prop com.android.build.boot.security_patch:2020-06-05
从而在bootimg_hdr不支持识别date 信息的情况下, 可以在reocovery模式下bootloader能够读到天的信息, 并传给KM TA.
新问题
最近测试在复测该问题时, 发现手机bootloader上锁状态下, 无法执行1217功能. 因此需要重新分析下这个问题的原因.
locked 状态下的调试
debug abl的方法
locked状态下的限制
首先, 小米机器locked 状态有如下限制:
- 不能使用fastboot烧录新的img, 即fastboot flash <partition.img> 是不被允许的
- 不能使用fastboot erase 分区, 像
fastboot erase misc
无法执行 - locked状态切到unlocked状态, unlocked状态切到locked状态, 都会reboot 进recovery, 清除数据.
上述限制或功能必须被禁用掉, 因为调试这个问题时, 本地打的调试(带logcat 和 adb shell)功能的在locked状态肯定会报system has destroyed
, 其次经常需要debug abl, 烧分区的限制肯定要禁用掉, 不然每次烧录新的abl 都需要使用9008模式烧机, 非常麻烦. locked 切 unlocked状态, 或反之的情况清除数据的功能肯定要拿掉, 因为1217测的就是解主系统加密过的userdata分区, 如果在切换过程中把userdata擦了, 那就破坏了测试的前提. 第二条清misc也是必须的, 因为recovery如果无法正常启动, 出现system has destroyed
, 可以通过清misc, 启动到主系统把recovery恢复回来.
change
去除locked状态下对fastboot flash / fastboot erase 和 切换locked unlocked 对userdata数据的操作
http://gerrit.bsp.xiaomi.srv/#/c/22341/
locked状态下让avb校验失败的recovery成功启动起来
注意不能修改avb校验完的状态, 保持最小变量原则
change
即将导向system has destroyed
的入口破坏掉
http://gerrit.bsp.xiaomi.srv/22334
本地recovery调试1217的方法
本地编译userdebug版本的recovery即可.
- 将上述change合入后, 编译abl, make aboot或者使用ninja, 注意最后abl一定要通过secureboot签名
- locked上锁状态可以先使用解锁工具解锁, 再通过fastboot flash abl abl.elf 烧录locked 状态修改过的abl, 然后再使用fastboot oem lock上锁.
- 上锁完后, fastboot flash recovery 本地的recovery.img.
- fastboot reboot recovery
- 使用下面的命令, 查看df -h的结果中是否有userdata, vold的输出的log是什么, 如果begin操作报错, 说明keymaster 返回了错误
1 | adb root; adb shell mv /system/bin/recovery /tmp/; adb shell touch /system/bin/recovery; adb shell /tmp/recovery --factory_test_reset&; sleep 6; adb shell df -h; adb logcat -s vold; |
问题分析
通过之前修改recovery 打包写入avb prop的方法已经可以使recovery在unlocked模式下1217正常工作. 而locked状态下却不行. 变量只有一个就是locked状态和unlocked状态.
先根据log定位下初步原因, 测试开始提供的log中只有recovery打出的部分信息:
recovery 重启, reason= fs_mgr_mount_all
根据串口log的信息, 首先可以判定是如下情形:
- 主系统bcb (reason –factory_test_reset) ->2. recovery启动(模式为1217)-> 3. recovery重启(模式变为fs_mgr_mount_all)
在第2步1217的执行步骤中触发了 RebootRecovery(fs_mgr_mount_all)的命令, 查看代码, 最终定位到
mount_all miui_factoryreset.fstab --late
时 init 在执行vdc mountFstab /dev/block/bootdevice/by-name/userdata /data
失败后执行了上述命令, 所以需要进一步的log判断为什么这个vdc 的操作失败了.
根据前面debug locked 状态下recovery的方法, 最终可以在locked状态下启动本地带调试版本的recovery
得到的log如下:
1 | 01-01 01:10:19.148 630 630 D vold : metadata_key_dir/key: /metadata/vold/metadata_encryption/key |
keymaster返回-33的错误导致了这样的表现.
根据之前对abl的分析, 这个大概率与abl传给KM TA的参数有关.
搜索代码, 最终定位到
1.
1 | /* Set Boot State */ |
debug分析这一过程发现locked状态下, 只有color是orange时可以让recovery在调用keymaster begin解密经主系统加密的userdata时可以正常返回.
而如果userdata没有通过主系统的加密, 即在recovery下先恢复出厂设置, 再对userdata加密时, color是green情况下, 也可以正常调用keymaster,没有返回错误, 而在recovery下加密userdata完成后, 再启动到主系统, 主系统会报fs_mgr_mount_all的错误.
通过上述现象, 可以推测 加密userdata相当于上层keymaster初始化, 使用当时的环境去加密的数据, 而换了环境之后, 再去解密, 由于环境的变化, 导致keymaster无法校验成功, 所以begin返回了invalid blob(-33), 而这个环境
是什么, 通过分析BootState的字段在recovery和主系统下的区别, 只有BootStateDigest
是值得怀疑的.
BootStateDigest即UserData->PublicKey的分析
上一步怀疑这个字段有问题后, 需要分析recovery模式和主系统下这个字段的数据来源.
最终发现新基线升级后, recovery的avb校验模式变成了只校验recovery分区自己, 而主系统是校验 vbmeta boot dtbo vbmeta_system. 而主系统这个字段最终来自vbmeta分区的public key. 而recovery的这个字段并没有赋值.
recovery模式:
1 | if ( ( (!Info->MultiSlotBoot) || |
问题解决
上面怀疑recovery模式和主系统下abl传给KM TA的摘要是不同的, 那可以想到将vbmeta的public key 填充到 UserData->PublicKey, 下发给KM TA 是否可以解决locked状态下recovery无法使用keymaster解密经主系统加密的数据.
方案如下:
http://gerrit.bsp.xiaomi.srv/#/c/22338/
只有非ab机型进入recovery情况下, 即AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION
flag的作用范围内, 在avb verify完recovery分区后, 再avb verify下vbmeta分区, 目的是为了让其覆盖ops->user_data
段, 而传进load_and_verify_vbmeta
的参数需要重新设定, 因为原先的参数很多都是全局或影响avb verify recovery结果的指针, 我们这里只能覆盖ops->user_data
段, 不能对其他段产生影响. 同时还需要对flag 重新置位, 绕开vbmeta相关的检查, 使得可以成功load vbmeta的public key, 并将其赋给ops->user_data
段.
1 | typedef struct { |
重新测试后, 上述patch有效, locked下recovery中可以正常进行1217功能.
验证
- locked状态下, 主系统开机后, 执行1217, 正常reboot到recovery中进行清数据的操作, 重启回主系统下, /data/miui/app下内容保留
- locked状态下, fastboot flash 本地编的recovery, fastboot reboot recovery后, 应该报
system has destroyed
- unlocked 状态下, 无论是本地编的recovery还是线刷包版本的recovery, 都可以正常进行1217功能
验证时, unlocked状态切换到locked状态, 或反之的情况, 切换过程中都需要进recovery wipe data, 擦完重新开机进主系统, 保证数据要重新经主系统初始化加密一次.