其实可能有人会说,怎么整这么多重复的,其实不是的。这是为了不断地巩固,但是其实再深入,虽然部分的概念是一样的,但很多的细节和流程上的还是各有倾向,等我梳理好整个以后,再来重新写个更完整的。
在这之前继续先来学习一下前辈们的优秀blog。
1、avb-结构概念
验证程序用来保护用户使用软件在设备上运行的完整性。
它通常从设备固件的只读部分开始,该部分加载代码并仅在密码验证代码是真实的且没有任何已知的安全缺陷之后执行。AVB是经过验证的引导的一种实现。
1、The VBMeta struct
AVB中使用的中心数据结构是VBMeta struct,这个数据结构包含许多描述符(和其他元数据),所有这些数据都是加密签名的。描述符用于img哈希表、img哈希树元数据和所谓的链式分区。一个简单的例子是:
vbmeta分区在哈希描述符中保存引导分区的哈希。对于system分区 vendor分区的hashtree遵循文件系统数据,vbmeta分区在哈希树描述符中保存哈希树的根哈希、salt和偏移量。
因为VBMeta分区中的VBMeta结构是加密签名的,引导加载程序可以检查签名并验证它是由key0的所有者创建的(例如,通过嵌入key0的公共部分),从而信任用于boot, system, and vendor。
一个链式分区描述符用于授权-它包含授权所在分区的名称,以及这个特定分区上签名所信任的公钥。例如,考虑以下设置:
在这个设置中,xyz分区有一个用于完整性检查的哈希树.在hashtree之后是一个VBMeta结构,它包含带有hashtree元数据的hashtree描述符(根散列、salt、偏移量等),这个结构使用key1签名。最后,在分区的末尾是一个页脚,它具有VBMeta结构的偏移量。
这个设置允许引导装载程序使用链式分区描述符找到页脚的分区(使用链中的分区描述符的名称),轮流帮助定位VBMeta结构,并验证它是由key1签署(使用存储在链key1_pub分区描述符)。至关重要的是,因为有一个带有偏移量的页脚,所以xyz分区可以在vbmeta分区不需要任何更改的情况下进行更新。
VBMeta结构足够灵活,可以允许任何分区的散列描述符和散列树描述符驻留在VBMeta分区、用于完整性检查的分区(通过链分区描述符)或任何其他分区(通过链分区描述符)中。这允许广泛的组织和信任关系
2、回滚的保护(Rollback Protection)
AVB包含回滚保护,用于防止已知的安全缺陷。每个VBMeta结构都有一个回滚索引,如下所示:
这些数字称为rollback_index[n],随着安全缺陷的发现和修复,每个映像的值都会增加。此外,该设备存储最后看到的回滚索引在篡改明显的存储
这些被称为stored_rollback_index[n]
回滚保护是让设备拒绝一个镜像,除非rollback_index[n] >= stored_rollback_index[n]针对所有n,并让设备随着时间增加stored_rollback_index[n]。更新存储的回滚索引一节将详细讨论如何实现这一点。
3、A/B Support**
AVB被设计用于处理A/B,它要求在存储在描述符中的任何分区名称中永远不要使用A/B后缀。下面是一个有两个插槽的例子:
注意回滚索引在插槽之间的差异——对于插槽A,回滚索引是[42,101],对于插槽B,它们是[43,103]。
在版本1.1或更高版本中,avbtool支持——do_not_use_ab用于add_hash_footer和add_hashtree_footer操作。
这使得处理不使用a /B且不应该有前缀的分区成为可能。这对应于AVB_HASH[TREE]_DESCRIPTOR_FLAGS_DO_NOT_USE_AB标志。
4、The VBMeta Digest(VBMeta摘要)
VBMeta Digest是所有VBMeta结构的Digest,包括根结构(例如在VBMeta分区中)和链分区中的所有VBMeta结构。这个 Digest可以在构建时使用avbtool calculate_vbmeta_digest计算,也可以在运行时使用avb_slot_verify_data_calculate_vbmeta_digest()函数计算,它在内核命令行上也设置为androidboot.vbmeta。要了解详细信息,请参阅avb_slot_verify()文档。
这个Digest可以与libavb一起在加载的操作系统的用户空间中使用,以验证加载的vbmeta结构的真实性。对启动阶段的root-of-trust 和 / 或者 回滚索验证引非常有利。
此外,VBMeta digest 包含使用密钥认证验证硬件支持的密钥对(Verifying hardware-backed key pairs with Key Attestation)依赖方可以提取digest,并将其与已知良好操作系统的digest列表进行比较,如果找到这些digest,则可以对应用程序所运行的设备提供额外的保证。
2、工具和库
avbtool and libavb
1、avbtool
avbtool的主要工作是创建vbmeta.img。此image被设计成进入vbmeta分区(如果使用A/B,则进入讨论插槽,例如vbmeta_a或vbmeta_b),并具有最小的尺寸(for out-of-band updates)。
vbmeta映像是加密签名的,包含用于验证引导的验证数据(例如,cryptographic digests) 用于验证boot.img, system.img 和其他分区镜像
vbmeta映像还可以包含对存储验证数据的其他分区的引用,以及指示谁应该签署验证数据的公钥。这种间接性提供了授权,也就是说,它允许第三方通过在vbmeta.img中包含他们的公钥来控制给定分区上的内容,根据设计只需更新vbmeta就可以轻松撤销此权限。
为有问题的分区提供了新的描述符。也就是说vbmeta.img 包含了其他分区的验证数据,只要更新vbmeta就能够解决验证问题。(怎么有点像bootargs)
通过avbtool工具能够完成各个imge的验证数据放到vbmeta中存储。
除了avbtool之外,还提供了一个库libavb。
2、libavb
这个库在设备端执行所有验证,例如,它首先加载vbmeta分区,检查签名,然后boot partition分区进行验证,这个库用于bootloader还包括Android。
它对系统依赖性(参见avb_Sysdeps.h)以及boot loader或OS预期要实现的操作(参见avb_Ops.h)有一个简单的抽象。验证的主要入口点是avb_slot_verify()。
文件和目录
- libavb/
**image 验证的实现。**此代码被设计为高度可移植性,因此可以在尽可能多的上下文中使用。这段代码需要一个兼容c99的C编译器,此代码的一部分被认为是实现的内部代码,不应该在实现外部使用。例如,avb_rsa.[ch]和avb_sha.[ch]文件。平台预期提供的系统依赖项在avb_Sysdeps.h中定义。如果平台提供标准的C运行时avb_Sysdeps_Posix.c,则可以使用。 - libavb_atx/
用于验证公钥元数据的android-things扩展 - libavb_user/
包含适用于Android用户空间的AVBOPS实现。这在boot_control.avb和avbctl中使用 - libavb_ab/
botoloader 中 A/B的实现。注意:此代码不推荐使用,您必须定义
AVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED使用。 - boot_control/
Android引导控制HAL的一种实现,用于使用实验libavb_a b A/B堆栈的botolaoder。 - contrib/
包含其他项目中与AVB互操作所需的补丁。例如,contrib/linux/4.4有linux kernel 4.4的补丁,由git格式补丁生成 - avbtool
用python编写的工具,用于处理与已验证引导相关的映像 - test/
测试 abvtool, libavb, libavb_ab, and libavb_atx. - tools/avbctl/
包含可用于在Android运行时控制AVB的工具的源代码 - examples/uefi/
包含使用libavb/和libavb_ab/的基于UEFI的引导加载程序的源代码。
3、版本控制和兼容性
AVB使用一个版本号,有三个字段——主版本、次版本和子版本:
avb vbmetaimageheader结构(如avb_vbmeta_image.h中定义的)包含验证相关结构所需的libavb的主版本号和次版本号,这存储在必需的required_libavb_version_major和required_libavb_version_minor字段中。
此外,此结构包含一个文本字段,其中包含用于创建结构的avbtool版本,例如“avbtool 1.4.3”或“avbtool 1.4.3某些主板git-4589fbec”
注意,完全可以使用AvbVBMetaImageHeader结构
4、添加新功能
如果添加一个新特性,例如一个新的算法或一个新的描述符,那么avb_version.h和avbtool中的AVB_VERSION_MINOR必须被替换,AVB_VERSION_SUB应该被设置为零。
添加新单元必须检验:
- 只有将适当的命令/选项传递给avbtool时才使用该功能。
- required_version_minor 需要被设置,同时用print_required_libavb_version检验对错。如果AVB_VERSION_MINOR已经在上次的release中已经被改过,就不需要再次修改。
5、工具的使用-Using avbtool
vbmeta分区的内容可以生成如下:
$ avbtool make_vbmeta_image \ [--output OUTPUT] \ [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing_or_pub_key] \ [--public_key_metadata /path/to/pkmd.bin] [--rollback_index NUMBER] \ [--include_descriptors_from_image /path/to/image.bin] \ [--setup_rootfs_from_kernel /path/to/image.bin] \ [--chain_partition part_name:rollback_index_location:/path/to/key1.bin] \ [--signing_helper /path/to/external/signer] \ [--signing_helper_with_files /path/to/external/signer_with_files] \ [--print_required_libavb_version] \ [--append_to_release_string STR]
完整页脚包含整个分区的哈希,可以添加到现有的镜像如下:
$ avbtool add_hash_footer \ --partition_name PARTNAME --partition_size SIZE \ [--image IMAGE] \ [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing_or_pub_key] \ [--public_key_metadata /path/to/pkmd.bin] [--rollback_index NUMBER] \ [--hash_algorithm HASH_ALG] [--salt HEX] \ [--include_descriptors_from_image /path/to/image.bin] \ [--setup_rootfs_from_kernel /path/to/image.bin] \ [--output_vbmeta_image OUTPUT_IMAGE] [--do_not_append_vbmeta_image] \ [--signing_helper /path/to/external/signer] \ [--signing_helper_with_files /path/to/external/signer_with_files] \ [--print_required_libavb_version] \ [--append_to_release_string STR] \ [--calc_max_image_size] \ [--do_not_use_ab] \ [--use_persistent_digest]
可以将包含分区哈希树的根摘要和salt的完整页脚添加到现有映像中,如下所示。哈希树也附加到映像中:
$ avbtool add_hashtree_footer \ --partition_name PARTNAME --partition_size SIZE \ [--image IMAGE] \ [--algorithm ALGORITHM] [--key /path/to/key_used_for_signing_or_pub_key] \ [--public_key_metadata /path/to/pkmd.bin] [--rollback_index NUMBER] \ [--hash_algorithm HASH_ALG] [--salt HEX] [--block_size SIZE] \ [--include_descriptors_from_image /path/to/image.bin] \ [--setup_rootfs_from_kernel /path/to/image.bin] \ [--setup_as_rootfs_from_kernel] \ [--output_vbmeta_image OUTPUT_IMAGE] [--do_not_append_vbmeta_image] \ [--do_not_generate_fec] [--fec_num_roots FEC_NUM_ROOTS] \ [--signing_helper /path/to/external/signer] \ [--signing_helper_with_files /path/to/external/signer_with_files] \ [--print_required_libavb_version] \ [--append_to_release_string STR] \ [--calc_max_image_size] \ [--do_not_use_ab] \ [--use_persistent_digest]
使用resize_image命令可以更改带有完整页脚的镜像的大小:
$ avbtool resize_image \ --image IMAGE \ --partition_size SIZE
可以从镜像中删除镜像上的完整性页脚。可以选择保留hashtree。
avbtool erase_footer --image IMAGE [--keep_hashtree]
对于散列和哈希树映像,还可以通过——output_vbmeta_image选项将vbmeta结构写入外部文件,还可以指定不将vbmeta结构和页脚添加到正在操作的映像中。
83/5000
镜像中的hashtree和FEC数据可以通过以下命令进行归零:
avbtool zero_hashtree --image IMAGE
这对于在运行时交换镜像图像的大小,以便重新计算hashtree和fec非常有用。
如果这样做,hashtree和FEC数据被设置为零,除了前八个字节被设置为魔数的ZeRoHaSH之外。hashtree或FEC数据或两者都可以以这种方式归零,因此应用程序应该检查这两个地方的魔数之处。
应用程序可以使用这种魔数来检测是否需要重新计算。
在使用avbtool add_hash_footer或avbtool add_hashtree_footer后,计算最大的镜像尺寸用来适应给定的尺寸,可以用–calc_max_image_size:
$ avbtool add_hash_footer --partition_size $((10*1024*1024)) \ --calc_max_image_size 10416128 $ avbtool add_hashtree_footer --partition_size $((10*1024*1024)) \ --calc_max_image_size 10330112
要计算放在vbmeta结构中的所需libavb版本,在使用make_vbmeta_image、add_hash_footer和add_hashtree_footer命令时加上——print_required_libavb_version选项:
$ avbtool make_vbmeta_image \ --algorithm SHA256_RSA2048 --key /path/to/key.pem \ --include_descriptors_from_image /path/to/boot.img \ --include_descriptors_from_image /path/to/system.img \ --print_required_libavb_version 1.0
可以在make_vbmeta_image、add_hash_footer和add_hashtree_footer命令中使用——signing_helper选项来指定用于签名散列的任何外部程序。
要签名的数据(包括填充,如PKCS1-v1.5)通过STDIN提供,签名的数据通过STDOUT返回。如果—signing_helper出现在命令行中,—key选项只需要包含一个公钥。签名助手的参数是算法和公钥。如果签名助手使用非零的退出代码退出,则意味着失败
/path/to/my_signing_program SHA256_RSA2048 /path/to/publickey.pem
signing_helper_with_files类似于——signing_helper,只是使用临时文件与helper通信,而不是使用STDIN和STDOUT.这在签名助手使用将诊断结果输出到STDOUT而不是STDERR上的代码的情况下非常有用。下面是一个示例调用:
/path/to/my_signing_program_with_files SHA256_RSA2048 \ /path/to/publickey.pem /tmp/path/to/communication_file
其中最后一个位置参数是包含要签名的数据的文件。helper应该在这个文件中编写签名。
可以使用append_vbmeta_image命令将整个vbmeta blob追加到另一个镜像的末尾。这是有用的情况下,当不使用任何vbmeta分区,例如:
$ cp boot.img boot-with-vbmeta-appended.img $ avbtool append_vbmeta_image \ --image boot-with-vbmeta-appended.img \ --partition_size SIZE_OF_BOOT_PARTITION \ --vbmeta_image vbmeta.img $ fastboot flash boot boot-with-vbmeta-appended.img
verify_image命令可用于同时验证多个镜像文件的内容。当在镜像上调用时,执行以下检查:
- 如果镜像具有vbmeta结构,则将根据嵌入的公钥检查签名。如果镜像看起来不像vbmeta.img,则会查找页脚并在存在时使用
- 如果传递了选项–key,则需要一个.pem文件,并检查所述vbmeta结构中嵌入的公钥是否与给定的密钥匹配
- vbmeta结构中的所有描述符都按以下方式检查:
- 对于散列描述符,将加载与分区名对应的映像文件,并将其digest与描述符中的digest进行检查
- 对于hashtree描述符,加载与分区名对应的映像文件,计算hashtree,并将其根digest与描述符中的根digest进行比较
- 对于链接分区描述符,它的内容将与需要通过–expected\u chain\u分区选项传入的内容进行比较。此选项的格式与–chain_分区选项的格式类似。如果链分区描述符没有–预期的\链\分区描述符,则检查失败。
下面是一个示例,boot.img 和 system.img 的digests 存放在vbmeta.img,用my_key.pem签名,它还检查分区foobar的链分区是否使用回滚索引8,以及AVB格式的公钥是否与文件foobar_vendor_key.avbpubkey匹配:
$ avbtool verify_image \ --image /path/to/vbmeta.img \ --key my_key.pem \ --expect_chained_partition foobar:8:foobar_vendor_key.avbpubkey Verifying image /path/to/vbmeta.img using key at my_key.pem vbmeta: Successfully verified SHA256_RSA4096 vbmeta struct in /path_to/vbmeta.img boot: Successfully verified sha256 hash of /path/to/boot.img for image of 10543104 bytes system: Successfully verified sha1 hashtree of /path/to/system.img for image of 1065213952 bytes foobar: Successfully verified chain partition descriptor matches expected data
在本例中,verify_image命令验证文件vbmeta.img,boot.img, and system.img 在路劲/path/to。给定映像的目录和文件扩展名(例如/path/to/vbmeta.img)与描述符中的分区名一起使用。
98/5000
verify_image命令还可用于检查自定义签名helper是否按预期工作。
calculate_vbmeta_digest命令可用于同时计算多个镜像文件的vbmeta digest 。结果在STDOUT或提供的路径上打印为十六进制字符串(使用——output选项)。
$ avbtool calculate_vbmeta_digest \ --hash_algorithm sha256 \ --image /path/to/vbmeta.img a20fdd01a6638c55065fe08497186acde350d6797d59a55d70ffbcf41e95c2f5
在本例中,calculate_vbmeta_digest命令加载vbmeta.img文件。如果这个镜像有一个或多个链分区描述符,那么就使用与verify_image命令相同的逻辑来加载这些文件(例如,它假设目录和文件扩展名与给定的映像相同)。加载完所有vbmeta结构后,将计算digest (使用由——hash_algorithm选项提供的哈希算法)并打印出来
6、建立系统集成(Build System Integration)
在Android中,AVB由BOARD_AVB_ENABLE变量启用
BOARD_AVB_ENABLE := true
这将使构建系统创建vbmeta.img。
这将包含boot.img散列描述符,hashtree for system.img,一个kernel-cmdline的描述符给开启dm-verity对于system.img来说,并添加hash-tree到system.img。如果构建系统设置为一个或多个vendor.img / product.img / odm.img /product_services.img。它们各自的hash-tree也将分别附加到镜像像中,它们的hash-tree描述符将包含在vbmeta.img。
默认情况下,算法sha256 rsa4096与来自外部/avb/test/data目录的测试密钥一起使用。这可以由board_avb_算法和board_avb_key_路径变量覆盖,例如4096位RSA密钥和SHA-512:
BOARD_AVB_ALGORITHM := SHA512_RSA4096 BOARD_AVB_KEY_PATH := /path/to/rsa_key_4096bits.pem
这里是不是很眼熟。
请记住,此密钥的公共部分需要对希望验证生成的镜像的设备的引导加载程序可用。
使用avbtool extract_public_key以期望的格式提取密钥(下面是AVB_pk)。如果设备使用与AVB_pk不同的信任根,则可以使用——public_key_metadata选项来嵌入一个blob(下面的AVB_pkmd),该blob可用于派生AVB_pk。在验证插槽时,AVB_pk和AVB_pkmd都传递给**validate_vbmeta_public_key()**操作。
Some devices may support the end-user configuring the root of trust to use, see the Device Specific Notes section for details.
Devices can be configured to create additional vbmeta partitions as chained partitions in order to update a subset of partitions without changing the top-level vbmeta partition. For example, the following variables create vbmeta_system.img as a chained vbmeta image that contains the hash-tree descriptors for system.img and product_services.img. vbmeta_system.img itself will be signed by the specified key and algorithm.
某些设备可能支持最终用户配置要使用的信任根,有关详细信息,请参阅设备特定说明部分。 设备可以配置为创建额外的vbmeta分区作为链接分区,以便在不更改顶级vbmeta分区的情况下更新分区的子集。例如,以下变量创建vbmeta_system。img作为一个链接的vbmeta图像,其中包含系统的哈希树描述符。img和product_services.img。vbmeta_系统。img本身将由指定的密钥和算法签名。
BOARD_AVB_VBMETA_SYSTEM := system product_services BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048 BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
请注意:
hash-tree descriptor for system.img and product_services.img 将被包含vbmeta_system.img,而不是在vbmeta.img。使用上述设置,system.img, product_services.img and vbmeta_system.img能够独立更新—而是作为一个组——其他分区的更新,或者作为更新所有分区的传统更新的一部分。
目前编译系统支持编译 chained vbmeta images of vbmeta_system.img (BOARD_AVB_VBMETA_SYSTEM) and vbmeta_vendor.img (BOARD_AVB_VBMETA_VENDOR).
为了防止回滚攻击,应该定期增加回滚索引。可以使用BOARD_AVB_ROLLBACK_INDEX变量设置回滚索引:
BOARD_AVB_ROLLBACK_INDEX := 5
如果不设置此值,回滚索引默认为0。
变量BOARD_AVB_MAKE_VBMETA_IMAGE_ARGS可用于指定传递给avbtool make_vbmeta_image的其他选项。这里使用的典型选项包括— —prop、— —prop_from_file、— —chain_partition、— —public_key_metadata和— —signing_helper。
变量BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS可用于为boot.img指定传递给avbtool add_hash_footer的其他选项。这里使用的典型选项包括— —hash_algorithm和— —salt。
变量BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS可用于为system.img指定传递给avbtool add_hashtree_footer的其他选项。这里使用的典型选项包括— —hash_algorithm、— —salt、— —block_size和— —do_not_generate_fec。
变量BOARD_AVB_VENDOR_ADD_HASHTREE_FOOTER_ARGS可用于为vendor.img指定传递给avbtool add_hashtree_footer的其他选项。这里使用的典型选项包括— —hash_algorithm、— —salt、— —block_size和— —do_not_generate_fec。
变量BOARD_AVB_DTBO_ADD_HASH_FOOTER_ARGS可用于为dtd .img指定传递给avbtool add_hash_footer的其他选项。这里使用的典型选项包括— —hash_algorithm和— —salt。
7、Device Integration(设备集成)
本节讨论将libavb与设备引导加载程序集成的建议和最佳实践。重要的是要强调,这些只是建议,所以这个词的使用必须谨慎
1、System Dependencies (系统依赖关系)
libavb库以某种方式编写,因此它可以移植到任何使用C99编译器的系统。
它不需要标准的C库,但是引导加载程序必须实现libavb所需的一组简单的系统原语,如avb_malloc()、avb_free()和avb_print()。
除了系统原语之外,libavb还通过提供的AvbOps结构与引导加载程序进行接口。这包括从分区读写数据、读写回滚索引、检查用于签名的公钥是否应该被接受等操作。
2、Locked and Unlocked mode
AVB被设计成支持Android中使用的设备处于锁定状态或解锁状态的概念。
在AVB上下文中,锁定状态意味着验证错误是致命的,而在解锁状态则不是。如果设备未锁定,则在avb_slot_verify()的flags参数中传递AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR标志,并处理验证错误,包括:
AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX
非致命。如果设备处于锁定状态,不要在avb_slot_verify()的flags参数中传递AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR标志,只将AVB_SLOT_VERIFY_RESULT_OK视为非致命的。
在Android上,设备状态可以通过fastboot界面来改变,比如fastboot闪烁锁定(切换到锁定状态)和fastboot闪烁解锁(切换到解锁状态)。
当从锁定状态转换到解锁状态(包括userdata分区和任何NVRAM空间)时,必须清除所有用户数据。此外,必须清除所有stored_rollback_index[n]位置(所有元素必须设置为零)。
类似的操作(擦除userdata、NVRAM空间和stored_rollback_index[n]位置)在从解锁到锁定的转换过程中也会发生。如果设备需要使用全磁盘加密,则需要较少的擦除以解锁锁定。根据设备的形状和预期用途,应该提示用户在删除任何数据之前进行确认。
3、Tamper-evident Storage-防篡改存储
在本文档中,tamper-evident意味着可以检测HLOS是否篡改了数据,例如,是否覆盖了数据。
Tamper-evident storage 必须用于存储的回滚索引、用于验证的键、设备状态(无论设备是锁定的还是未锁定的)和named persistent values。
如果检测到篡改,相应的AvbOps操作应该失败,例如返回AVB_IO_RESULT_ERROR_IO。尤其重要的是,不能篡改验证密钥,因为它们代表信任根。
如果验证键是可变的,则只能由最终用户设置,例如,在工厂、商店或最终用户之前的任何中间点都不能设置验证键。此外,只能在设备处于解锁状态时设置或清除密钥。
4、命名持久值-Named Persistent Values
AVB 1.1引入了对指定持久性值的支持,这些值必须是明显的篡改值,并允许AVB存储任意键值对。Integrators 可以将对这些值的支持限制为一组固定的知名名称、最大值大小和/或值的最大数量。
5、持续性消化-Persistent Digests
使用 Persistent Digests 对分区来说digest (root digest in the case of a hashtree)不存储在描述符,但是存储named persistent value。这允许AVB验证不同设备的配置数据。当设备处于锁定状态时,不能修改 persistent digest,除非digest 不存在。
若要指定描述符应使用Persistent Digests,将- -use_persistent_digest选项用于add_hash_footer或add_hashtree_foote r avbtool操作。在验证描述符时,AVB将在命名的Persistent Digests AVB .persistent_digest.$(partition_name)中而不是在描述符本身中查找Digests 。
对于使用Persistent Digests的hashtree描述符,可以使用$(AVB_FOO_ROOT_DIGEST)形式的令牌将digest 值替换为内核命令行描述符,其中“FOO”是大写分区名,在本例中是“FOO”分区的名称。标记将被十六进制形式的digest 替换。
默认情况下,当— —use_persistent_digest选项与add_hash_footer或add_hashtree_footer一起使用时,avbtool将生成一个不含salt的描述符,而不是生成一个与Digests长度相等的随机salt的典型默认值。这是因为Digests值存储在持久存储中,因此不能随时间而更改。另一种选择是手动提供一个随机的salt using — —salt,但是一旦编写了持久性消化值,这个salt就需要在设备的生命周期中保持不变。
6、更新存储的回滚索引
为了回滚保护工作,引导加载程序需要在将控制转移到HLOS之前更新设备上的stored_rollback_indexes[n]数组。如果不使用A/B,这很简单——在引导之前,只需将其更新为AVB元数据中的插槽。在伪代码中是这样的:
// The |slot_data| parameter should be the AvbSlotVerifyData returned // by avb_slot_verify() for the slot we're about to boot. // bool update_stored_rollback_indexes_for_slot(AvbOps* ops, AvbSlotVerifyData* slot_data) { for (int n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) { uint64_t rollback_index = slot_data->rollback_indexes[n]; if (rollback_index > 0) { AvbIOResult io_ret; uint64_t current_stored_rollback_index; io_ret = ops->read_rollback_index(ops, n, ¤t_stored_rollback_index); if (io_ret != AVB_IO_RESULT_OK) { return false; } if (rollback_index > current_stored_rollback_index) { io_ret = ops->write_rollback_index(ops, n, rollback_index); if (io_ret != AVB_IO_RESULT_OK) { return false; } } } } return true; }
然而,如果使用A/B必须采取更多的注意,仍然允许设备回到旧插槽,如果更新不起作用。
对于像Android这样的HLOS,只有在发现更新的OS版本不能工作时才支持回滚,stored_rollback_index[n]应该只从A/B元数据中标记为成功的槽中更新。它的伪代码如下:is_slot_is_marked_as_success()来自正在使用的A/B堆栈:
if (is_slot_is_marked_as_successful(slot->ab_suffix)) { if (!update_stored_rollback_indexes_for_slot(ops, slot)) { // TODO: handle error. } }
对于可以回滚到以前版本的HLOS, stored_rollback_index[n]应该设置为允许所有可引导槽引导的最大可能值。这种方法在AVB的实验性(现在已被弃用)A/B堆栈libavb_ab中实现,请参见avb_ab_flow()实现。注意,这需要在每次引导时验证所有可引导插槽,这可能会影响引导时间。
推荐Bootflow
注:
- 该设备将搜索所有的A/B插槽,直到找到一个有效的操作系统来引导。在锁定状态下被拒绝的插槽可能不会在未锁定状态下被拒绝(例如,当未锁定任何键时可以使用,并且允许回滚索引失败),因此用于选择插槽的算法取决于设备处于什么状态。
- 如果没有找到有效的操作系统(即没有可引导的A/B插槽),则设备无法启动,必须进入修复模式。它是依赖于设备的。如果设备有屏幕,它必须将这种状态传递给用户。
- 如果设备被锁定,则只接受由嵌入式验证密钥签名的操作系统(请参阅前一节)。此外,存储在已验证映像中的rollback_index[n]必须大于或等于设备上stored_rollback_index[n]中的值(对于所有n),并且stored_rollback_index[n]数组预计将按照前一节中指定的方式更新。
- 如果用于验证的密钥是由最终用户设置的,并且设备有一个屏幕,那么它必须显示一个带有密钥指纹的警告,以表示设备正在引导一个自定义OS。在启动过程继续之前,警告必须显示至少10秒。如果设备没有屏幕,则必须使用其他方式来表示设备正在引导自定义OS(灯杆、led等)。
- 如果设备未锁定,则不需要检查用于签署操作系统的密钥,也不需要检查或更新设备上的rollbackstored_rollback_index[n]。因此,必须始终向用户显示关于未发生验证的警告。
- 这取决于设备如何实现,因为它取决于设备的形状因素和预期用途。如果设备有屏幕和按钮(例如,如果是手机),则警告至少要显示10秒,然后引导过程才会继续。如果设备没有屏幕,则必须使用其他方式来表示设备已解锁(灯光条、led灯等)。
7、处理dm-verity错误
按照设计,哈希树验证错误是由HLOS而不是引导加载程序检测到的。AVB提供了一种方法来指定应该如何通过avb_slot_verify()函数中的hashtree_error_mode参数来处理错误。可能的值有
- AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE表示HLOS将使当前插槽无效并重新启动。在具有A/B的设备上,这将导致尝试引导另一个插槽(如果它被标记为可引导),或者可能导致无法引导操作系统的模式(例如某种形式的修复模式)。在Linux中,这需要使用CONFIG_DM_VERITY_AVB构建内核。
- AVB_HASHTREE_ERROR_MODE_RESTART意味着操作系统将在当前插槽无效的情况下重启。无条件使用此模式时要小心,因为如果每次引导都遇到相同的hashtree验证错误,那么它可能会引入引导循环。
- AVB_HASHTREE_ERROR_MODE_EIO表示将向应用程序返回一个EIO错误。
- AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO表示根据状态使用重启或EIO模式。该模式实现了一个状态机,默认情况下使用RESTART,当AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION传递给avb_slot_verify()时,模式转换为EIO。当检测到一个新的操作系统时,设备将切换回重启模式。
To do this persistent storage is needed - specifically this means that the passed in AvbOps will need to have the read_persistent_value() and write_persistent_value() operations implemented. The name of the persistent value used is avb.managed_verity_mode and 32 bytes of storage is needed.
要做到这一点,需要持久存储——具体来说,这意味着传入的AvbOps需要实现read_persistent_value()和write_persistent_value()操作。使用的持久值的名称是avb.managed_verity_mode,需要32字节的存储空间。
- AVB_HASHTREE_ERROR_MODE_LOGGING意味着错误将被记录,损坏的数据可能会返回给应用程序。此模式应仅用于诊断和调试。除非允许验证错误,否则不能使用它。
hashtree_error_mode中传递的值实际上只是通过androidboot传递给HLOS。veritymode androidboot.veritymode。管理和androidboot.vbmeta。invalidate_on_error内核命令行参数如下:
此表的唯一例外是,如果在顶级vbmeta中设置了avb_vbmeta_image_flags_hashtree_disabled标志,则androidboot.veritymode设置为disabled,androidboot.veritymode.managed和androidboot.vbmeta.invalidate_on_error未设置。
8、Android特定集成(Android Specific Integration)
On Android, the boot loader must set the androidboot.verifiedbootstate parameter on the kernel command-line to indicate the boot state. It shall use the following values: green: If in LOCKED state and the key used for verification was not set by the end user. yellow: If in LOCKED state and the key used for verification was set by the end user. orange: If in the UNLOCKED state.
在Android上,引导加载程序必须设置androidboot。内核命令行上的verifiedbootstate参数,用于指示引导状态。应使用以下值: 绿色:如果处于锁定状态,且最终用户未设置用于验证的密钥。 黄色:如果处于锁定状态,并且用于验证的密钥由最终用户设置。 橙色:如果处于解锁状态。