Microdroïde

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Microdroid est un mini-Android OS qui s'exécute dans une pVM. Vous n'êtes pas obligé d'utiliser Microdroid, vous pouvez démarrer une machine virtuelle avec n'importe quel système d'exploitation. Cependant, les principaux cas d'utilisation des pVM n'exécutent pas un système d'exploitation autonome, mais offrent plutôt un environnement d'exécution isolé pour exécuter une partie d'une application avec des garanties de confidentialité et d'intégrité plus fortes qu'Android ne peut fournir.

Avec les systèmes d'exploitation traditionnels, assurer une confidentialité et une intégrité solides nécessite une bonne quantité de travail (souvent dupliqué) car les systèmes d'exploitation traditionnels ne correspondent pas à l'architecture globale d'Android. Par exemple, avec l'architecture Android standard, les développeurs doivent implémenter un moyen de charger et d'exécuter en toute sécurité une partie de leur application dans la pVM, et la charge utile est construite sur glibc. L'application Android utilise Bionic, la communication nécessite un protocole personnalisé sur vsock et le débogage à l'aide d'adb est difficile.

Microdroid comble ces lacunes en fournissant une image de système d'exploitation prête à l'emploi conçue pour nécessiter le moins d'efforts de la part des développeurs pour décharger une partie de leur application dans une pVM. Le code natif est construit sur Bionic, la communication se fait via Binder, et il permet d'importer des APEX à partir d'Android et expose un sous-ensemble de l'API Android, comme le magasin de clés pour les opérations cryptographiques avec des clés matérielles. Dans l'ensemble, les développeurs devraient trouver dans Microdroid un environnement familier avec les outils auxquels ils se sont habitués dans le système d'exploitation Android complet.

Fonctionnalités

Microdroid est une version simplifiée d'Android avec quelques composants supplémentaires spécifiques aux pVM. Microdroid prend en charge :

  • Un sous-ensemble d'API NDK (toutes les API pour l'implémentation Android de libc et Bionic sont fournies)
  • Fonctionnalités de débogage, telles que adb, logcat, tombstone et gdb
  • Démarrage vérifié et SELinux activés
  • Charger et exécuter un binaire, ainsi que des bibliothèques partagées, intégrés dans un APK
  • Binder RPC sur vsock et échange de fichiers avec contrôles d'intégrité implicites
  • Chargement des APEX

Microdroid ne prend pas en charge :

  • API Java Android dans les packages android.\*

  • System Server et Zygote

  • Graphiques/interface utilisateur

  • HAL

Architecture microdroïde

Microdroid est similaire à Cuttlefish en ce sens que les deux ont une architecture similaire à Android standard. Microdroid se compose des images de partition suivantes regroupées dans une image disque composite :

  • bootloader - Vérifie et démarre le noyau.
  • boot.img - Contient le noyau et le disque virtuel d'initialisation.
  • vendor\_boot.img - Contient des modules de noyau spécifiques à la machine virtuelle, tels que virtio.
  • super.img - Comprend les partitions logiques du système et du fournisseur.
  • vbmeta.img - Contient des métadonnées de démarrage vérifiées.

Les images de partition sont livrées dans l'APEX de virtualisation et sont regroupées dans une image de disque composite par VirtualizationService . En plus de l'image disque composite principale du système d'exploitation, VirtualizationService est responsable de la création de ces autres partitions :

  • payload - Un ensemble de partitions soutenues par les APEX et les APK d'Android
  • instance - Une partition chiffrée pour conserver les données de démarrage vérifiées par instance, telles que le sel par instance, les clés publiques APEX approuvées et les compteurs de restauration

Séquence d'amorçage

La séquence de démarrage Microdroid se produit après le démarrage de l'appareil . Le démarrage de l'appareil est abordé dans le document Architecture . La figure 1 montre les étapes qui ont lieu pendant la séquence de démarrage du Microdroid :

Bootflow sécurisé de l'instance microdroid

Figure 1. Bootflow sécurisé de l'instance de microdroid

