Cómo implementar dm-verity

Android 4.4 y las versiones posteriores admiten el inicio verificado a través de la función del kernel de device-mapper-verity (dm-verity), que proporciona información la verificación de integridad de los dispositivos de almacenamiento en bloques. dm-verity ayuda a prevenir los rootkits persistentes que puede conservar privilegios de administrador y comprometer dispositivos. Esta ayuda a los usuarios de Android a asegurarse de que, cuando inician un dispositivo, se encuentren en el mismo actual como cuando se usó por última vez.

Las aplicaciones potencialmente dañinas (APD) con privilegios de administrador pueden ocultarse de detección de intrusiones y se enmascaran. El software de permisos de administrador Esto se debe a que suelen tener más privilegios que los detectores, lo que permite que "mentir" a los programas de detección.

La función dm-verity permite observar un dispositivo de almacenamiento en bloques, el del sistema de archivos y determinará si coincide con configuración. Para ello, usa un árbol de hash criptográfico. Por cada bloque (por lo general, 4K), hay un hash SHA256.

Debido a que los valores de hash se almacenan en un árbol de páginas, solo se puede “raíz” hash debe ser de confianza para verificar el resto del árbol. La capacidad de modificar cualquiera de los bloques equivale a romper el hash criptográfico. Consulta el siguiente diagrama para ver una representación de esta estructura.

tabla-hash-dm-verity

Figura 1: Tabla de hash de dm-verity

Se incluye una clave pública en la partición de inicio, que debe verificarse. externamente por el fabricante del dispositivo. Esa clave se usa para verificar la firma para ese hash y confirmar que la partición del sistema del dispositivo esté protegida sin cambios.

Operación

La protección de dm-verity se encuentra en el kernel. Por lo tanto, si el software de permisos de administrador pone en riesgo del sistema antes de que aparezca el kernel, conservará ese acceso. Para mitigar esto la mayoría de los fabricantes verifican el kernel con una clave quemada en el dispositivo. Esa clave no se puede cambiar una vez que el dispositivo sale de fábrica.

Los fabricantes usan esa clave para verificar la firma en el primer nivel que, a su vez, verifica la firma en los niveles posteriores, el de la aplicación y, finalmente, el kernel. Cada fabricante que desee para aprovechar los beneficios verificados boot debe tener un método para verificar la integridad del kernel. Suponiendo que el kernel se verificó, puede observar un dispositivo de bloques. y verifícalo tal como está montado.

Una forma de verificar un dispositivo de almacenamiento en bloques es generar un hash directamente en su contenido y compararlo un valor almacenado. Sin embargo, intentar verificar un dispositivo de almacenamiento en bloques completo tardar un período prolongado y consumir gran parte de la energía de un dispositivo. Los dispositivos tardarían durante períodos extensos para que se inicien y se desvíen de manera significativa antes de usarlos.

En cambio, dm-verity verifica los bloques individualmente y solo cuando cada uno a las que se accede. Cuando se lee en la memoria, el bloque genera un hash en paralelo. El hash es verificamos el árbol. Como leer el bloque es algo costoso, la latencia que ingresa esta verificación a nivel de bloque en comparación con un valor nominal.

Si falla la verificación, el dispositivo generará un error de E/S que indicará el bloqueo. no se pueden leer. Aparecerá como si el sistema de archivos se hubiera dañado, al igual que lo esperado.

Las aplicaciones pueden optar por continuar sin los datos resultantes, como cuando esos resultados no son necesarios para la función principal de la aplicación. Sin embargo, Si la aplicación no puede continuar sin los datos, fallará.

Corrección de errores de reenvío

Android 7.0 y versiones posteriores mejoran la solidez de dm-verity con error directo correcto (FEC). La implementación del AOSP comienza con Reed-Solomon de corrección de errores y aplica un llamada intercalación para reducir la sobrecarga del espacio y aumentar la la cantidad de bloques dañados que se pueden recuperar. Para obtener más detalles sobre la FEC, consulte Inicio verificado estricto con corrección de errores.

Implementación

Resumen

  1. Genera una imagen del sistema ext4.
  2. Genera un árbol de hash para esa imagen.
  3. Crea una tabla de dm-verity para ese árbol de hash.
  4. Firma la tabla de dm-verity para generar una tabla. firma.
  5. Agrupa la firma de la tabla y la tabla de dm-verity en metadatos de verity.
  6. Concatena la imagen del sistema, los metadatos de verity y el árbol de hash.

Consulta el artículo Proyectos de Chromium: Inicio verificado para obtener una descripción detallada del árbol de hash y de la tabla dm-verity.

Cómo generar el árbol de hash

Como se describe en la introducción, el árbol de hash es fundamental para dm-verity. El cryptsetup generar un árbol de hash por ti. Como alternativa, aquí se define una compatible:

<your block device name> <your block device name> <block size> <block size> <image size in blocks> <image size in blocks + 8> <root hash> <salt>

Para formar el hash, la imagen del sistema se divide en la capa 0 en bloques de 4,000, cada uno se le asignó un hash SHA256. La capa 1 se forma uniendo solo los hash SHA256 en bloques de 4K, lo que da como resultado una imagen mucho más pequeña. La capa 2 se forma de manera idéntica, con los hash SHA256 de la capa 1.

