Microdroid è un mini sistema operativo Android che viene eseguito in una pVM. Non devi utilizzare Microdroid, puoi avviare una VM con qualsiasi sistema operativo. Tuttavia, i casi d'uso principali per le pVM non sono l'esecuzione di un sistema operativo autonomo, ma piuttosto l'offerta di un ambiente di esecuzione isolato per l'esecuzione di una parte di un'app con garanzie di riservatezza e integrità più elevate rispetto a quelle che Android può fornire.
Con i sistemi operativi tradizionali, fornire una forte riservatezza e integrità richiede una notevole quantità di lavoro (spesso duplicato) perché i sistemi operativi tradizionali non si adattano all'architettura Android generale. Ad esempio, con l'architettura Android standard, gli sviluppatori devono implementare un mezzo per caricare ed eseguire in modo sicuro una parte della loro app nella pVM e il payload viene creato in base a glibc. L'app per Android utilizza Bionic, la comunicazione richiede un protocollo personalizzato su vsock e il debug tramite ADB è difficile.
Microdroid colma queste lacune fornendo un'immagine del sistema operativo pronta all'uso progettata per richiedere il minimo sforzo da parte degli sviluppatori per trasferire una parte della loro app in una pVM. Il codice nativo viene creato in base a Bionic, la comunicazione avviene tramite Binder e consente di importare APEX dall'host Android ed espone un sottoinsieme dell'API Android, ad esempio keystore per operazioni di crittografia con chiavi supportate dall'hardware. In generale, gli sviluppatori dovrebbero trovare Microdroid un ambiente familiare con gli strumenti a cui si sono abituati nel sistema operativo Android completo.
Funzionalità
Microdroid è una versione ridotta di Android con alcuni componenti aggiuntivi specifici per le pVM. Microdroid supporta:
- Un sottoinsieme di API NDK (vengono fornite tutte le API per l'implementazione di libc e Bionic di Android)
- Funzionalità di debug, come adb, logcat, tombstone e gdb
- Avvio verificato e SELinux
- Caricamento ed esecuzione di un file binario, insieme a librerie condivise, incorporate in un APK
- RPC Binder su vsock e scambio di file con controlli di integrità impliciti
- Caricamento di APEX
Microdroid non supporta:
API Java Android nei pacchetti
android.\*java.\*SystemServer e Zygote
Grafica/interfaccia utente
HAL
Architettura Microdroid
Microdroid è simile a Cuttlefish in quanto entrambi hanno un'architettura che è simile ad Android standard. Microdroid è costituito dalle seguenti immagini di partizione raggruppate in un'immagine disco composita:
bootloader- Verifica e avvia il kernel.boot.img- Contiene il kernel e il ramdisk init.vendor_boot.img- Contiene moduli kernel specifici della VM, come virtio.super.img- È costituito da partizioni logiche di sistema e fornitore.vbmeta.img- Contiene i metadati di avvio verificato.
Le immagini di partizione vengono fornite nell'APEX di virtualizzazione e vengono pacchettizzate in un'immagine disco composita da VirtualizationService. Oltre all'immagine disco composita del sistema operativo principale, VirtualizationService è responsabile della creazione di queste altre partizioni:
payload- Un insieme di partizioni supportate da APEX e APK di Androidinstance- Una partizione criptata per la persistenza dei dati di avvio verificato per istanza , come il salt per istanza, le chiavi pubbliche APEX attendibili e i contatori di rollback
Sequenza di avvio
La sequenza di avvio di Microdroid si verifica dopo l'avvio del dispositivo. L'avvio del dispositivo è descritto nella sezione Firmware pVM del documento sull'architettura. La Figura 1 mostra i passaggi che si verificano durante la sequenza di avvio di Microdroid:
Ecco una spiegazione dei passaggi:
Il bootloader viene caricato in memoria da crosvm e pvmfw inizia l'esecuzione. Prima di passare al bootloader, pvmfw esegue due attività:
- Verifica il bootloader per controllare se proviene da una fonte attendibile (Google o un OEM).
- Garantisce che lo stesso bootloader venga utilizzato in modo coerente in più avvii della stessa pVM tramite l'utilizzo dell'immagine dell'istanza. Nello specifico, la pVM viene avviata inizialmente con un'immagine dell'istanza vuota. pvmfw archivia l'identità del bootloader nell'immagine dell'istanza e la cripta. Pertanto, la volta successiva che la pVM viene avviata con la stessa immagine dell'istanza, pvmfw decripta l'identità salvata dall'immagine dell'istanza e verifica che sia la stessa salvata in precedenza. Se le identità sono diverse, pvmfw si rifiuta di avviarsi.
Il bootloader avvia quindi Microdroid.
Il bootloader accede al disco dell'istanza. Analogamente a pvmfw, il bootloader ha un'unità disco dell'istanza con informazioni sulle immagini di partizione utilizzate in questa istanza durante gli avvii precedenti, inclusa la chiave pubblica.
Il bootloader verifica vbmeta e le partizioni concatenate, come
bootesuper, e, se l'operazione va a buon fine, deriva i segreti della pVM di fase successiva. Microdroid passa quindi il controllo al kernel.Poiché la partizione super è già stata verificata dal bootloader (passaggio 3), il kernel monta incondizionatamente la partizione super. Come per Android completo, la partizione super è costituita da più partizioni logiche montate su dm-verity. Il controllo viene quindi passato al processo
init, che avvia vari servizi nativi. Lo scriptinit.rcè simile a quello di Android completo, ma è adattato alle esigenze di Microdroid.Il processo
initavvia il gestore Microdroid, che accede all'immagine dell'istanza. Il servizio di gestione di Microdroid decripta l'immagine utilizzando la chiave passata dalla fase precedente e legge le chiavi pubbliche e i contatori di rollback dell'APK e degli APEX del client di cui questa pVM si fida. Queste informazioni vengono utilizzate in un secondo momento dazipfuseeapexdquando montano rispettivamente l'APK del client e gli APEX richiesti.Il servizio di gestione di Microdroid avvia
apexd.apexdmonta gli APEX nelle directory/apex/<name>. L'unica differenza tra il modo in cui Android e Microdroid montano gli APEX è che in Microdroid i file APEX provengono da dispositivi a blocchi virtuali (/dev/vdc1, …), non da file normali (/system/apex/*.apex).zipfuseè il file system FUSE di Microdroid.zipfusemonta l'APK del client, che è essenzialmente un file ZIP come file system. Sotto, il file APK viene passato come dispositivo a blocchi virtuali dalla pVM con dm-verity, come APEX. L'APK contiene un file di configurazione con un elenco di APEX che lo sviluppatore di app ha richiesto per questa istanza pVM. L'elenco viene utilizzato daapexddurante l'attivazione degli APEX.Il flusso di avvio torna al servizio di gestione di Microdroid. Il servizio di gestione comunica quindi con
VirtualizationServicedi Android utilizzando Binder RPC in modo da poter segnalare eventi importanti come arresti anomali o arresti e accettare richieste come la terminazione della pVM. Il servizio di gestione legge la posizione del file binario principale dal file di configurazione dell'APK e lo esegue.
Scambio di file (AuthFS)
È normale che i componenti Android utilizzino i file per input, output e stato e che li passino come descrittori di file (tipo ParcelFileDescriptor in AIDL) con accesso controllato dal kernel Android. AuthFS facilita funzionalità simili per lo scambio di file tra endpoint che non si fidano reciprocamente oltre i limiti della pVM.
Fondamentalmente, AuthFS è un file system remoto con controlli di integrità trasparenti sulle singole operazioni di accesso, simili a fs-verity. I controlli consentono al frontend, ad esempio un programma di lettura di file in esecuzione in una pVM, di rilevare se il backend non attendibile, in genere Android, ha manomesso i contenuti dei file.
Per scambiare i file, il backend (fd\_server) viene avviato con una configurazione per file che specifica se è destinato all'input (sola lettura) o all'output (lettura/scrittura). Per l'input, il frontend impone che i contenuti corrispondano a un hash noto, oltre a un albero di Merkle per la verifica dell'accesso. Per l'output, AuthFS mantiene internamente un albero hash dei contenuti osservati dalle operazioni di scrittura e può applicare l'integrità quando i dati vengono letti di nuovo.
Il trasporto sottostante è attualmente basato su Binder RPC, ma potrebbe cambiare in futuro per ottimizzare le prestazioni.
Gestione delle chiavi
Le pVM sono dotate di una chiave di sigillatura stabile adatta a proteggere i dati persistenti e di una chiave di attestazione adatta a produrre firme che vengono prodotte in modo verificabile dalla pVM.
RPC Binder
La maggior parte delle interfacce di Android è espressa in AIDL, che si basa sul driver del kernel Linux Binder. Per supportare le interfacce tra le pVM, il protocollo Binder è stato riscritto per funzionare su socket, vsock nel caso delle pVM. L'utilizzo di socket consente di utilizzare le interfacce AIDL esistenti di Android in questo nuovo ambiente.
Per configurare la connessione, un endpoint, ad esempio il payload della pVM, crea un oggetto RpcServer, registra un oggetto root e inizia ad ascoltare le nuove connessioni. I client possono connettersi a questo server utilizzando un oggetto RpcSession, ottenere l'oggetto Binder e utilizzarlo esattamente come un oggetto Binder viene utilizzato con il driver Binder del kernel.