Microdroide

Microdroid è un mini sistema operativo Android che viene eseguito in una pVM. Non è necessario usare Microdroid, puoi avviare una VM con qualsiasi sistema operativo. Tuttavia, i casi d'uso principali per le pVM non eseguono un sistema operativo autonomo, ma offrono 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 può fornire Android.

Con i sistemi operativi tradizionali, garantire riservatezza e integrità solidi richiedono una discreta quantità di lavoro (spesso duplicati), perché i sistemi operativi tradizionali non sono compatibili con l'architettura Android generale. Ad esempio, con l'architettura Android standard, gli sviluppatori devono implementare un mezzo per caricare ed eseguire in sicurezza parte della propria 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 è complicato.

Microdroid colma queste lacune fornendo un'immagine del sistema operativo pronta all'uso progettata per richiedere agli sviluppatori il minimo sforzo per scaricare una parte della loro app in una VM. Il codice nativo è creato in base a Bionic, la comunicazione avviene tramite Binder, consente l'importazione di APEX dall'host Android ed espone un sottoinsieme dell'API Android, ad esempio il keystore per le operazioni di crittografia con chiavi basate su hardware. Nel complesso, gli sviluppatori dovrebbero trovare Microdroid un ambiente familiare con gli strumenti a cui sono abituati nel sistema operativo Android completo.

Funzionalità

Microdroid è una versione semplificata di Android con alcuni componenti aggiuntivi specifici delle pVM. Microdroid supporta:

  • Un sottoinsieme di API NDK (sono 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 alle librerie condivise, incorporato in un APK
  • RPC Binder su vsock e scambio di file con controlli di integrità impliciti
  • Caricamento di APEX

Microdroid non supporta:

  • API Java per Android nei pacchetti android.\*

  • SystemServer e Zygote

  • Grafica/interfaccia utente

  • HAL

Architettura di Microdroid

Microdroid è simile a Seppia in quanto entrambi hanno un'architettura simile ad Android standard. Il microdroide è costituito dalle seguenti immagini di partizione raggruppate in un'immagine disco composito:

  • bootloader: verifica e avvia il kernel.
  • boot.img: contiene il kernel e il ramdisk init.
  • vendor_boot.img: contiene moduli del kernel specifici per la VM, come virtio.
  • super.img: è costituito da partizioni logiche di sistema e del fornitore.
  • vbmeta.img - Contiene metadati di avvio verificati.

Le immagini delle partizioni vengono fornite nell'APEX di virtualizzazione e sono pacchettizzate in un'immagine disco composita da VirtualizationService. Oltre all'immagine del disco composito del sistema operativo principale, VirtualizationService è responsabile della creazione di queste altre partizioni:

  • payload: un insieme di partizioni supportate dagli APK e dagli APEX di Android
  • instance - Una partizione criptata per dati di avvio verificati per istanza, come sale per istanza, chiavi pubbliche APEX attendibili e contatori di rollback

Sequenza di avvio

La sequenza di avvio di Microdroid avviene dopo l'avvio del dispositivo. Il boot del dispositivo è discusso nella sezione Firmware pVM del documento Architettura. La figura 1 mostra i passaggi che si verificano durante la sequenza di avvio di Microdroid:

Flusso di boot sicuro di un'istanza di microdroidi

Figura 1. Flusso di avvio protetto dell'istanza microdroid

Ecco una spiegazione dei passaggi:

  1. Il bootloader viene caricato in memoria da crosvm e pvmfw inizia a eseguire. Prima di passare al bootloader, pvmfw esegue due attività:

    • Verifica il bootloader per verificare 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 inizialmente avviata 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 VM 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 rifiuta di avviarsi.

    Il bootloader avvia quindi Microdroid.

  2. Il bootloader accede al disco dell'istanza. Come pvmfw, il bootloader ha un'unità disco dell'istanza con informazioni sulle immagini delle partizioni utilizzate in questa istanza durante gli avvii precedenti, inclusa la chiave pubblica.

  3. Il bootloader verifica vbmeta e le partizioni concatenate, come boot e super e, in caso di esito positivo, ricava i secret pVM della fase successiva. Dopodiché Microdroid passa il controllo al kernel.

  4. Poiché la partizione super è già stata verificata dal bootloader (passaggio 3), il kernel la monta incondizionatamente. Come per Android completo, la partizione super è composta da più partizioni logiche montate su dm-verity. Il controllo viene poi passato al processo init, che avvia vari servizi nativi. Lo script init.rc è simile a quello di Android completo, ma si adatta alle esigenze dei Microdroide.

  5. Il processo init avvia 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 client e degli APEX attendibili di questa pVM. Queste informazioni vengono usate in un secondo momento da zipfuse e apexd quando installano l'APK client e richiedono gli APEX, rispettivamente.

  6. Il servizio di gestione di Microdroid si avvia il giorno apexd.

  7. apexd monta 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 di blocco virtuali (/dev/vdc1, …), non da file normali (/system/apex/*.apex).

  8. zipfuse è il file system FUSE di Microdroid. zipfuse monta l'APK client, che è essenzialmente un file ZIP come file system. Sotto, il file APK viene passato come dispositivo di blocco virtuale dalla pVM con dm-verity, come per APEX. L'APK contiene un file di configurazione con un elenco di APEX che lo sviluppatore dell'app ha richiesto per questa istanza pVM. L'elenco viene utilizzato da apexd per attivare gli APEX.

  9. Il flusso di avvio torna al servizio di gestione Microdroid. Il servizio di gestione comunica quindi con VirtualizationService di Android tramite Binder RPC in modo da poter segnalare eventi importanti come arresti anomali o arresti anomali e accettare richieste come l'arresto della pVM. Il servizio di gestione legge la posizione del file binario principale dal file di configurazione dell'APK ed esegue il file.

Scambio di file (AuthFS)

È normale che i componenti Android utilizzino file per input, output e stato e li trasmettano come descrittori file (ParcelFileDescriptor type in AIDL) con accesso controllato dal kernel di Android. AuthFS facilita funzionalità simili per lo scambio di file tra endpoint che non si fidano reciprocamente al di fuori dei confini delle pVM.

Fondamentalmente, AuthFS è un file system remoto con controlli di integrità trasparenti sulle singole operazioni di accesso, come in fs-verity. I controlli consentono al frontend, ad esempio un programma di lettura dei 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 conosciuto, sopra un albero Merkle per la verifica all'accesso. Per l'output, AuthFS mantiene internamente una struttura di hash dei contenuti osservata dalle operazioni di scrittura e può imporre l'integrità alla lettura dei dati.

Il trasporto sottostante è attualmente basato su Binder RPC, ma potrebbe cambiare in futuro per ottimizzare le prestazioni.

Gestione delle chiavi

Le pVM sono fornite con una chiave di sigillatura stabile adatta per proteggere i dati permanenti e una chiave di attestazione adatta per produrre firme verificabili prodotte dalla pVM.

Binder RPC

La maggior parte delle interfacce di Android è espressa in AIDL, che si basa sul driver kernel Binder Linux. Per supportare le interfacce tra le pVM, il protocollo Binder è stato riscritto per funzionare su socket, vsock nel caso delle pVM. Il funzionamento tramite 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 VM, crea un oggetto RpcServer, registra un oggetto principale e inizia a monitorare le nuove connessioni. I client possono connettersi a questo server utilizzando un oggetto RpcSession, recuperare l'oggetto Binder e utilizzarlo esattamente come un oggetto Binder viene utilizzato con il driver Binder del kernel.