Voici une explication des étapes :

  1. Le chargeur de démarrage est chargé en mémoire par crossvm et pvmfw commence à s'exécuter. Avant de passer au bootloader, pvmfw effectue deux tâches :

    • Vérifie le chargeur de démarrage pour vérifier s'il provient d'une source fiable (Google ou un OEM).
    • Garantit que le même chargeur de démarrage est utilisé de manière cohérente sur plusieurs démarrages de la même pVM grâce à l'utilisation de l'image d'instance. Plus précisément, la pVM est initialement démarrée avec une image d'instance vide. pvmfw stocke l'identité du chargeur de démarrage dans l'image d'instance et la chiffre. Ainsi, la prochaine fois que la pVM est démarrée avec la même image d'instance, pvmfw déchiffre l'identité enregistrée à partir de l'image d'instance et vérifie qu'il s'agit de la même que celle précédemment enregistrée. Si les identités diffèrent, pvmfw refuse de démarrer.

    Le chargeur de démarrage démarre ensuite Microdroid.

  2. Le bootloader accède au disque de l'instance. Semblable à pvmfw, le chargeur de démarrage dispose d'un lecteur de disque d'instance avec des informations sur les images de partition utilisées dans cette instance lors des démarrages précédents, y compris la clé publique.

  3. Le chargeur de démarrage vérifie vbmeta et les partitions chaînées, telles que boot et super , et, en cas de succès, dérive les secrets pVM de l'étape suivante. Ensuite, Microdroid passe le contrôle au noyau.

  4. Comme la super partition a déjà été vérifiée par le bootloader (étape 3), le noyau monte inconditionnellement la super partition. Comme avec Android complet, la super partition se compose de plusieurs partitions logiques montées sur dm-verity. Le contrôle est ensuite passé au processus init , qui démarre divers services natifs. Le script init.rc est similaire à celui d'Android complet mais adapté aux besoins de Microdroid.

  5. Le processus d' init démarre le gestionnaire Microdroid, qui accède à l'image de l'instance. Le service Microdroid manager déchiffre l'image à l'aide de la clé transmise à l'étape précédente et lit les clés publiques et les compteurs de rollback de l'APK client et des APEX auxquels cette pVM fait confiance. Ces informations sont utilisées ultérieurement par zipfuse et apexd lorsqu'ils montent l'APK client et les APEX demandés, respectivement.

  6. Le service de gestion Microdroid démarre apexd .

  7. apexd monte les APEX dans les répertoires /apex/<name> . La seule différence entre la façon dont Android et Microdroid montent les APEX est que dans Microdroid, les fichiers APEX proviennent de périphériques de bloc virtuels ( /dev/vdc1 , …), et non de fichiers normaux ( /system/apex/*.apex ).

  8. zipfuse est le système de fichiers FUSE de Microdroid. zipfuse monte l'APK client, qui est essentiellement un fichier Zip en tant que système de fichiers. En dessous, le fichier APK est transmis en tant que périphérique de bloc virtuel par le pVM avec dm-verity, comme APEX. L'APK contient un fichier de configuration avec une liste d'APEX que le développeur de l'application a demandés pour cette instance de pVM. La liste est utilisée par apexd lors de l'activation des APEX.

  9. Le flux de démarrage revient au service de gestion Microdroid. Le service de gestionnaire communique ensuite avec VirtualizationService d'Android à l'aide de Binder RPC afin qu'il puisse signaler des événements importants tels qu'un crash ou un arrêt, et accepter des demandes telles que l'arrêt de la pVM. Le service de gestionnaire lit l'emplacement du binaire principal à partir du fichier de configuration de l'APK et l'exécute.

Échange de fichiers (AuthFS)

Il est courant que les composants Android utilisent des fichiers pour l'entrée, la sortie et l'état et les transmettent en tant que descripteurs de fichiers (type ParcelFileDescriptor dans AIDL) avec un accès contrôlé par le noyau Android. AuthFS facilite une fonctionnalité similaire pour l'échange de fichiers entre des points de terminaison qui se méfient mutuellement à travers les limites de pVM.

Fondamentalement, AuthFS est un système de fichiers distant avec des contrôles d'intégrité transparents sur les opérations d'accès individuelles, similaire à fs-verity . Les vérifications permettent au frontal, tel qu'un programme de lecture de fichiers exécuté dans une pVM, de détecter si le backend non approuvé, généralement Android, a falsifié le contenu du fichier.

Pour échanger des fichiers, le backend ( fd\_server ) est démarré avec une configuration par fichier spécifiant s'il est destiné à l'entrée (lecture seule) ou à la sortie (lecture-écriture). Pour l'entrée, l'interface impose que le contenu corresponde à un hachage connu, au-dessus d'un arbre Merkle pour la vérification à l'accès. Pour la sortie, AuthFS maintient en interne un arbre de hachage du contenu tel qu'observé à partir des opérations d'écriture et peut appliquer l'intégrité lorsque les données sont relues.

Le transport sous-jacent est actuellement basé sur Binder RPC, mais cela pourrait changer à l'avenir pour optimiser les performances.

Gestion des clés

Les pVM sont fournies avec une clé de scellement stable adaptée aux données persistantes protégées et une clé d'attestation adaptée à la production de signatures produites de manière vérifiable par la pVM.

Classeur RPC

La majorité des interfaces d'Android sont exprimées en AIDL , qui est construit au-dessus du pilote du noyau Binder Linux. Pour prendre en charge les interfaces entre les pVM, le protocole Binder a été réécrit pour fonctionner sur les sockets, vsock dans le cas des pVM. Le fonctionnement sur des sockets permet aux interfaces AIDL existantes d'Android d'être utilisées dans ce nouvel environnement.

Pour configurer la connexion, un point de terminaison, tel que la charge utile pVM, crée un objet RpcServer , enregistre un objet racine et commence à écouter les nouvelles connexions. Les clients peuvent se connecter à ce serveur à l'aide d'un objet RpcSession , obtenir l'objet Binder et l'utiliser exactement comme un objet Binder est utilisé avec le pilote Binder du noyau.