El inicio verificado requiere la verificación criptográfica de todo el código ejecutable y los datos que forman parte de la versión de Android que se está iniciando antes de que se use. Esto incluye el kernel (cargado desde la partición boot), el árbol de dispositivos (cargado desde la partición dtbo), la partición system, la partición vendor y así sucesivamente.
Por lo general, las particiones pequeñas, como boot y dtbo, que se leen solo una vez, se verifican cargando todo el contenido en la memoria y, luego, calculando su hash. Luego, este valor de hash calculado se compara con el valor de hash esperado. Si el valor no coincide, Android no se cargará.
Para obtener más detalles, consulta Flujo de inicio.
Las particiones más grandes que no caben en la memoria (como los sistemas de archivos) pueden usar un árbol hash en el que la verificación es un proceso continuo que ocurre a medida que se cargan los datos en la memoria. En este caso, el hash raíz del árbol hash se calcula durante el tiempo de ejecución y se compara con el valor de hash raíz esperado. Android incluye el controlador dm-verity para verificar particiones más grandes. Si en algún momento el hash raíz calculado no coincide con el valor de hash raíz esperado, no se usan los datos y Android entra en un estado de error. Para obtener más detalles, consulta Corrupción de dm-verity.
Por lo general, los hashes esperados se almacenan al final o al principio de cada partición verificada, en una partición dedicada o en ambos. Es fundamental que la raíz de confianza firme estos hashes (ya sea directa o indirectamente). Por ejemplo, la implementación de AVB admite ambos enfoques. Consulta Android Verified Boot para obtener más detalles.
Protección contra reversiones
Incluso con un proceso de actualización completamente seguro, es posible que una vulnerabilidad del kernel de Android no persistente instale manualmente una versión anterior y más vulnerable de Android, se reinicie en la versión vulnerable y, luego, use esa versión de Android para instalar una vulnerabilidad persistente. A partir de ahí, el atacante es propietario permanente del dispositivo y puede hacer cualquier cosa, incluida la inhabilitación de actualizaciones.
La protección contra esta clase de ataques se denomina protección contra reversiones. Por lo general, la protección contra reversiones se implementa mediante el uso de almacenamiento a prueba de manipulaciones para registrar la versión más reciente de Android y negarse a iniciar Android si es inferior a la versión registrada. Por lo general, se realiza un seguimiento de las versiones por partición.
Para obtener más detalles sobre cómo AVB controla las protecciones contra reversiones, consulta el archivo README de AVB .
Cómo controlar los errores de verificación
La verificación puede fallar en el momento del inicio (por ejemplo, si el hash calculado en la partición boot no coincide con el hash esperado) o en el tiempo de ejecución (por ejemplo, si dm-verity encuentra un error de verificación en la partición system). Si la verificación falla en el momento del inicio, el dispositivo no puede iniciarse y el usuario final debe seguir los pasos para recuperarlo.
Si la verificación falla en el tiempo de ejecución, el flujo es un poco más complicado. Si el dispositivo usa dm-verity, debe configurarse en el modo restart. En el modo restart, si se encuentra un error de verificación, el dispositivo se reinicia de inmediato con una marca específica establecida para indicar el motivo. El cargador de arranque debe notar esta marca y cambiar dm-verity para usar el modo de error de E/S (eio) y permanecer en este modo hasta que se instale una nueva actualización.
Cuando se inicia en el modo eio, el dispositivo muestra una pantalla de error que informa al usuario que se detectó corrupción y que es posible que el dispositivo no funcione correctamente. La pantalla se muestra hasta que el usuario la descarta. En el modo eio, el controlador dm-verity no reiniciará el dispositivo si se encuentra un error de verificación. En su lugar, se muestra un error EIO y la app debe ocuparse del error.
El objetivo es que se ejecute el actualizador del sistema (para que se pueda instalar un nuevo SO sin errores de corrupción) o que el usuario pueda quitar la mayor cantidad posible de sus datos del dispositivo. Una vez que se instala el nuevo SO, el cargador de arranque nota el SO recién instalado y vuelve al modo restart.