Esto se hace hasta que los hash SHA256 de la capa anterior pueden caber en una sola bloque. Cuando obtienes el SHA256 de ese bloque, obtienes el hash raíz del árbol.

El tamaño del árbol de hash (y el uso del espacio en el disco correspondiente) varía según el de la partición verificada. En la práctica, el tamaño de los árboles de hash suele ser pequeño, a menudo, de menos de 30 MB.

Si tienes un bloque en una capa que no se llena completamente de forma natural con hash de la capa anterior, debes rellenarla con ceros para lograr se esperaba 4K. Esto le permite saber que no se quitó el árbol de hash y está en su lugar, se completa con datos en blanco.

Para generar el árbol de hash, concatena los hashes de la capa 2 con los hash de la capa la capa 3, los hashes sobre los de la capa 2, y así sucesivamente. Escribe todo esto al disco. Ten en cuenta que esto no hace referencia a la capa 0 del hash raíz.

En resumen, el algoritmo general para construir el árbol de hash es el siguiente:

  1. Elige una sal aleatoria (codificación hexadecimal).
  2. Divide la imagen de sistema en bloques de 4,000.
  3. Para cada bloque, obtén su hash SHA256 (con sal).
  4. Concatena estos hashes para formar un nivel
  5. Rellena el nivel con 0 hasta un límite de bloque de 4,000.
  6. Concatena el nivel en tu árbol de hash.
  7. Repite los pasos 2 a 6 con el nivel anterior como fuente para el siguiente solo tienes un hash.

El resultado es un solo hash, que es tu hash raíz. Esto y tu sal se utilizarán durante la creación de la tabla de asignación de dm-verity.

Compila la tabla de asignación de dm-verity

Compila la tabla de asignación de dm-verity, que identifica el dispositivo de bloques (o destino). para el kernel y la ubicación del árbol de hash (que es el mismo valor). Esta la asignación se usa para la generación y el inicio de fstab. La tabla también identifica el tamaño de los bloques y hash_start, la ubicación inicial del árbol de hash (específicamente, el número de bloque desde el principio de la imagen).

Consulta cryptsetup para obtener un descripción detallada de los campos de la tabla de asignación de objetivos de verity.

Firma de la tabla dm-verity

Firma la tabla dm-verity para generar una firma de tabla. Cuando verifiques un la firma de la tabla se valida primero. Esto se hace con una clave en tu imagen de arranque en una ubicación fija. Por lo general, las claves se incluyen de los fabricantes crear sistemas para la inclusión automática en los dispositivos en una ubicación ubicación.

Para verificar la partición con esta combinación de firma y clave, haz lo siguiente:

  1. Agrega una clave RSA-2048 en formato compatible con libmincrypt al /boot partición en /verity_key. Identifica la ubicación de la clave que se usa para la verificación el árbol de hash.
  2. En la pestaña fstab de la entrada correspondiente, agrega verify a las marcas fs_mgr.

Empaqueta la firma de la tabla en metadatos

Agrupa la firma de la tabla y la tabla de dm-verity en metadatos de verity. Todo el de metadatos tiene un control de versiones para que se extienda, por ejemplo, para agregar tipo de firma o cambiar algún orden.

Como comprobación de estado, se asocia un número mágico con cada conjunto de metadatos de la tabla. que ayuda a identificar la tabla. Dado que la longitud se incluye en el sistema ext4 de imagen, esto proporciona una forma de buscar los metadatos sin conocer el contenido de los datos en sí.

Esto garantiza que no hayas elegido verificar una partición no verificada. Si es así, la ausencia de este número mágico detendrá el proceso de verificación. Este número se parece a:
0xb001b001

Los valores de bytes en hexadecimal son los siguientes:

  • primer byte = b0
  • segundo byte = 01
  • tercer byte = b0
  • cuarto byte = 01

En el siguiente diagrama, se muestra el desglose de los metadatos de verity:

<magic number>|<version>|<signature>|<table length>|<table>|<padding>
\-------------------------------------------------------------------/
\----------------------------------------------------------/   |
                            |                                  |
                            |                                 32K
                       block content

Y esta tabla describe esos campos de metadatos.

Tabla 1: Campos de metadatos de verity

Campo Propósito Tamaño Valor
número mágico utilizado por fs_mgr como comprobación de estado 4 bytes 0xb001b001
version que se usa para crear versiones del bloque de metadatos 4 bytes actualmente 0
firma la firma de la tabla en forma con relleno PKCS1.5 256 bytes
longitud de la tabla la longitud de la tabla dm-verity en bytes 4 bytes
mesa la tabla dm-verity descrita anteriormente bytes de longitud de tabla
relleno esta estructura tiene 0 relleno y 32 k de longitud 0

Optimización de la dm-verity

Para obtener el mejor rendimiento de dm-verity, debes hacer lo siguiente:

  • En el kernel, activa NEON SHA-2 para ARMv7 y SHA-2 para ARMv8.
  • Experimenta con diferentes clústeres de lectura anticipada y prefetch_cluster para encontrar la mejor configuración para tu dispositivo.