Implémenter dm-verity

Android 4.4 et versions ultérieures sont compatibles avec le démarrage validé via la fonctionnalité de noyau device-mapper-verity (dm-verity) facultative, qui fournit une vérification transparente de l'intégrité des appareils de bloc. dm-verity permet d'éviter les rootkits persistants qui peuvent conserver les droits d'administration et compromettre les appareils. Cette fonctionnalité permet aux utilisateurs Android de s'assurer, lors du démarrage d'un appareil, qu'il est dans le même état que lors de sa dernière utilisation.

Les applications potentiellement dangereuses (PHA) disposant de droits racines peuvent être masquées pour des programmes de détection et de se masquer. Le logiciel d’activation du mode root peut faire car il est souvent plus privilégié que les détecteurs, ce qui permet logiciel de "mentir" aux programmes de détection.

La fonctionnalité dm-verity vous permet d'examiner un appareil de bloc, la couche de stockage sous-jacente du système de fichiers, et de déterminer s'il correspond à sa configuration attendue. Pour ce faire, il utilise un arbre de hachage cryptographique. Pour chaque bloc (généralement 4 ko), il existe un hachage SHA256.

Les valeurs de hachage étant stockées dans une arborescence de pages, seul le premier niveau "racine" le hachage doit être approuvé pour vérifier le reste de l'arborescence. La possibilité de modifier l’un des blocs équivaudrait à briser le hachage cryptographique. Consultez le schéma suivant pour voir une représentation de cette structure.

Table de hachage dm-verity

Figure 1 : Table de hachage dm-verity

Une clé publique est incluse dans la partition de démarrage, qui doit être vérifiée en externe par le fabricant de l'appareil. Cette clé permet de vérifier la signature de ce hachage et de confirmer que la partition système de l'appareil est protégée et inchangée.

Conditions de fonctionnement

La protection dm-verity réside dans le noyau. Ainsi, si un logiciel d'activation du mode root compromet système avant que le noyau n’apparaisse, il conserve cet accès. Pour atténuer ce risque, la plupart des fabricants vérifient le noyau à l'aide d'une clé gravée sur l'appareil. Cette clé ne peut pas être modifiée une fois que l'appareil quitte l'usine.

Les fabricants utilisent cette clé pour valider la signature sur le bootloader de premier niveau, qui à son tour valide la signature sur les niveaux suivants, le bootloader de l'application et finalement le noyau. Chaque fabricant souhaitant profiter des validations démarrage doit proposer une méthode permettant de vérifier l'intégrité du noyau. En supposant que le noyau a été validé, il peut examiner un périphérique de bloc et le valider lorsqu'il est installé.

Pour vérifier un appareil de bloc, vous pouvez hacher directement son contenu et le comparer à une valeur stockée. Toutefois, essayer de valider l'intégralité d'un appareil de stockage en mode bloc prendre une période prolongée et consommer une grande partie de la batterie d'un appareil. Les appareils prendraient pendant de longues périodes au démarrage, puis s'épuiser considérablement avant utilisation.

À la place, dm-verity vérifie les blocs individuellement et uniquement lorsqu'ils sont consultés. Lors de la lecture en mémoire, le bloc est haché en parallèle. Le hachage est ensuite validé dans l'arborescence. Étant donné que la lecture du bloc est une opération très coûteuse, la latence introduite par cette validation au niveau du bloc est relativement faible.

En cas d'échec de la validation, l'appareil génère une erreur d'E/S indiquant que le bloc ne peut pas être lu. Il semble que le système de fichiers a été corrompu, comme prévu.

Les applications peuvent choisir de continuer sans les données obtenues, par exemple lorsque ces résultats ne sont pas nécessaires à la fonction principale de l'application. Toutefois, si l'application ne peut pas continuer sans les données, elle échoue.

Correction d'erreurs par anticipation

Android 7.0 et les versions ultérieures améliorent la robustesse de dm-verity avec la correction d'erreurs par anticipation (FEC). La mise en œuvre d'AOSP commence par le code de correction d'erreur Reed-Solomon et applique un appelée "entrelacement" pour réduire la surcharge d'espace et augmenter de blocages corrompus et récupérables. Pour en savoir plus sur la FEC, consultez la section Verified Boot strictement appliqué avec correction d'erreurs.

Implémentation

Résumé

  1. Générez une image système ext4.
  2. Générez une arborescence de hachage pour cette image.
  3. Créez une table dm-verity pour cette arborescence de hachage.
  4. Signez cette table dm-verity pour générer une signature de table.
  5. Regrouper la signature de table et la table dm-verity en métadonnées de vérité.
  6. Concatenate l'image système, les métadonnées de validation et l'arborescence de hachage.

Pour obtenir une description détaillée de l'arborescence de hachage et du tableau dm-verity, consultez The Chromium Projects - Verified Boot (Projets Chromium : démarrage validé).

Générer l'arborescence de hachage

Comme décrit dans l'introduction, l'arborescence de hachage fait partie intégrante de dm-verity. L'outil cryptsetup génère un arbre de hachage pour vous. Une autre solution compatible est définie ici:

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

Pour former le hachage, l'image système est divisée à la couche 0 en blocs de 4 ko, chacun étant associé à un hachage SHA256. La couche 1 est constituée uniquement de ces hachages SHA256 en blocs de 4 ko, ce qui donne une image beaucoup plus petite. La couche 2 est formée de manière identique, avec les hachages SHA256 de la couche 1.

