Microdroid ist ein Mini-Android-Betriebssystem, das in einer pVM ausgeführt wird. Sie müssen Microdroid nicht verwenden, sondern können eine VM mit jedem Betriebssystem starten. Bei den Hauptanwendungsfällen für PVMs wird jedoch kein eigenständiges Betriebssystem ausgeführt, sondern eine isolierte Ausführungsumgebung, um einen Teil einer App mit stärkeren Vertraulichkeits- und Integritätsgarantien auszuführen, als Android bieten kann.
Bei herkömmlichen Betriebssystemen ist es mit einem erheblichen Arbeitsaufwand (oft doppelt) verbunden, für eine hohe Vertraulichkeit und Integrität zu sorgen, da herkömmliche Betriebssysteme nicht zur übergeordneten Android-Architektur passen. Bei der standardmäßigen Android-Architektur müssen Entwickler beispielsweise eine Möglichkeit implementieren, einen Teil ihrer App sicher in der pVM zu laden und auszuführen. Die Nutzlast wird dann mit glibc erstellt. Die Android-App verwendet Bionic, die Kommunikation erfordert ein benutzerdefiniertes Protokoll über vsock und das Debuggen mit adb ist schwierig.
Microdroid schließt diese Lücken, indem es ein vorkonfiguriertes Betriebssystem-Image bereitstellt, mit dem Entwickler einen Teil ihrer App mit minimalem Aufwand in eine pVM auslagern können. Nativer Code wird für Bionic erstellt, die Kommunikation erfolgt über Binder. Außerdem können APEXes vom Android-Host importiert werden und es wird ein Teil der Android API freigegeben, z. B. der Schlüsselspeicher für kryptografische Vorgänge mit hardwaregestützten Schlüsseln. Insgesamt sollten Entwickler Microdroid als vertraute Umgebung mit den Tools empfinden, die sie vom vollständigen Android-Betriebssystem gewohnt sind.
Funktionen
Microdroid ist eine stark reduzierte Version von Android mit einigen zusätzlichen Komponenten, die speziell für pVMs entwickelt wurden. Microdroid unterstützt:
- Eine Teilmenge der NDK-APIs (alle APIs für die Android-Implementierung von libc und Bionic werden bereitgestellt)
- Debugging-Funktionen wie adb, logcat, tombstone und gdb
- Verifizierter Bootmodus und SELinux
- Laden und Ausführen eines Binärprogramms zusammen mit gemeinsam genutzten Bibliotheken, die in ein APK eingebettet sind
- Binder-RPC über vsock und Austausch von Dateien mit impliziten Integritätsprüfungen
- Laden von APEX-Objekten
Microdroid unterstützt Folgendes nicht:
Android Java APIs in den
android.\*
-PaketenSystemServer und Zygote
Grafiken/Benutzeroberfläche
HALs
Microdroid-Architektur
Microdroid ähnelt Cuttlefish, da beide eine Architektur haben, die dem Standard-Android ähnelt. Microdroid besteht aus den folgenden Partitions-Images, die in einem zusammengesetzten Laufwerk-Image gruppiert sind:
bootloader
– Prüft und startet den Kernel.boot.img
: Enthält den Kernel und das Init-Ramdisk.vendor_boot.img
: Enthält VM-spezifische Kernelmodule wie virtio.super.img
: Besteht aus logischen System- und Anbieterpartitionen.vbmeta.img
– Enthält Metadaten für den verifizierten Bootmodus.
Die Partitions-Images werden im Virtualization APEX geliefert und von VirtualizationService
in einem zusammengesetzten Laufwerk-Image verpackt. Zusätzlich zum Haupt-Composite-Laufwerk-Image des Betriebssystems ist VirtualizationService
für die Erstellung der folgenden Partitionen verantwortlich:
payload
– eine Reihe von Partitionen, die von den APEX-Dateien und APKs von Android unterstützt werdeninstance
– eine verschlüsselte Partition zum Speichern von pro Instanz geprüften Boot-Daten, z. B. pro Instanz gültiger Salt, vertrauenswürdige APEX-öffentliche Schlüssel und Rollback-Zähler
Bootreihenfolge
Die Microdroid-Bootsequenz erfolgt nach dem Hochfahren des Geräts. Der Gerätestart wird im Abschnitt zur pVM-Firmware des Dokuments Architektur beschrieben. Abbildung 1 zeigt die Schritte, die während der Microdroid-Bootsequenz ausgeführt werden:
Hier eine Erklärung der einzelnen Schritte:
Der Bootloader wird von crosvm in den Arbeitsspeicher geladen und pvmfw wird ausgeführt. Bevor pvmfw zum Bootloader springt, führt er zwei Aufgaben aus:
- Prüft, ob der Bootloader von einer vertrauenswürdigen Quelle (Google oder ein OEM) stammt.
- Sorgt dafür, dass derselbe Bootloader durch Verwendung des Instanz-Images bei mehreren Starts derselben pVM konsistent verwendet wird. Die pVM wird dabei mit einem leeren Instanz-Image gestartet. pvmfw speichert die Identität des Bootloaders im Instanz-Image und verschlüsselt sie. Wenn die pVM also das nächste Mal mit demselben Instanz-Image gestartet wird, entschlüsselt pvmfw die gespeicherte Identität aus dem Instanz-Image und prüft, ob es sich um dieselbe Identität handelt, die zuvor gespeichert wurde. Wenn die Identitäten nicht übereinstimmen, startet pvmfw nicht.
Der Bootloader startet dann Microdroid.
Der Bootloader greift auf das Instanzlaufwerk zu. Ähnlich wie pvmfw hat der Bootloader ein Instanzlaufwerk mit Informationen zu Partitions-Images, die in dieser Instanz bei früheren Starts verwendet wurden, einschließlich des öffentlichen Schlüssels.
Der Bootloader überprüft vbmeta und die verketteten Partitionen wie
boot
undsuper
und leitet bei Erfolg die pVM-Geheimnisse der nächsten Stufe ab. Anschließend übergibt Microdroid die Kontrolle an den Kernel.Da die Super-Partition bereits vom Bootloader überprüft wurde (Schritt 3), wird sie vom Kernel bedingungslos bereitgestellt. Wie bei der vollständigen Android-Version besteht die Superpartition aus mehreren logischen Partitionen, die über dm-verity bereitgestellt werden. Die Steuerung wird dann an den
init
-Prozess übergeben, der verschiedene native Dienste startet. Dasinit.rc
-Script ähnelt dem von Android, ist aber auf die Anforderungen von Microdroid zugeschnitten.Der Prozess
init
startet den Microdroid-Manager, der auf das Instanz-Image zugreift. Der Microdroid-Manager-Dienst entschlüsselt das Image mit dem Schlüssel, der aus der vorherigen Phase übergeben wurde, und liest die öffentlichen Schlüssel und Rollback-Zähler der Client-APK und APEXe, denen diese pVM vertraut. Diese Informationen werden später vonzipfuse
undapexd
verwendet, um das Client-APK bzw. die angeforderten APEX-Dateien bereitzustellen.Der Microdroid-Managerdienst wird am
apexd
gestartet.apexd
stellt die APEXes in den Verzeichnissen/apex/<name>
bereit. Der einzige Unterschied zwischen der Bereitstellung von APEX-Dateien unter Android und Microdroid besteht darin, dass die APEX-Dateien unter Microdroid von virtuellen Blockgeräten (/dev/vdc1
, …) und nicht von regulären Dateien (/system/apex/*.apex
) stammen.zipfuse
ist das FUSE-Dateisystem von Microdroid.zipfuse
stellt das Client-APK bereit, das im Wesentlichen eine ZIP-Datei ist. Die APK-Datei wird von der pVM mit dm-verity als virtuelles Blockgerät übergeben, genau wie bei APEX. Die APK enthält eine Konfigurationsdatei mit einer Liste der APEXes, die der App-Entwickler für diese PVM-Instanz angefordert hat. Die Liste wird vonapexd
verwendet, wenn APEX-Einträge aktiviert werden.Der Bootvorgang kehrt zum Microdroid-Managerdienst zurück. Der Managerdienst kommuniziert dann über Binder RPC mit der
VirtualizationService
von Android, um wichtige Ereignisse wie Abstürze oder das Herunterfahren zu melden und Anfragen wie das Beenden der pVM anzunehmen. Der Managerdienst liest den Speicherort der Haupt-Binärdatei aus der Konfigurationsdatei des APKs und führt sie aus.
Dateiaustausch (AuthFS)
Android-Komponenten verwenden häufig Dateien für Eingabe, Ausgabe und Status und geben diese als Dateideskriptoren (ParcelFileDescriptor
typische AIDL-Dateien) weiter, deren Zugriff vom Android-Kernel gesteuert wird. AuthFS bietet ähnliche Funktionen für den Austausch von Dateien zwischen sich gegenseitig nicht vertrauenden Endpunkten über pVM-Grenzen hinweg.
AuthFS ist im Grunde ein Remote-Dateisystem mit transparenten Integritätsprüfungen für einzelne Zugriffsvorgänge, ähnlich wie fs-verity
. Durch die Prüfungen kann das Frontend, z. B. ein Programm zum Lesen von Dateien, das in einer pVM ausgeführt wird, erkennen, ob das nicht vertrauenswürdige Backend, in der Regel Android, den Dateiinhalt manipuliert hat.
Zum Austausch von Dateien wird das Backend (fd\_server
) mit einer pro Datei konfiguriert, die angibt, ob es für die Eingabe (schreibgeschützt) oder die Ausgabe (Lesen/Schreiben) bestimmt ist. Für die Eingabe erzwingt das Frontend, dass der Inhalt mit einem bekannten Hash über einem Merkle-Baum für die On-Access-Bestätigung übereinstimmt. Für die Ausgabe verwaltet AuthFS intern einen Hash-Baum der Inhalte, wie sie bei Schreibvorgängen beobachtet wurden, und kann die Integrität erzwingen, wenn die Daten wieder gelesen 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 Siegelschlüssel zur Sicherung persistenter Daten und einem Attestationsschlüssel zur Erstellung von Signaturen bereitgestellt, die nachweislich von der pVM stammen.
Binder RPC
Die meisten Android-Schnittstellen werden in AIDL ausgedrückt, das auf dem Linux-Kernel-Treiber „Binder“ basiert. Zur Unterstützung von Schnittstellen zwischen pVMs wurde das Binder-Protokoll neu geschrieben, um über Sockets zu funktionieren, im Fall von pVMs vsock. Durch die Ausführung über Sockets können die vorhandenen AIDL-Schnittstellen von Android in dieser neuen Umgebung verwendet werden.
Zur Einrichtung der Verbindung erstellt ein Endpunkt, z. B. die pVM-Nutzlast, ein RpcServer
-Objekt, registriert ein Stammobjekt und beginnt, auf neue Verbindungen zu warten. Clients können über ein RpcSession
-Objekt eine Verbindung zu diesem Server herstellen, das Binder
-Objekt abrufen und genau so verwenden, wie ein Binder
-Objekt mit dem Kernel-Binder-Treiber verwendet wird.