| <html devsite> |
| <head> |
| <title>Verifying Boot</title> |
| <meta name="project_path" value="/_project.yaml" /> |
| <meta name="book_path" value="/_book.yaml" /> |
| </head> |
| <body> |
| <!-- |
| Copyright 2018 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| //www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| |
| <p> |
| 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 <code>boot</code> partition), the device tree (loaded |
| from the <code>dtbo</code> partition), <code>system</code> partition, |
| <code>vendor</code> partition, and so on. |
| </p> |
| |
| <p> |
| Small partitions, such as <code>boot</code> and <code>dtbo</code>, 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 |
| <em>expected hash value</em>. If the value doesn't match, Android won't load. |
| For more details, see <a href="/security/verifiedboot/boot-flow">Boot Flow</a>. |
| </p> |
| <p> |
| 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 <em>expected root hash value</em>. |
| Android includes the <a href="/security/verifiedboot/dm-verity">dm-verity |
| driver</a> to verify larger partitions. If at some point the calculated root |
| hash doesn't match the <em>expected root hash value</em>, the data is not used |
| and Android enters an error state. For more details, see |
| <a href="/security/verifiedboot/boot-flow#dm-verity-corruption">dm-verity |
| corruption</a>. |
| </p> |
| <p> |
| The <em>expected hashes</em> 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 |
| <a href="/security/verifiedboot/avb">Android Verified Boot</a> for details. |
| </p> |
| |
| <h2 id="rollback-protection">Rollback protection</h2> |
| <p> |
| 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. |
| </p> |
| <p> |
| The protection against this class of attacks is called <em>Rollback |
| Protection</em>. 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. |
| </p> |
| <p> |
| For more details on how AVB handles rollback protections, see the AVB |
| <a href="https://android.googlesource.com/platform/external/avb/+/master/README.md#Rollback-Protection" |
| class="external">README</a>. |
| </p> |
| |
| <h2 id="handling-verification-errors">Handling verification errors</h2> |
| <p> |
| Verification can fail either at boot time (such as, if the calculated hash on |
| <code>boot</code> partition doesn't match the expected hash) or at run time |
| (such as, if dm-verity encounters a verification error on the |
| <code>system</code> partition). If verification fails at boot time, the device |
| cannot boot and the end user needs to go through steps to recover the device. |
| </p> |
| <p> |
| If verification fails at run-time the flow is a bit more complicated. If the |
| device uses dm-verity, it should be configured in <code>restart</code> mode. In |
| <code>restart</code> 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 |
| (<code>eio</code>) mode and stay in this mode until a new update has been |
| installed. |
| </p> |
| <p> |
| When booting in <code>eio</code> 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 |
| <code>eio</code> 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. |
| </p> |
| <p> |
| 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 <code>restart</code> mode. |
| </p> |
| </body> |
| </html> |