Cela se fait jusqu'à ce que les hachages SHA256 de la couche précédente puissent tenir dans un seul . Lorsque vous obtenez le SHA-256 de ce bloc, vous disposez du hachage racine de l'arborescence.

La taille de l'arborescence de hachage (et l'espace disque utilisé en conséquence) varie en fonction de la taille de la partition validée. En pratique, la taille des arbres de hachage a tendance à être petit, souvent moins de 30 Mo.

Si l'un de vos blocs d'un calque n'est pas complètement rempli naturellement par les hachages de la couche précédente, vous devez la remplir avec des zéros pour obtenir le la résolution attendue est 4K. Cela vous permet de savoir que l'arborescence de hachage n'a pas été supprimée et qu'elle est plutôt complétée par des données vides.

Pour générer l'arborescence de hachage, concaténez les hachages de couche 2 avec ceux de la couche 1, la couche 3 aux hachages sur ceux de la couche 2, et ainsi de suite. Écrire tout cela sur le disque. Notez que cela ne fait pas référence à la couche 0 du hachage racine.

Pour récapituler, l'algorithme général pour construire l'arborescence de hachage est le suivant:

  1. Choisissez un salage aléatoire (encodage hexadécimal).
  2. Diviser votre image système en blocs de 4K
  3. Pour chaque bloc, obtenez son hachage SHA256 (salé).
  4. Concaténer ces hachages pour former un niveau
  5. Compléter le niveau avec des 0 jusqu'à une limite de bloc de 4 000
  6. Concatenate le niveau à votre arbre de hachage.
  7. Répétez les étapes 2 à 6 en utilisant le niveau précédent comme source du suivant jusqu'à ce qu'il ne reste qu'un seul hachage.

Le résultat est un hachage unique, qui est votre hachage racine. Ceci et votre sel sont utilisés lors de la construction de votre table de mappage dm-verity.

Créer la table de mappage dm-verity

Créez la table de mappage dm-verity, qui identifie le périphérique de bloc (ou cible) pour le noyau et l'emplacement de l'arborescence de hachage (qui est la même valeur). Ce Le mappage est utilisé pour la génération et le démarrage de fstab. Le tableau identifie également la taille des blocs et hash_start, l'emplacement de départ de l'arbre de hachage (plus précisément, son numéro de bloc à partir du début de l'image).

Consultez cryptsetup pour découvrir description détaillée des champs de la table de mappage des cibles de vérification.

Signer la table dm-verity

Signez la table dm-verity pour générer une signature de table. Lors de la validation d'un la signature de la table est validée en premier. Cela se fait par rapport à une clé sur l'image de démarrage à un emplacement fixe. Les clés sont généralement incluses des fabricants pour permettre l'inclusion automatique sur les appareils l'emplacement.

Pour vérifier la partition avec cette combinaison de signature et de clé:

  1. Ajoutez une clé RSA-2048 dans un format compatible avec libmincrypt au Partition /boot à /verity_key. Identifiez l'emplacement de la clé utilisée pour valider l'arborescence de hachage.
  2. Dans le fichier fstab de l'entrée concernée, ajoutez verify aux indicateurs fs_mgr.

Regrouper la signature de la table dans des métadonnées

Regroupez la signature de la table et la table dm-verity dans les métadonnées Verity. L'ensemble du bloc de métadonnées est versionné afin qu'il puisse être étendu, par exemple pour ajouter un deuxième type de signature ou modifier l'ordre.

Pour vérification, un nombre magique est associé à chaque ensemble de métadonnées de table qui permet de l'identifier. Parce que la longueur est incluse dans le système ext4 l'en-tête de l'image, ce qui permet de rechercher les métadonnées sans connaître le contenu des données elles-mêmes.

Cela permet de s'assurer que vous n'avez pas choisi de valider une partition non validée. Si oui, l'absence de ce chiffre interrompt le processus de vérification. Ce nombre est au format suivant : 0xb001b001

Les valeurs d'octets au format hexadécimal sont les suivantes :

  • premier octet = b0
  • Deuxième octet = 01
  • troisième octet = b0
  • quatrième octet = 01

Le schéma suivant illustre la répartition des métadonnées de vérification:

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

Ce tableau décrit ces champs de métadonnées.

Tableau 1. Champs de métadonnées de vérification

Champ Objectif Taille Valeur
nombre magique utilisé par fs_mgr pour contrôler l'intégrité 4 octets 0xb001b001
version utilisé pour gérer les versions du bloc de métadonnées 4 octets actuellement 0
signature la signature de la table au format PKCS1.5 rempli 256 octets
longueur du tableau la longueur de la table dm-verity en octets 4 octets
table le tableau dm-verity décrit précédemment longueur de la table en octets
padding Cette structure est remplie de zéros pour atteindre une longueur de 32 ko. 0

Optimiser la dm-verity

Pour obtenir les meilleures performances possibles avec dm-verity, procédez comme suit :

  • Dans le kernel, activez NEON SHA-2 pour ARMv7 et les extensions SHA-2 pour ARMv8.
  • Tester différentes options read-ahead et prefetch_cluster afin de trouver la meilleure configuration pour votre appareil.