Mikrodroide

Microdroid ist ein Mini-Android-Betriebssystem, das in einer pVM läuft. Sie müssen Microdroid nicht verwenden, Sie können eine VM mit jedem Betriebssystem starten. Die primären Anwendungsfälle für pVMs sind jedoch nicht das Ausführen eines eigenständigen Betriebssystems, sondern das Anbieten einer isolierten Ausführungsumgebung zum Ausführen eines Teils einer App mit stärkeren Vertraulichkeits- und Integritätsgarantien als Android bieten kann.

Bei herkömmlichen Betriebssystemen erfordert die Bereitstellung starker Vertraulichkeit und Integrität eine Menge Arbeit (oft doppelt), da herkömmliche Betriebssysteme nicht in die übergreifende Android-Architektur passen. Bei der standardmäßigen Android-Architektur müssen Entwickler beispielsweise ein Mittel zum sicheren Laden und Ausführen eines Teils ihrer App in der pVM implementieren, und die Nutzlast wird gegen glibc erstellt. Die Android-App verwendet Bionic, die Kommunikation erfordert ein benutzerdefiniertes Protokoll über vsock und das Debuggen mit adb ist eine Herausforderung.

Microdroid füllt diese Lücken, indem es ein gebrauchsfertiges Betriebssystem-Image bereitstellt, das so konzipiert ist, dass es den Entwicklern den geringsten Aufwand abverlangt, einen Teil ihrer App in eine pVM auszulagern. Nativer Code wird gegen Bionic erstellt, die Kommunikation erfolgt über Binder und ermöglicht den Import von APEXs aus Android und stellt eine Teilmenge der Android-API bereit, z. B. Keystore für kryptografische Operationen mit hardwaregestützten Schlüsseln. Insgesamt sollten Entwickler Microdroid als vertraute Umgebung mit den Tools vorfinden, an die sie sich im vollständigen Android-Betriebssystem gewöhnt haben.

Merkmale

Microdroid ist eine abgespeckte Version von Android mit einigen zusätzlichen pVM-spezifischen Komponenten. Microdroid unterstützt:

  • Eine Teilmenge von NDK-APIs (alle APIs für die Android-Implementierung von libc und Bionic werden bereitgestellt)
  • Debugging-Funktionen wie adb, logcat, tombstone und gdb
  • Verifizierter Start und SELinux aktiviert
  • Laden und Ausführen einer Binärdatei zusammen mit gemeinsam genutzten Bibliotheken, eingebettet in ein APK
  • Binder RPC über vsock und Austausch von Dateien mit impliziten Integritätsprüfungen
  • Laden von APEXen

Microdroid unterstützt nicht:

  • Android-Java-APIs in den android.\* Paketen

  • SystemServer und Zygote

  • Grafik/Benutzeroberfläche

  • HALs

Microdroid-Architektur

Microdroid ist Cuttlefish insofern ähnlich, als beide eine Architektur haben, die der von Standard-Android ähnelt. Microdroid besteht aus den folgenden Partitions-Images, die in einem zusammengesetzten Disk-Image gruppiert sind:

  • bootloader – Überprüft und startet den Kernel.
  • boot.img - Enthält den Kernel und die Init-Ramdisk.
  • vendor\_boot.img – Enthält VM-spezifische Kernel-Module wie virtio.
  • super.img - Besteht aus logischen Partitionen des Systems und des Herstellers.
  • vbmeta.img – Enthält verifizierte Boot-Metadaten.

Die Partitions-Images werden in Virtualization APEX ausgeliefert und von VirtualizationService in ein zusammengesetztes Datenträger-Image gepackt. Zusätzlich zum zusammengesetzten Festplatten-Image des Hauptbetriebssystems ist VirtualizationService für die Erstellung dieser anderen Partitionen verantwortlich:

  • payload – Eine Reihe von Partitionen, die von den APEXes und APKs von Android unterstützt werden
  • instance – Eine verschlüsselte Partition zum Beibehalten von instanzverifizierten Startdaten, wie z. B. instanzbezogenem Salt, vertrauenswürdigen öffentlichen APEX-Schlüsseln und Rollback-Zählern

