Verifying Boot

Verified boot requires cryptographically verifying all executable code and data that is part of the Android version being booted before it is used. This includes the kernel (loaded from the boot partition), the device tree (loaded from the dtbo partition), system partition, vendor partition, and so on.

Small partitions, such as boot and dtbo, that are read only once are typically verified by loading the entire contents into memory and then calculating its hash. This calculated hash value is then compared to the expected hash value. If the value doesn't match, Android won't load. For more details, see Boot Flow.

Larger partitions that won't fit into memory (such as, file systems) may use a hash tree where verification is a continuous process happening as data is loaded into memory. In this case, the root hash of the hash tree is calculated during run time and is checked against the expected root hash value. Android includes the dm-verity driver to verify larger partitions. If at some point the calculated root hash doesn't match the expected root hash value, the data is not used and Android enters an error state. For more details, see dm-verity corruption.

The expected hashes are typically stored at either the end or beginning of each verified partition, in a dedicated partition, or both. Crucially, these hashes are signed (either directly or indirectly) by the root of trust. As an example, the AVB implementation supports both approaches, see Android Verified Boot for details.

Rollback protection

Even with a completely secure update process, it's possible for a non-persistent Android kernel exploit to manually install an older, more vulnerable version of Android, reboot into the vulnerable version, and then use that Android version to install a persistent exploit. From there the attacker permanently owns the device and can do anything, including disabling updates.

The protection against this class of attacks is called Rollback Protection. Rollback protection is typically implemented by using tamper-evident storage to record the most recent version of the Android and refusing to boot Android if it's lower than the recorded version. Versions are typically tracked on a per-partition basis.

For more details on how AVB handles rollback protections, see the AVB README.

Handling verification errors

Verification can fail either at boot time (such as, if the calculated hash on boot partition doesn't match the expected hash) or at run time (such as, if dm-verity encounters a verification error on the system partition). If verification fails at boot time, the device cannot boot and the end user needs to go through steps to recover the device.

If verification fails at run-time the flow is a bit more complicated. If the device uses dm-verity, it should be configured in restart mode. In restart mode, if a verification error is encountered, the device is immediately restarted with a specific flag set to indicate the reason. The boot loader should notice this flag and switch dm-verity over to use I/O Error (eio) mode and stay in this mode until a new update has been installed.

When booting in eio mode, the device shows an error screen informing the user that corruption has been detected and the device may not function correctly. The screen shows until the user dismisses it. In eio mode the dm-verity driver will not restart the device if a verification error is encountered, instead an EIO error is returned and the application needs to deal with the error.

The intent is that either the system updater will run (so a new OS without corruption errors can be installed) or the user can get as much of their data off the device as possible. Once the new OS has been installed, the boot loader notices the newly installed OS and switches back to restart mode.