3 votos

¿Cómo update_engine valida una imagen de actualización diferencial con dm-verity habilitado?

Estoy trabajando con Android 8, el arranque verificado de Android con dm-verity y actualizaciones diferenciales A/B sin problemas basadas en bloques. Según mi entendimiento, el update_engine de Android realiza algunas validaciones de la imagen de actualización recibida antes de proceder a escribir en las particiones objetivo. Hasta donde sé, update_engine verifica si la actualización diferencial se puede instalar en las particiones actuales. ¿Cómo se realiza esta verificación?

Puedo imaginar dos posibilidades, pero no he encontrado documentación autoritativa sobre ninguna de las dos hipótesis:

  1. El paquete de actualización diferencial contiene un hash lineal de la partición fuente. En el dispositivo, update_engine calcula un hash SHA-256 de toda la partición sobre la cual se aplicará la actualización diferencial. Compara este valor con el proporcionado como parte del paquete de actualización y procede solo si los dos valores coinciden.
  2. El paquete de actualización diferencial contiene el hash root de dm-verity del Árbol de Merkle utilizado para la validación por bloques con dm-verity. El update_engine compara este hash root objetivo con el proporcionado en el dispositivo en la estructura vbmeta. Solo si coinciden, procede a instalar la actualización.

¿Es correcta alguna de estas hipótesis, o me estoy perdiendo algo? De manera similar, ¿cómo valida el update_engine las particiones objetivo una vez que han sido escritas? ¿A través de un hash lineal, o utilizando el hash root? ¿O de otra forma?

3voto

Jack Wade Puntos 231

¿Es correcta alguna de estas hipótesis?

Hasta ahora no he experimentado con el dispositivo A/B, pero lo que entiendo de la documentación oficial y el código fuente es que es ambas cosas. Se verifica el hash SHA-256 de la partición de destino contra el recibido del servidor de actualizaciones. Y después del reinicio se realiza la verificación de dm-verity.

De Vida de una actualización A/B:

"5. Se vuelven a leer y verificar las particiones completas contra el hash esperado."

Además, el implementador puede agregar comprobaciones adicionales post-instalación. Y:

_"Después del reinicio, update_verifier activa la comprobación de integridad utilizando dm-verity".
...
"Después de que la comprobación se completa, update_verifier marca el inicio exitoso."_

.

Android update_engine realiza algunas validaciones de la imagen de actualización recibida antes de proceder a escribir las particiones de destino

Las actualizaciones A/B difieren de las antiguas actualizaciones basadas en recuperación no A/B. En este último caso, el paquete de actualización se verifica dos veces contra las claves públicas en /system/etc/security/otacerts.zip (arranque normal) y /res/keys (arranque de recuperación). En el caso de las actualizaciones basadas en bloques, dm-verity es una verificación adicional. Pero las actualizaciones A/B tienen soporte para actualizaciones en streaming:

_"Las actualizaciones se pueden transmitir a dispositivos A/B, eliminando la necesidad de descargar el paquete antes de instalarlo. La transmisión significa que no es necesario que el usuario tenga suficiente espacio libre para almacenar el paquete de actualización en /data o /cache
...
update_engine actualizará los bloques brutos en la partición actualmente no utilizada mientras transmite el paquete de actualización."_

Así que no siempre es posible verificar la integridad completa del paquete de actualización (carga) antes de flashear. En su lugar, la integridad del paquete de actualización se verifica después de la actualización. Si algo sale mal, la ranura de partición más antigua sigue intacta como respaldo, mientras que la ranura actualizada se marca como no arrancable hasta la próxima actualización.

.

¿Significa esto que update_engine calcula un hash SHA-256 lineal completo de todas las particiones de origen que se supone actualizar?

"Durante actualizaciones incrementales o delta, los datos binarios de la ranura actual se utilizan para generar los datos en la nueva ranura". Pero update_engine calcula los hashes de todas las particiones de destino después de que estas son actualizadas. Desde el código fuente:

"Esta acción calculará el hash de todas las particiones de la ranura de destino involucradas en la actualización. Los hashes luego se verifican con los de el InstallPlan. Si el hash de destino no coincide, la acción fallará."

.

dm-verity no realiza una verificación exhaustiva en cada reinicio, porque eso tomaría mucho tiempo. Por eso asumo que update_verifier, en contraste, realiza la verificación exhaustiva en un reinicio después de una instalación exitosa

Según los detalles encontrados en Implementando dm-verity, el hash de cada bloque de 4k se precalcula y se agrega al final de system.img (o vendor.img) en la tabla de dm-verity (metabloque; ligeramente detalles diferentes en caso de AVB) que está firmada por la clave privada del OEM. La clave pública se guarda en el anillo de claves del sistema del kernel (en dispositivos A/B) que el kernel utiliza para verificar la integridad de la tabla de verificación en cada reinicio.

"Una forma de verificar un dispositivo de bloques es hacer un hash directamente de su contenido y compararlos con un valor almacenado. Sin embargo, intentar verificar un dispositivo de bloques completo puede llevar un período extendido y consumir mucha energía de un dispositivo.
...
En su lugar, dm-verity verifica los bloques individualmente y solo cuando cada uno es accedido. Cuando se lea en la memoria, el bloque se hace hash en paralelo. El hash se verifica luego en el árbol. Y dado que leer el bloque es una operación costosa, la latencia introducida por esta verificación a nivel de bloque es comparativamente nominal.
...
Si la verificación falla, el dispositivo genera un error de E/S que indica que el bloque no se puede leer."

update_verifier lee una lista de bloques en el próximo reinicio. Ningún error de E/S significa que el nuevo system.img está firmado con una clave genuina y la ranura actualizada se marca como exitosa.

para una actualización diferencial muy pequeña, solo se verifican los bloques que han cambiado. Para una actualización completa, se vuelven a leer todos los bloques. ¿Es esta suposición correcta?

La documentación dice:

_"update_verifier solo leerá los bloques listados en /data/ota_package/care_map.txt, que se incluye en un paquete de actualización A/B"_

No leerá otros bloques, ya estén actualizados o no.

0 votos

¿La imagen de vbmeta también se actualiza con nuevas root cuando se aplica una actualización OTA?

PreguntAndroid.com

PreguntAndroid es una comunidad de usuarios de Android en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X