Startvorgang

Die Microdroid-Startsequenz findet nach dem Gerätestart statt. Der Gerätestart wird im Architekturdokument erörtert. Abbildung 1 zeigt die Schritte, die während der Microdroid-Startsequenz stattfinden:

Sicherer Bootflow der Microdroid-Instanz

Abbildung 1. Sicherer Bootflow einer Microdroid-Instanz

Hier ist eine Erklärung der Schritte:

  1. Der Bootloader wird von crossvm in den Arbeitsspeicher geladen und pvmfw beginnt mit der Ausführung. Bevor zum Bootloader gesprungen wird, führt pvmfw zwei Aufgaben aus:

    • Überprüft den Bootloader, um zu prüfen, ob er von einer vertrauenswürdigen Quelle stammt (Google oder ein OEM).
    • Stellt durch die Verwendung des Instanz-Images sicher, dass derselbe Bootloader konsistent über mehrere Starts derselben pVM hinweg verwendet wird. Insbesondere wird die pVM anfänglich mit einem leeren Instanz-Image gebootet. pvmfw speichert die Identität des Bootloaders im Instanz-Image und verschlüsselt es. Wenn also die pVM das nächste Mal mit demselben Instanz-Image gebootet wird, entschlüsselt pvmfw die gespeicherte Identität aus dem Instanz-Image und überprüft, ob es dieselbe ist, die zuvor gespeichert wurde. Wenn sich die Identitäten unterscheiden, weigert sich pvmfw zu booten.

    Der Bootloader bootet dann Microdroid.

  2. Der Bootloader greift auf die Instanzfestplatte zu. Ähnlich wie pvmfw verfügt der Bootloader über ein Instanz-Festplattenlaufwerk mit Informationen zu Partitionsabbildern, die in dieser Instanz während früherer Starts verwendet wurden, einschließlich des öffentlichen Schlüssels.

  3. Der Bootloader überprüft vbmeta und die verketteten Partitionen wie boot und super und leitet bei Erfolg die pVM-Geheimnisse der nächsten Stufe ab. Dann übergibt Microdroid die Kontrolle an den Kernel.

  4. Da die Super-Partition bereits vom Bootloader verifiziert wurde (Schritt 3), hängt der Kernel die Super-Partition bedingungslos ein. Wie beim vollständigen Android besteht die Super-Partition aus mehreren logischen Partitionen, die über dm-verity gemountet werden. Die Kontrolle wird dann an den init -Prozess übergeben, der verschiedene native Dienste startet. Das Skript init.rc ähnelt dem des vollständigen Android, ist jedoch auf die Bedürfnisse von Microdroid zugeschnitten.

  5. Der init -Prozess startet den Microdroid-Manager, der auf das Instanz-Image zugreift. Der Microdroid-Managerdienst entschlüsselt das Bild mit dem aus der vorherigen Stufe übergebenen Schlüssel und liest die öffentlichen Schlüssel und Rollback-Zähler der Client-APKs und APEXes, denen diese pVM vertraut. Diese Informationen werden später von zipfuse und apexd wenn sie das Client-APK bzw. die angeforderten APEX-Dateien bereitstellen.

  6. Der Microdroid-Managerdienst startet apexd .

  7. apexd die APEX-Dateien in den Verzeichnissen /apex/<name> bereit. Der einzige Unterschied zwischen Android und Microdroid besteht darin, dass in Microdroid die APEX-Dateien von virtuellen Blockgeräten ( /dev/vdc1 , …) stammen, nicht von regulären Dateien ( /system/apex/*.apex ).

  8. zipfuse ist das FUSE-Dateisystem von Microdroid. zipfuse das Client-APK bereit, das im Wesentlichen eine Zip-Datei als Dateisystem ist. Darunter wird die APK-Datei als virtuelles Blockgerät von der pVM mit dm-verity übergeben, genau wie APEX. Das APK enthält eine Konfigurationsdatei mit einer Liste von APEXes, die der App-Entwickler für diese pVM-Instanz angefordert hat. Die Liste wird von apexd beim Aktivieren von APEXs verwendet.

  9. Der Boot-Flow kehrt zum Microdroid-Managerdienst zurück. Der Manager-Dienst kommuniziert dann über Binder RPC mit dem VirtualizationService von Android, sodass er wichtige Ereignisse wie Absturz oder Herunterfahren melden und Anforderungen wie das Beenden der pVM annehmen kann. Der Verwaltungsdienst liest den Speicherort der Hauptbinärdatei aus der Konfigurationsdatei des APK und führt sie aus.

Dateiaustausch (AuthFS)

Es ist üblich, dass Android-Komponenten Dateien für die Eingabe, Ausgabe und den Status verwenden und diese als Dateideskriptoren ( ParcelFileDescriptor Typ in AIDL) mit vom Android-Kernel gesteuertem Zugriff weitergeben. AuthFS ermöglicht eine ähnliche Funktionalität für den Austausch von Dateien zwischen Endpunkten, die sich gegenseitig misstrauen, über pVM-Grenzen hinweg.

Grundsätzlich ist AuthFS ein Remote-Dateisystem mit transparenten Integritätsprüfungen bei einzelnen Zugriffsvorgängen, ähnlich wie fs-verity . Die Überprüfungen ermöglichen es dem Frontend, beispielsweise einem Dateileseprogramm, das in einer pVM ausgeführt wird, zu erkennen, ob das nicht vertrauenswürdige Backend, typischerweise Android, den Dateiinhalt manipuliert hat.

Um Dateien auszutauschen, wird das Backend ( fd\_server ) mit einer Konfiguration pro Datei gestartet, die angibt, ob es für die Eingabe (nur Lesen) oder die Ausgabe (Lesen/Schreiben) gedacht ist. Für die Eingabe erzwingt das Frontend, dass der Inhalt mit einem bekannten Hash über einem Merkle-Baum für die On-Access-Überprüfung übereinstimmt. Für die Ausgabe verwaltet AuthFS intern einen Hash-Baum des Inhalts, wie er von Schreibvorgängen beobachtet wird, und kann die Integrität erzwingen, wenn die Daten zurückgelesen werden.

Der zugrunde liegende Transport basiert derzeit auf Binder RPC, dies kann sich jedoch in Zukunft ändern, um die Leistung zu optimieren.

Schlüsselverwaltung

pVMs werden mit einem stabilen Versiegelungsschlüssel bereitgestellt, der für geschützte persistente Daten geeignet ist, und einem Bestätigungsschlüssel , der zum Erzeugen von Signaturen geeignet ist, die nachweislich von der pVM erzeugt werden.

Binder-RPC

Ein Großteil der Android-Schnittstellen wird in AIDL ausgedrückt, das auf dem Binder-Linux-Kernel-Treiber aufbaut. Um Schnittstellen zwischen pVMs zu unterstützen, wurde das Binder-Protokoll so umgeschrieben, dass es über Sockets funktioniert, vsock im Fall von pVMs. Durch den Betrieb über Sockets können die vorhandenen AIDL-Schnittstellen von Android in dieser neuen Umgebung verwendet werden.

Um die Verbindung einzurichten, erstellt ein Endpunkt, wie z. B. die pVM-Nutzlast, ein RpcServer -Objekt, registriert ein Root-Objekt und beginnt, auf neue Verbindungen zu warten. Clients können mithilfe eines RpcSession -Objekts eine Verbindung zu diesem Server herstellen, das Binder -Objekt abrufen und es genau so verwenden, wie ein Binder -Objekt mit dem Kernel-Binder-Treiber verwendet wird.