Android Verified Boot (AVB)

From postmarketOS

What is it

AVB is implementation of verified boot process, current version (since Android 8 Oreo) is called AVB 2.0. Verified boot is a process of assuring the end user of the integrity of the software running on a device. It typically starts with a read-only portion of the device firmware which loads code and executes it only after cryptographically verifying that the code is authentic. It also helps in implementing rollback protection.

Implementation details

It is implemented inside libavb - simple C library, that can be used both inside userspace programs (Android's avbctl?) and by kernel space (bootloader). Heart of the system is VBMeta struct, which contains both checksums of contents of several important partitions, and the public key used to cryptographically sign them. Several important partitions include boot, recovery, dtbo, vendor and system. Public key is meant to be verified by bootloader to the one that is embedded inside it, to be trusted.

The vbmeta struct is described in libavb/avb_vbmeta_image.h. It contains header, auth data (reference to public key) and references to descriptors for several paritions. Read the comment above its declaration for more info.

Verified boot process

When device is locked, bootloader loads vbmeta struct from vbmeta partition. And then it calls avb_slot_verify() for each partition mentioned inside vbmeta struct. If some partition fails this check, then bootloader can know that system files were modified. From the result of this test bootloader sets boot state:

  • YELLOW: Warning screen for LOCKED devices with custom root of trust set
  • ORANGE: Warning screen for UNLOCKED devices
  • RED (eio): Warning screen for dm-verity corruption
  • RED (no os found): No valid OS found

And then it can display warnings on the screen, and reflect boot state in kernel command line, like for example androidboot.verifiedbootstate=orange.

For unlocked device bootloader skips the verification for boot partition, but can still verify others. See relevant LK aboot code.

Example bootloader debug output regarding verified boot process with original boot.img, unlocked device:

Booting Into Mission Mode
avb_slot_verify.c:432: DEBUG: Loading vbmeta struct from partition 'vbmeta'.
Partition found: vbmeta
avb_slot_verify.c:186: DEBUG: dtbo: Loading entire partition.
Partition found: dtbo
avb_slot_verify.c:186: DEBUG: boot: Loading entire partition.
Partition found: boot
Device is unlocked, Skipping boot verification
State: Unlocked, AvbSlotVerify returned OK, continue boot
VB2: Authenticate complete! boot state is: orange
VB2: boot state: orange(1)

Example bootloader debug output regarding verified boot process with custom boot.img, unlocked device:

Booting Into Mission Mode
avb_slot_verify.c:432: DEBUG: Loading vbmeta struct from partition 'vbmeta'.
Partition found: vbmeta
avb_slot_verify.c:186: DEBUG: dtbo: Loading entire partition.
Partition found: dtbo
avb_slot_verify.c:186: DEBUG: boot: Loading entire partition.
Partition found: boot
avb_slot_verify.c:242: ERROR: boot: Hash of data does not match digest in descriptor.
State: Unlocked, AvbSlotVerify returned ERROR_VERIFICATION, continue boot
VB2: Authenticate complete! boot state is: orange
VB2: boot state: orange(1)
Display menu is not enabled!
Device is unlocked, Skipping boot verification
VB2: BootState = 1

Using avbtool

avbtool is a python script that can be used to view, create and edit images for AVB process.

Use avbtool --help to get list of commands, and avbtool <command> --help to view help on specific command.

Examining contents of stock images

avbtool info_image command can be used to query headers of vbmeta struct, or for partition images it will show contents of vbmeta footer signature. Example usage:

avbtool info_image --image /path/to/vbmeta.img
avbtool info_image --image /path/to/boot.img

Signing & checksumming the partitions

For small partition images (boot, dtbo, recovery) you can add checksum/signature with: avbtool add_hash_footer.

For larger partitions (vendor, system) you should use avbtool add_hashtree_footer. Arguments are the same. Example:

avbtool add_hash_footer --partition_name PARTITION_NAME --partition_size PARTITION_SIZE --image IMAGE [--key /path/to/key_used_for_signing_or_pub_key]
avbtool add_hash_footer --partition_name boot --partition_size 67108864 --image boot.img-postmarketos-qcom-sdm660

PARTITION_NAME will be written into vbmeta struct later and used by bootloader during verification process.

PARTITION_SIZE should be equal to partition size in bytes. Image file will be padded to this size and vbmeta footer will be addded at the end of it.

Creating vbmeta image

vbmeta.img is an image file that is intended to be flashed into vbmeta partition. It is used by bootloader as source for checksums in verification process.

First you should checksum/sign all other partition images that are part of your AVB process (for example, boot, system, etc)! See example just above.

avbtool make_vbmeta_image Is the command that you will use in this case:

avbtool make_vbmeta_image \
    --output my_vbmeta.img \
    --padding_size 4096 \
    --include_descriptors_from_image ./boot.img-postmarketos-qcom-sdm660 \
    --include_descriptors_from_image ./path/to/some_another_image.img \
    ...
    [--key /path/to/key_used_for_signing_or_pub_key]

This command will create my_vbmeta.img file, at least 4096 bytes in size, that will contain hash/hashtree descriptors from all the partition images specified in --include_descriptors_from_image parameters.

Disabling verified boot

To disable verified boot you should create an empty vbmeta.img, which does not contain any hash/hashtree desriptors and specified a special flag in vbmeta header. The command for it should look like this:

avbtool make_vbmeta_image --flags 2 --padding_size 4096 --output vbmeta_disabled.img

Mysterious flag 2 is AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED, which is documented as:

AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: If this flag is set,
verification will be disabled and descriptors will not be parsed.

Example bootloader output when booting with vbmeta_disabled.img flashed to vbmeta partition:

Booting Into Mission Mode
avb_slot_verify.c:432: DEBUG: Loading vbmeta struct from partition 'vbmeta'.
Partition found: vbmeta
avb_slot_verify.c:544: ERROR: vbmeta: Error verifying vbmeta image: OK_NOT_SIGNED
avb_slot_verify.c:704: DEBUG: vbmeta: VERIFICATION_DISABLED bit is set.
avb_slot_verify.c:317: DEBUG: boot: Loading entire partition.
Partition found: boot
avb_slot_verify.c:317: DEBUG: dtbo: Loading entire partition.
Partition found: dtbo
State: Unlocked, AvbSlotVerify returned ERROR_VERIFICATION, continue boot
VB2: Authenticate complete! boot state is: orange
VB2: boot state: orange(1)

Note VERIFICATION_DISABLED bit is set. Apparently bootloader can detect that verification is disabled, but its reaction to this mode may be device specific?

Links